Skip to content

Commit a7959c2

Browse files
committed
Implement correct (but untested) filtering
1 parent 65f34b3 commit a7959c2

File tree

1 file changed

+281
-19
lines changed

1 file changed

+281
-19
lines changed

src/filter.rs

Lines changed: 281 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,290 @@
11
use crate::Builder;
22

3-
macro_rules! filter {
4-
( $( $op:ident ),* ) => {
5-
$(
6-
pub fn $op(mut self, column: &str, param: &str) -> Self {
7-
self.queries.push((column.to_string(),
8-
format!("{}.{}", stringify!($op), param)));
9-
self
10-
}
11-
)*
3+
impl Builder {
4+
pub fn eq<S, T>(mut self, column: S, param: T) -> Self
5+
where
6+
S: Into<String>,
7+
T: Into<String>,
8+
{
9+
self.queries
10+
.push((column.into(), format!("eq.{}", param.into())));
11+
self
1212
}
13-
}
1413

15-
impl Builder {
16-
// It's unfortunate that `in` is a keyword, otherwise it'd belong in the
17-
// collection of filters below
18-
filter!(
19-
eq, gt, gte, lt, lte, neq, like, ilike, is, fts, plfts, phfts, wfts, cs, cd, ov, sl, sr,
20-
nxr, nxl, adj, not
21-
);
14+
pub fn neq<S, T>(mut self, column: S, param: T) -> Self
15+
where
16+
S: Into<String>,
17+
T: Into<String>,
18+
{
19+
self.queries
20+
.push((column.into(), format!("neq.{}", param.into())));
21+
self
22+
}
23+
24+
pub fn gt<S, T>(mut self, column: S, param: T) -> Self
25+
where
26+
S: Into<String>,
27+
T: Into<String>,
28+
{
29+
self.queries
30+
.push((column.into(), format!("gt.{}", param.into())));
31+
self
32+
}
33+
34+
pub fn gte<S, T>(mut self, column: S, param: T) -> Self
35+
where
36+
S: Into<String>,
37+
T: Into<String>,
38+
{
39+
self.queries
40+
.push((column.into(), format!("gte.{}", param.into())));
41+
self
42+
}
43+
44+
pub fn lt<S, T>(mut self, column: S, param: T) -> Self
45+
where
46+
S: Into<String>,
47+
T: Into<String>,
48+
{
49+
self.queries
50+
.push((column.into(), format!("lt.{}", param.into())));
51+
self
52+
}
53+
54+
pub fn lte<S, T>(mut self, column: S, param: T) -> Self
55+
where
56+
S: Into<String>,
57+
T: Into<String>,
58+
{
59+
self.queries
60+
.push((column.into(), format!("lte.{}", param.into())));
61+
self
62+
}
2263

23-
pub fn in_(mut self, column: &str, param: &str) -> Self {
64+
pub fn like<S>(mut self, column: S, param: &str) -> Self
65+
where
66+
S: Into<String>,
67+
{
68+
let param = str::replace(param, '%', "*");
2469
self.queries
25-
.push((column.to_string(), format!("in.{}", param)));
70+
.push((column.into(), format!("like.{}", param)));
2671
self
2772
}
73+
74+
pub fn ilike<S>(mut self, column: S, param: &str) -> Self
75+
where
76+
S: Into<String>,
77+
{
78+
let param = str::replace(param, '%', "*");
79+
self.queries
80+
.push((column.into(), format!("ilike.{}", param)));
81+
self
82+
}
83+
84+
pub fn is<S, T>(mut self, column: S, param: T) -> Self
85+
where
86+
S: Into<String>,
87+
T: Into<String>,
88+
{
89+
self.queries
90+
.push((column.into(), format!("is.{}", param.into())));
91+
self
92+
}
93+
94+
pub fn in_<S, T>(mut self, column: S, param: T) -> Self
95+
where
96+
S: Into<String>,
97+
T: Into<Vec<String>>,
98+
{
99+
// As per PostgREST docs, `in` should allow quoted commas
100+
let param: Vec<String> = param
101+
.into()
102+
.iter()
103+
.map(|s| {
104+
if s.contains(',') {
105+
format!("\"{}\"", s)
106+
} else {
107+
s.to_string()
108+
}
109+
})
110+
.collect();
111+
self.queries
112+
.push((column.into(), format!("in.({})", param.join(","))));
113+
self
114+
}
115+
116+
pub fn cs<S, T>(mut self, column: S, param: T) -> Self
117+
where
118+
S: Into<String>,
119+
T: Into<Vec<String>>,
120+
{
121+
self.queries
122+
.push((column.into(), format!("cs.{{{}}}", param.into().join(","))));
123+
self
124+
}
125+
126+
pub fn cd<S, T>(mut self, column: S, param: T) -> Self
127+
where
128+
S: Into<String>,
129+
T: Into<Vec<String>>,
130+
{
131+
self.queries
132+
.push((column.into(), format!("cd.{{{}}}", param.into().join(","))));
133+
self
134+
}
135+
136+
pub fn sl<S, T>(mut self, column: S, param: T) -> Self
137+
where
138+
S: Into<String>,
139+
T: Into<String>,
140+
{
141+
self.queries
142+
.push((column.into(), format!("sl.{}", param.into())));
143+
self
144+
}
145+
146+
pub fn sr<S, T>(mut self, column: S, param: T) -> Self
147+
where
148+
S: Into<String>,
149+
T: Into<String>,
150+
{
151+
self.queries
152+
.push((column.into(), format!("sr.{}", param.into())));
153+
self
154+
}
155+
156+
pub fn nxl<S, T>(mut self, column: S, param: T) -> Self
157+
where
158+
S: Into<String>,
159+
T: Into<String>,
160+
{
161+
self.queries
162+
.push((column.into(), format!("nxl.{}", param.into())));
163+
self
164+
}
165+
166+
pub fn nxr<S, T>(mut self, column: S, param: T) -> Self
167+
where
168+
S: Into<String>,
169+
T: Into<String>,
170+
{
171+
self.queries
172+
.push((column.into(), format!("nxr.{}", param.into())));
173+
self
174+
}
175+
176+
pub fn adj<S, T>(mut self, column: S, param: T) -> Self
177+
where
178+
S: Into<String>,
179+
T: Into<String>,
180+
{
181+
self.queries
182+
.push((column.into(), format!("adj.{}", param.into())));
183+
self
184+
}
185+
186+
pub fn ov<S, T>(mut self, column: S, param: T) -> Self
187+
where
188+
S: Into<String>,
189+
T: Into<String>,
190+
{
191+
self.queries
192+
.push((column.into(), format!("ov.{}", param.into())));
193+
self
194+
}
195+
196+
pub fn fts<S, T>(mut self, column: S, tsquery: T, config: Option<String>) -> Self
197+
where
198+
S: Into<String>,
199+
T: Into<String>,
200+
{
201+
let config = if let Some(conf) = config {
202+
format!("({})", conf)
203+
} else {
204+
String::new()
205+
};
206+
self.queries
207+
.push((column.into(), format!("fts{}.{}", config, tsquery.into())));
208+
self
209+
}
210+
211+
pub fn plfts<S, T>(mut self, column: S, tsquery: T, config: Option<String>) -> Self
212+
where
213+
S: Into<String>,
214+
T: Into<String>,
215+
{
216+
let config = if let Some(conf) = config {
217+
format!("({})", conf)
218+
} else {
219+
String::new()
220+
};
221+
self.queries
222+
.push((column.into(), format!("plfts{}.{}", config, tsquery.into())));
223+
self
224+
}
225+
226+
pub fn phfts<S, T>(mut self, column: S, tsquery: T, config: Option<String>) -> Self
227+
where
228+
S: Into<String>,
229+
T: Into<String>,
230+
{
231+
let config = if let Some(conf) = config {
232+
format!("({})", conf)
233+
} else {
234+
String::new()
235+
};
236+
self.queries
237+
.push((column.into(), format!("phfts{}.{}", config, tsquery.into())));
238+
self
239+
}
240+
241+
pub fn wfts<S, T>(mut self, column: S, tsquery: T, config: Option<String>) -> Self
242+
where
243+
S: Into<String>,
244+
T: Into<String>,
245+
{
246+
let config = if let Some(conf) = config {
247+
format!("({})", conf)
248+
} else {
249+
String::new()
250+
};
251+
self.queries
252+
.push((column.into(), format!("wfts{}.{}", config, tsquery.into())));
253+
self
254+
}
255+
}
256+
257+
#[cfg(test)]
258+
mod tests {
259+
use crate::Postgrest;
260+
261+
const REST_URL: &str = "http://localhost:3000";
262+
263+
#[test]
264+
fn simple_filters_assert_query() {
265+
let client = Postgrest::new(REST_URL);
266+
267+
let req = client.from("users").select("ignored").eq("column", "key");
268+
assert_eq!(
269+
req.queries
270+
.contains(&("column".to_string(), "eq.key".to_string())),
271+
true
272+
);
273+
274+
let req = client.from("users").select("ignored").neq("column", "key");
275+
assert_eq!(
276+
req.queries
277+
.contains(&("column".to_string(), "neq.key".to_string())),
278+
true
279+
);
280+
281+
let req = client.from("users").select("ignored").gt("column", "key");
282+
assert_eq!(
283+
req.queries
284+
.contains(&("column".to_string(), "gt.key".to_string())),
285+
true
286+
);
287+
288+
// ...
289+
}
28290
}

0 commit comments

Comments
 (0)