1use std::collections::HashMap;
25
26pub type Payload = HashMap<String, serde_json::Value>;
32
33pub type PayloadValue = serde_json::Value;
35
36#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
38#[serde(untagged)]
39pub enum PointId {
40 Num(u64),
41 Uuid(String),
42}
43
44impl From<u64> for PointId {
45 fn from(v: u64) -> Self {
46 Self::Num(v)
47 }
48}
49
50impl From<String> for PointId {
51 fn from(v: String) -> Self {
52 if let Ok(n) = v.parse::<u64>() {
55 Self::Num(n)
56 } else {
57 Self::Uuid(v)
58 }
59 }
60}
61
62impl From<&str> for PointId {
63 fn from(v: &str) -> Self {
64 Self::from(v.to_string())
65 }
66}
67
68impl std::fmt::Display for PointId {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 match self {
71 Self::Num(n) => write!(f, "{n}"),
72 Self::Uuid(s) => write!(f, "{s}"),
73 }
74 }
75}
76
77#[derive(
79 Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize, utoipa::ToSchema,
80)]
81pub enum PayloadSchemaType {
82 Keyword,
83 Integer,
84 Float,
85 Text,
86 Bool,
87 Geo,
88 Datetime,
89}
90
91impl PayloadSchemaType {
92 pub fn as_str(&self) -> &'static str {
93 match self {
94 Self::Keyword => "keyword",
95 Self::Integer => "integer",
96 Self::Float => "float",
97 Self::Text => "text",
98 Self::Bool => "bool",
99 Self::Geo => "geo",
100 Self::Datetime => "datetime",
101 }
102 }
103}
104
105#[derive(Debug, Clone, Copy, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
116pub struct GeoPoint {
117 pub lat: f64,
118 pub lon: f64,
119}
120
121impl GeoPoint {
122 pub fn new(lat: f64, lon: f64) -> Self {
123 Self { lat, lon }
124 }
125}
126
127#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
129pub struct GeoRadius {
130 pub center: GeoPoint,
131 pub radius: f64,
133}
134
135impl GeoRadius {
136 pub fn new(center: GeoPoint, radius: f64) -> Self {
137 Self { center, radius }
138 }
139}
140
141#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
143pub struct GeoBoundingBox {
144 pub top_left: GeoPoint,
145 pub bottom_right: GeoPoint,
146}
147
148impl GeoBoundingBox {
149 pub fn new(top_left: GeoPoint, bottom_right: GeoPoint) -> Self {
150 Self {
151 top_left,
152 bottom_right,
153 }
154 }
155}
156
157#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
159pub struct ValuesCountCondition {
160 pub gt: Option<u64>,
161 pub gte: Option<u64>,
162 pub lt: Option<u64>,
163 pub lte: Option<u64>,
164}
165
166impl ValuesCountCondition {
167 pub fn new() -> Self {
168 Self {
169 gt: None,
170 gte: None,
171 lt: None,
172 lte: None,
173 }
174 }
175
176 pub fn gt(mut self, value: u64) -> Self {
177 self.gt = Some(value);
178 self
179 }
180
181 pub fn gte(mut self, value: u64) -> Self {
182 self.gte = Some(value);
183 self
184 }
185
186 pub fn lt(mut self, value: u64) -> Self {
187 self.lt = Some(value);
188 self
189 }
190
191 pub fn lte(mut self, value: u64) -> Self {
192 self.lte = Some(value);
193 self
194 }
195}
196
197impl Default for ValuesCountCondition {
198 fn default() -> Self {
199 Self::new()
200 }
201}
202
203#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
205#[schema(no_recursion)]
206pub struct VectorFilter {
207 pub must: Option<Vec<FilterCondition>>,
208 pub must_not: Option<Vec<FilterCondition>>,
209 pub should: Option<Vec<FilterCondition>>,
210 pub min_should: Option<MinShouldCondition>,
211}
212
213impl VectorFilter {
214 pub fn new() -> Self {
215 Self::default()
216 }
217
218 pub fn must(mut self, condition: FilterCondition) -> Self {
219 self.must.get_or_insert_with(Vec::new).push(condition);
220 self
221 }
222
223 pub fn must_not(mut self, condition: FilterCondition) -> Self {
224 self.must_not.get_or_insert_with(Vec::new).push(condition);
225 self
226 }
227
228 pub fn should(mut self, condition: FilterCondition) -> Self {
229 self.should.get_or_insert_with(Vec::new).push(condition);
230 self
231 }
232}
233
234#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
236#[schema(no_recursion)]
237pub struct MinShouldCondition {
238 pub conditions: Vec<FilterCondition>,
239 pub min_count: usize,
240}
241
242#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
244#[schema(no_recursion)]
245pub struct FilterCondition {
246 pub field: String,
247 pub condition: ConditionType,
248}
249
250impl FilterCondition {
251 pub fn new(field: impl Into<String>, condition: ConditionType) -> Self {
252 Self {
253 field: field.into(),
254 condition,
255 }
256 }
257
258 pub fn match_value(field: impl Into<String>, value: impl Into<String>) -> Self {
259 Self::new(
260 field,
261 ConditionType::Match {
262 value: value.into(),
263 },
264 )
265 }
266
267 pub fn match_any(field: impl Into<String>, values: Vec<PayloadValue>) -> Self {
268 Self::new(field, ConditionType::MatchAny { values })
269 }
270
271 pub fn range(field: impl Into<String>, range: RangeCondition) -> Self {
272 Self::new(field, ConditionType::Range(range))
273 }
274
275 pub fn is_empty(field: impl Into<String>) -> Self {
276 Self::new(field, ConditionType::IsEmpty)
277 }
278
279 pub fn is_null(field: impl Into<String>) -> Self {
280 Self::new(field, ConditionType::IsNull)
281 }
282
283 pub fn has_id(ids: Vec<String>) -> Self {
284 Self::new("_id", ConditionType::HasId { ids })
285 }
286
287 pub fn geo_radius(field: impl Into<String>, radius: GeoRadius) -> Self {
288 Self::new(field, ConditionType::GeoRadius(radius))
289 }
290
291 pub fn geo_bounding_box(field: impl Into<String>, bbox: GeoBoundingBox) -> Self {
292 Self::new(field, ConditionType::GeoBoundingBox(bbox))
293 }
294
295 pub fn values_count(field: impl Into<String>, count: ValuesCountCondition) -> Self {
296 Self::new(field, ConditionType::ValuesCount(count))
297 }
298
299 pub fn contains(field: impl Into<String>, value: impl Into<String>) -> Self {
300 Self::new(
301 field,
302 ConditionType::Contains {
303 value: value.into(),
304 },
305 )
306 }
307}
308
309#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
311#[schema(no_recursion)]
312pub enum ConditionType {
313 Match {
315 value: String,
316 },
317 MatchAny {
319 #[schema(value_type = Vec<serde_json::Value>)]
320 values: Vec<PayloadValue>,
321 },
322 Range(RangeCondition),
324 IsEmpty,
325 IsNull,
326 HasId {
327 ids: Vec<String>,
328 },
329 Nested {
330 filter: Box<VectorFilter>,
331 },
332 GeoRadius(GeoRadius),
333 GeoBoundingBox(GeoBoundingBox),
334 ValuesCount(ValuesCountCondition),
335 Contains {
336 value: String,
337 },
338}
339
340#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
342pub struct RangeCondition {
343 pub gt: Option<f64>,
344 pub gte: Option<f64>,
345 pub lt: Option<f64>,
346 pub lte: Option<f64>,
347}
348
349impl RangeCondition {
350 pub fn new() -> Self {
351 Self {
352 gt: None,
353 gte: None,
354 lt: None,
355 lte: None,
356 }
357 }
358
359 pub fn gt(mut self, value: f64) -> Self {
360 self.gt = Some(value);
361 self
362 }
363
364 pub fn gte(mut self, value: f64) -> Self {
365 self.gte = Some(value);
366 self
367 }
368
369 pub fn lt(mut self, value: f64) -> Self {
370 self.lt = Some(value);
371 self
372 }
373
374 pub fn lte(mut self, value: f64) -> Self {
375 self.lte = Some(value);
376 self
377 }
378}
379
380impl Default for RangeCondition {
381 fn default() -> Self {
382 Self::new()
383 }
384}
385
386#[derive(Debug, Clone, Default, serde::Serialize, serde::Deserialize, utoipa::ToSchema)]
388pub struct PayloadSelector {
389 pub include: Option<Vec<String>>,
390 pub exclude: Option<Vec<String>>,
391}
392
393impl PayloadSelector {
394 pub fn apply(&self, payload: &Payload) -> Payload {
397 let mut out = if let Some(include) = &self.include {
398 include
399 .iter()
400 .filter_map(|k| payload.get(k).map(|v| (k.clone(), v.clone())))
401 .collect::<Payload>()
402 } else {
403 payload.clone()
404 };
405 if let Some(exclude) = &self.exclude {
406 for k in exclude {
407 out.remove(k);
408 }
409 }
410 out
411 }
412
413 pub fn include(fields: Vec<String>) -> Self {
414 Self {
415 include: Some(fields),
416 exclude: None,
417 }
418 }
419
420 pub fn exclude(fields: Vec<String>) -> Self {
421 Self {
422 include: None,
423 exclude: Some(fields),
424 }
425 }
426
427 pub fn all() -> Self {
428 Self {
429 include: None,
430 exclude: None,
431 }
432 }
433}