velesdb_core/velesql/ast/
with_clause.rs1use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
12#[non_exhaustive]
13pub enum QuantizationMode {
14 F32,
16 Int8,
18 Dual,
20 #[default]
22 Auto,
23}
24
25impl QuantizationMode {
26 #[must_use]
28 pub fn parse(s: &str) -> Option<Self> {
29 match s.to_lowercase().as_str() {
30 "f32" | "full" | "exact" => Some(Self::F32),
31 "int8" | "sq8" | "quantized" => Some(Self::Int8),
32 "dual" | "hybrid" => Some(Self::Dual),
33 "auto" | "default" => Some(Self::Auto),
34 _ => None,
35 }
36 }
37
38 #[must_use]
40 pub const fn as_str(&self) -> &'static str {
41 match self {
42 Self::F32 => "f32",
43 Self::Int8 => "int8",
44 Self::Dual => "dual",
45 Self::Auto => "auto",
46 }
47 }
48}
49
50#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
52pub struct WithClause {
53 pub options: Vec<WithOption>,
55}
56
57impl WithClause {
58 #[must_use]
60 pub fn new() -> Self {
61 Self::default()
62 }
63
64 #[must_use]
66 pub fn with_option(mut self, key: impl Into<String>, value: WithValue) -> Self {
67 self.options.push(WithOption {
68 key: key.into(),
69 value,
70 });
71 self
72 }
73
74 #[must_use]
76 pub fn get(&self, key: &str) -> Option<&WithValue> {
77 self.options
78 .iter()
79 .find(|opt| opt.key.eq_ignore_ascii_case(key))
80 .map(|opt| &opt.value)
81 }
82
83 #[must_use]
88 pub fn get_mode(&self) -> Option<&str> {
89 self.get("mode")
90 .or_else(|| self.get("quality"))
91 .and_then(|v| v.as_str())
92 }
93
94 #[must_use]
96 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
97 pub fn get_ef_search(&self) -> Option<usize> {
98 self.get("ef_search")
99 .and_then(WithValue::as_integer)
100 .map(|v| v as usize)
101 }
102
103 #[must_use]
105 #[allow(clippy::cast_sign_loss)]
106 pub fn get_timeout_ms(&self) -> Option<u64> {
107 self.get("timeout_ms")
108 .and_then(WithValue::as_integer)
109 .map(|v| v as u64)
110 }
111
112 #[must_use]
114 pub fn get_rerank(&self) -> Option<bool> {
115 self.get("rerank").and_then(WithValue::as_bool)
116 }
117
118 #[must_use]
122 pub fn get_quantization(&self) -> Option<QuantizationMode> {
123 self.get("quantization")
124 .and_then(WithValue::as_str)
125 .and_then(QuantizationMode::parse)
126 }
127
128 #[must_use]
132 #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
133 pub fn get_oversampling(&self) -> Option<usize> {
134 self.get("oversampling")
135 .and_then(WithValue::as_integer)
136 .map(|v| v.max(1) as usize)
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
142pub struct WithOption {
143 pub key: String,
145 pub value: WithValue,
147}
148
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
151#[non_exhaustive]
152pub enum WithValue {
153 String(String),
155 Integer(i64),
157 Float(f64),
159 Boolean(bool),
161 Identifier(String),
163}
164
165impl WithValue {
166 #[must_use]
168 pub fn as_str(&self) -> Option<&str> {
169 match self {
170 Self::String(s) | Self::Identifier(s) => Some(s),
171 _ => None,
172 }
173 }
174
175 #[must_use]
177 pub fn as_integer(&self) -> Option<i64> {
178 match self {
179 Self::Integer(i) => Some(*i),
180 _ => None,
181 }
182 }
183
184 #[must_use]
186 pub fn as_float(&self) -> Option<f64> {
187 match self {
188 Self::Float(f) => Some(*f),
189 #[allow(clippy::cast_precision_loss)]
190 Self::Integer(i) => Some(*i as f64),
191 _ => None,
192 }
193 }
194
195 #[must_use]
197 pub fn as_bool(&self) -> Option<bool> {
198 match self {
199 Self::Boolean(b) => Some(*b),
200 _ => None,
201 }
202 }
203}