1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
4#[serde(rename_all = "lowercase")]
5pub enum FilterOperator {
6 Eq,
7 Ne,
8 Gt,
9 Lt,
10 Gte,
11 Lte,
12 Like,
13 ILike,
14 In,
15 NotIn,
16 IsNull,
17 IsNotNull,
18 Between,
19 Contains,
20}
21
22#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
23#[serde(untagged)]
24pub enum FilterValue {
25 String(String),
26 Int(i64),
27 Float(f64),
28 Bool(bool),
29 Array(Vec<FilterValue>),
30 Null,
31}
32
33impl FilterValue {
34 pub fn to_sql_string(&self) -> String {
35 match self {
36 FilterValue::String(s) => format!("'{}'", s.replace('\'', "''")),
37 FilterValue::Int(i) => i.to_string(),
38 FilterValue::Float(f) => f.to_string(),
39 FilterValue::Bool(b) => if *b { "TRUE" } else { "FALSE" }.to_string(),
40 FilterValue::Array(arr) => {
41 let items: Vec<String> = arr.iter().map(|v| v.to_sql_string()).collect();
42 format!("({})", items.join(", "))
43 }
44 FilterValue::Null => "NULL".to_string(),
45 }
46 }
47}
48
49#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
50pub struct Filter {
51 pub field: String,
52 pub operator: FilterOperator,
53 pub value: FilterValue,
54}
55
56impl Filter {
57 pub fn new(field: impl Into<String>, operator: FilterOperator, value: FilterValue) -> Self {
58 Self {
59 field: field.into(),
60 operator,
61 value,
62 }
63 }
64
65 pub fn to_sql_where(&self) -> String {
66 match &self.operator {
67 FilterOperator::Eq => format!("{} = {}", self.field, self.value.to_sql_string()),
68 FilterOperator::Ne => format!("{} != {}", self.field, self.value.to_sql_string()),
69 FilterOperator::Gt => format!("{} > {}", self.field, self.value.to_sql_string()),
70 FilterOperator::Lt => format!("{} < {}", self.field, self.value.to_sql_string()),
71 FilterOperator::Gte => format!("{} >= {}", self.field, self.value.to_sql_string()),
72 FilterOperator::Lte => format!("{} <= {}", self.field, self.value.to_sql_string()),
73 FilterOperator::Like => format!("{} LIKE {}", self.field, self.value.to_sql_string()),
74 FilterOperator::ILike => format!("{} ILIKE {}", self.field, self.value.to_sql_string()),
75 FilterOperator::In => format!("{} IN {}", self.field, self.value.to_sql_string()),
76 FilterOperator::NotIn => {
77 format!("{} NOT IN {}", self.field, self.value.to_sql_string())
78 }
79 FilterOperator::IsNull => format!("{} IS NULL", self.field),
80 FilterOperator::IsNotNull => format!("{} IS NOT NULL", self.field),
81 FilterOperator::Between => {
82 if let FilterValue::Array(arr) = &self.value {
83 if arr.len() == 2 {
84 return format!(
85 "{} BETWEEN {} AND {}",
86 self.field,
87 arr[0].to_sql_string(),
88 arr[1].to_sql_string()
89 );
90 }
91 }
92 format!("{} = {}", self.field, self.value.to_sql_string())
93 }
94 FilterOperator::Contains => {
95 format!("{} @> {}", self.field, self.value.to_sql_string())
96 }
97 }
98 }
99
100 pub fn to_surrealql_where(&self) -> String {
101 match &self.operator {
102 FilterOperator::Eq => format!("{} = {}", self.field, self.value.to_sql_string()),
103 FilterOperator::Ne => format!("{} != {}", self.field, self.value.to_sql_string()),
104 FilterOperator::Gt => format!("{} > {}", self.field, self.value.to_sql_string()),
105 FilterOperator::Lt => format!("{} < {}", self.field, self.value.to_sql_string()),
106 FilterOperator::Gte => format!("{} >= {}", self.field, self.value.to_sql_string()),
107 FilterOperator::Lte => format!("{} <= {}", self.field, self.value.to_sql_string()),
108 FilterOperator::Like | FilterOperator::ILike => {
109 format!("{} ~ {}", self.field, self.value.to_sql_string())
110 }
111 FilterOperator::In => format!("{} INSIDE {}", self.field, self.value.to_sql_string()),
112 FilterOperator::NotIn => {
113 format!("{} NOT INSIDE {}", self.field, self.value.to_sql_string())
114 }
115 FilterOperator::IsNull => format!("{} IS NULL", self.field),
116 FilterOperator::IsNotNull => format!("{} IS NOT NULL", self.field),
117 FilterOperator::Between => {
118 if let FilterValue::Array(arr) = &self.value {
119 if arr.len() == 2 {
120 return format!(
121 "{} >= {} AND {} <= {}",
122 self.field,
123 arr[0].to_sql_string(),
124 self.field,
125 arr[1].to_sql_string()
126 );
127 }
128 }
129 format!("{} = {}", self.field, self.value.to_sql_string())
130 }
131 FilterOperator::Contains => {
132 format!("{} CONTAINS {}", self.field, self.value.to_sql_string())
133 }
134 }
135 }
136}