shared/domain/ports/query/
convert.rs1use mongodb::bson::{Document, doc};
2
3use super::{
4 builder::QueryBuilder,
5 value::{DbValue, Op},
6};
7
8pub trait IntoDbFilter {
9 fn into_mongo_filter(self) -> Document;
10 fn into_mongo_update(self) -> Document;
11 fn into_postgres_filter(self, offset: usize) -> (String, Vec<DbValue>);
12 fn into_postgres_update(self) -> (String, Vec<DbValue>);
13 fn into_sqlite_filter(self) -> (String, Vec<DbValue>);
14 fn into_sqlite_update(self) -> (String, Vec<DbValue>);
15}
16
17impl IntoDbFilter for QueryBuilder {
18 fn into_mongo_filter(self) -> Document {
19 let mut doc = Document::new();
20
21 for op in self.filters {
23 let value = op.value.into_boson(op.field);
24 let field = if op.field == "id" { "_id" } else { op.field };
25
26 match op.op {
27 Op::Eq => {
28 doc.insert(field, value);
29 }
30 Op::Ne => {
31 doc.insert(field, doc! { "$ne": value });
32 }
33 Op::Gt => {
34 doc.insert(field, doc! { "$gt": value });
35 }
36 Op::Lt => {
37 doc.insert(field, doc! { "$lt": value });
38 }
39 Op::In => {
40 doc.insert(field, doc! { "$in": value });
41 }
42 Op::Null => {
43 doc.insert(field, doc! { "$in": [mongodb::bson::Bson::Null] });
44 }
45 _ => {}
46 }
47 }
48
49 doc
50 }
51
52 fn into_mongo_update(self) -> Document {
53 let mut doc = Document::new();
54
55 if !self.updates.is_empty() {
57 let mut set_doc = Document::new();
58 let mut inc_doc = Document::new();
59 let mut unset_doc = Document::new();
60
61 for op in self.updates {
62 let value = op.value.into_boson(op.field);
63
64 match op.op {
65 Op::Set => {
66 set_doc.insert(op.field, value);
67 }
68 Op::Inc => {
69 inc_doc.insert(op.field, value);
70 }
71 Op::Unset => {
72 unset_doc.insert(op.field, "");
73 }
74 _ => {}
75 }
76 }
77
78 if !set_doc.is_empty() {
79 doc.insert("$set", set_doc);
80 }
81 if !inc_doc.is_empty() {
82 doc.insert("$inc", inc_doc);
83 }
84 if !unset_doc.is_empty() {
85 doc.insert("$unset", unset_doc);
86 }
87 }
88
89 doc
90 }
91 fn into_postgres_filter(self, offset: usize) -> (String, Vec<DbValue>) {
92 let clause = self
93 .filters
94 .iter()
95 .enumerate()
96 .map(|(i, f)| match f.op {
97 Op::Eq => format!("\"{}\" = ${}", f.field, i + 1 + offset),
98 Op::Null => format!("\"{}\" IS NULL", f.field), Op::Ne => format!("\"{}\" != ${}", f.field, i + 1 + offset),
100 Op::Gt => format!("\"{}\" > ${}", f.field, i + 1 + offset),
101 Op::Lt => format!("\"{}\" < ${}", f.field, i + 1 + offset),
102 Op::In => format!("\"{}\" = ANY(${})", f.field, i + 1 + offset),
103 _ => unreachable!("update ops not valid in filter context"),
104 })
105 .collect::<Vec<_>>()
106 .join(" AND ");
107
108 let values = self.filters.iter().map(|f| f.value.clone()).collect();
109 (clause, values)
110 }
111 fn into_postgres_update(self) -> (String, Vec<DbValue>) {
112 let clause = self
113 .updates
114 .iter()
115 .enumerate()
116 .map(|(i, f)| match f.op {
117 Op::Set => format!("\"{}\" = ${}", f.field, i + 1),
118 Op::Inc => format!("\"{}\" = \"{}\" + ${}", f.field, f.field, i + 1),
119 Op::Unset => format!("\"{}\" = NULL", f.field),
120 _ => unreachable!("filter ops not valid in update context"),
121 })
122 .collect::<Vec<_>>()
123 .join(" , ");
124
125 let values = self.updates.iter().map(|f| f.value.clone()).collect();
126 (clause, values)
127 }
128
129 fn into_sqlite_filter(self) -> (String, Vec<DbValue>) {
131 let clause = self
132 .filters
133 .iter()
134 .map(|f| match f.op {
135 Op::Eq => format!("\"{}\" = ?", f.field),
136 Op::Null => format!("\"{}\" IS NULL", f.field),
137 Op::Ne => format!("\"{}\" != ?", f.field),
138 Op::Gt => format!("\"{}\" > ?", f.field),
139 Op::Lt => format!("\"{}\" < ?", f.field),
140 Op::In => match &f.value {
142 DbValue::List(list) => {
143 let placeholders = list.iter().map(|_| "?").collect::<Vec<_>>().join(", ");
144 format!("\"{}\" IN ({})", f.field, placeholders)
145 }
146 _ => unreachable!("In op must have List value"),
147 },
148 _ => unreachable!("update ops not valid in filter context"),
149 })
150 .collect::<Vec<_>>()
151 .join(" AND ");
152
153 let values = self
155 .filters
156 .iter()
157 .flat_map(|f| match &f.value {
158 DbValue::List(list) => list.clone(),
159 _ => vec![f.value.clone()],
160 })
161 .collect();
162
163 (clause, values)
164 }
165 fn into_sqlite_update(self) -> (String, Vec<DbValue>) {
166 let clause = self
167 .updates
168 .iter()
169 .map(|f| match f.op {
170 Op::Set => format!("\"{}\" = ?", f.field),
171 Op::Inc => format!("\"{}\" = \"{}\" + ?", f.field, f.field),
172 Op::Unset => format!("\"{}\" = NULL", f.field),
173 _ => unreachable!("filter ops not valid in update context"),
174 })
175 .collect::<Vec<_>>()
176 .join(" , ");
177
178 let values = self.updates.iter().map(|f| f.value.clone()).collect();
179 (clause, values)
180 }
181}