use std::collections::HashMap;
use crate::{Expr, OrderBy, Value};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum VectorMetric {
L2,
InnerProduct,
Cosine,
}
impl VectorMetric {
pub fn as_str(self) -> &'static str {
match self {
Self::L2 => "l2",
Self::InnerProduct => "innerProduct",
Self::Cosine => "cosine",
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct VectorNearest {
pub field: String,
pub query: Vec<f32>,
pub metric: VectorMetric,
}
#[derive(Debug, Default, Clone)]
pub struct IncludeRelation {
pub where_: Option<Expr>,
pub order_by: Vec<OrderBy>,
pub take: Option<i32>,
pub skip: Option<u32>,
pub cursor: Option<HashMap<String, Value>>,
pub distinct: Vec<String>,
pub include: HashMap<String, IncludeRelation>,
}
impl IncludeRelation {
pub fn plain() -> Self {
Self::default()
}
pub fn with_filter(filter: Expr) -> Self {
Self {
where_: Some(filter),
..Self::default()
}
}
pub fn with_order_by(mut self, order: OrderBy) -> Self {
self.order_by.push(order);
self
}
pub fn with_take(mut self, take: i32) -> Self {
self.take = Some(take);
self
}
pub fn with_skip(mut self, skip: u32) -> Self {
self.skip = Some(skip);
self
}
pub fn with_cursor(mut self, cursor: HashMap<String, Value>) -> Self {
self.cursor = Some(cursor);
self
}
pub fn with_distinct(mut self, distinct: Vec<String>) -> Self {
self.distinct = distinct;
self
}
pub fn with_include(mut self, relation: impl Into<String>, include: IncludeRelation) -> Self {
self.include.insert(relation.into(), include);
self
}
}
#[derive(Debug, Clone)]
pub struct FindUniqueArgs {
pub where_: Expr,
pub select: HashMap<String, bool>,
pub include: HashMap<String, IncludeRelation>,
}
impl FindUniqueArgs {
pub fn new(filter: Expr) -> Self {
FindUniqueArgs {
where_: filter,
select: HashMap::new(),
include: HashMap::new(),
}
}
pub fn with_include(mut self, relation: impl Into<String>, include: IncludeRelation) -> Self {
self.include.insert(relation.into(), include);
self
}
pub fn with_select(mut self, field: impl Into<String>) -> Self {
self.select.insert(field.into(), true);
self
}
}
#[derive(Debug, Default, Clone)]
pub struct FindManyArgs {
pub where_: Option<Expr>,
pub order_by: Vec<OrderBy>,
pub take: Option<i32>,
pub skip: Option<u32>,
pub include: HashMap<String, IncludeRelation>,
pub select: HashMap<String, bool>,
pub cursor: Option<HashMap<String, Value>>,
pub distinct: Vec<String>,
pub nearest: Option<VectorNearest>,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn include_relation_builder_methods_populate_all_fields() {
let cursor = HashMap::from([("id".to_string(), Value::I64(5))]);
let include =
IncludeRelation::with_filter(Expr::column("posts__published").eq(Expr::param(true)))
.with_order_by(OrderBy::desc("posts__created_at"))
.with_take(10)
.with_skip(2)
.with_cursor(cursor.clone())
.with_distinct(vec!["title".to_string()])
.with_include("comments", IncludeRelation::plain());
assert!(include.where_.is_some());
assert_eq!(include.order_by.len(), 1);
assert_eq!(include.take, Some(10));
assert_eq!(include.skip, Some(2));
assert_eq!(include.cursor, Some(cursor));
assert_eq!(include.distinct, vec!["title"]);
assert!(include.include.contains_key("comments"));
}
#[test]
fn find_unique_args_new_starts_without_projection_or_includes() {
let args = FindUniqueArgs::new(Expr::column("users__id").eq(Expr::param(1i64)));
assert!(args.select.is_empty());
assert!(args.include.is_empty());
}
#[test]
fn vector_metric_strings_match_protocol_shape() {
assert_eq!(VectorMetric::L2.as_str(), "l2");
assert_eq!(VectorMetric::InnerProduct.as_str(), "innerProduct");
assert_eq!(VectorMetric::Cosine.as_str(), "cosine");
}
}