icydb_core/db/query/builder/
field.rs1use crate::{
2 db::query::predicate::{
3 CoercionId, CompareOp, ComparePredicate, Predicate, UnsupportedQueryFeature,
4 },
5 traits::FieldValue,
6 value::Value,
7};
8
9#[derive(Clone, Copy, Eq, Hash, PartialEq)]
18pub struct FieldRef(&'static str);
19
20impl FieldRef {
21 #[must_use]
23 pub const fn new(name: &'static str) -> Self {
24 Self(name)
25 }
26
27 #[must_use]
29 pub const fn as_str(self) -> &'static str {
30 self.0
31 }
32
33 #[must_use]
39 pub fn eq(self, value: impl FieldValue) -> Predicate {
40 Predicate::Compare(ComparePredicate::with_coercion(
41 self.0,
42 CompareOp::Eq,
43 value.to_value(),
44 CoercionId::Strict,
45 ))
46 }
47
48 #[must_use]
50 pub fn text_eq_ci(self, value: impl FieldValue) -> Predicate {
51 Predicate::Compare(ComparePredicate::with_coercion(
52 self.0,
53 CompareOp::Eq,
54 value.to_value(),
55 CoercionId::TextCasefold,
56 ))
57 }
58
59 #[must_use]
61 pub fn ne(self, value: impl FieldValue) -> Predicate {
62 Predicate::Compare(ComparePredicate::with_coercion(
63 self.0,
64 CompareOp::Ne,
65 value.to_value(),
66 CoercionId::Strict,
67 ))
68 }
69
70 #[must_use]
72 pub fn lt(self, value: impl FieldValue) -> Predicate {
73 Predicate::Compare(ComparePredicate::with_coercion(
74 self.0,
75 CompareOp::Lt,
76 value.to_value(),
77 CoercionId::NumericWiden,
78 ))
79 }
80
81 #[must_use]
83 pub fn lte(self, value: impl FieldValue) -> Predicate {
84 Predicate::Compare(ComparePredicate::with_coercion(
85 self.0,
86 CompareOp::Lte,
87 value.to_value(),
88 CoercionId::NumericWiden,
89 ))
90 }
91
92 #[must_use]
94 pub fn gt(self, value: impl FieldValue) -> Predicate {
95 Predicate::Compare(ComparePredicate::with_coercion(
96 self.0,
97 CompareOp::Gt,
98 value.to_value(),
99 CoercionId::NumericWiden,
100 ))
101 }
102
103 #[must_use]
105 pub fn gte(self, value: impl FieldValue) -> Predicate {
106 Predicate::Compare(ComparePredicate::with_coercion(
107 self.0,
108 CompareOp::Gte,
109 value.to_value(),
110 CoercionId::NumericWiden,
111 ))
112 }
113
114 #[must_use]
116 pub fn in_list<I, V>(self, values: I) -> Predicate
117 where
118 I: IntoIterator<Item = V>,
119 V: FieldValue,
120 {
121 Predicate::Compare(ComparePredicate::with_coercion(
122 self.0,
123 CompareOp::In,
124 Value::List(values.into_iter().map(|v| v.to_value()).collect()),
125 CoercionId::Strict,
126 ))
127 }
128
129 #[must_use]
135 pub fn is_null(self) -> Predicate {
136 Predicate::IsNull {
137 field: self.0.to_string(),
138 }
139 }
140
141 #[must_use]
143 pub fn is_missing(self) -> Predicate {
144 Predicate::IsMissing {
145 field: self.0.to_string(),
146 }
147 }
148
149 #[must_use]
151 pub fn is_empty(self) -> Predicate {
152 Predicate::IsEmpty {
153 field: self.0.to_string(),
154 }
155 }
156
157 #[must_use]
159 pub fn is_not_empty(self) -> Predicate {
160 Predicate::IsNotEmpty {
161 field: self.0.to_string(),
162 }
163 }
164
165 pub fn map_contains_key(
171 self,
172 _key: impl FieldValue,
173 _coercion: CoercionId,
174 ) -> Result<Predicate, UnsupportedQueryFeature> {
175 Err(UnsupportedQueryFeature::MapPredicate {
176 field: self.0.to_string(),
177 })
178 }
179
180 pub fn map_contains_value(
182 self,
183 _value: impl FieldValue,
184 _coercion: CoercionId,
185 ) -> Result<Predicate, UnsupportedQueryFeature> {
186 Err(UnsupportedQueryFeature::MapPredicate {
187 field: self.0.to_string(),
188 })
189 }
190
191 pub fn map_contains_entry(
193 self,
194 _key: impl FieldValue,
195 _value: impl FieldValue,
196 _coercion: CoercionId,
197 ) -> Result<Predicate, UnsupportedQueryFeature> {
198 Err(UnsupportedQueryFeature::MapPredicate {
199 field: self.0.to_string(),
200 })
201 }
202
203 #[must_use]
205 pub fn text_contains(self, value: impl FieldValue) -> Predicate {
206 Predicate::TextContains {
207 field: self.0.to_string(),
208 value: value.to_value(),
209 }
210 }
211
212 #[must_use]
214 pub fn text_contains_ci(self, value: impl FieldValue) -> Predicate {
215 Predicate::TextContainsCi {
216 field: self.0.to_string(),
217 value: value.to_value(),
218 }
219 }
220}
221
222impl AsRef<str> for FieldRef {
227 fn as_ref(&self) -> &str {
228 self.0
229 }
230}
231
232impl std::ops::Deref for FieldRef {
233 type Target = str;
234
235 fn deref(&self) -> &Self::Target {
236 self.0
237 }
238}
239
240#[cfg(test)]
241mod tests {
242 use crate::db::query::predicate::UnsupportedQueryFeature;
243
244 use super::FieldRef;
245
246 #[test]
247 fn map_predicate_builder_fails_immediately() {
248 let err = FieldRef::new("attributes")
249 .map_contains_entry("k", 1u64, super::CoercionId::Strict)
250 .expect_err("map predicate builder must fail immediately");
251
252 assert_eq!(
253 err,
254 UnsupportedQueryFeature::MapPredicate {
255 field: "attributes".to_string(),
256 }
257 );
258 }
259}