Skip to content

Commit fb4db9c

Browse files
committed
Add basic support for filters
1 parent 8284bb0 commit fb4db9c

File tree

1 file changed

+77
-17
lines changed

1 file changed

+77
-17
lines changed

src/builder.rs

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,83 @@
11
use reqwest::{Client, Error, Method, Response};
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+
)*
12+
}
13+
}
14+
315
pub struct Builder {
4-
method: Option<Method>,
16+
method: Method,
517
url: String,
618
queries: Vec<(String, String)>,
719
headers: Vec<(String, String)>,
820
body: Option<String>,
921
}
1022

23+
// TODO: Complex filters (not, and, or)
24+
// TODO: Switching schema
25+
// TODO: Exact, planned, estimated count (HEAD verb)
26+
// TODO: Response format
27+
// TODO: Embedded resources
1128
impl Builder {
12-
// TODO: Switching schema
1329
pub fn new(url: &str) -> Self {
1430
Builder {
15-
method: None,
31+
method: Method::GET,
1632
url: url.to_string(),
1733
queries: Vec::new(),
1834
headers: Vec::new(),
1935
body: None,
2036
}
2137
}
2238

39+
// TODO: Multiple columns
40+
// TODO: Renaming columns
41+
// TODO: Casting columns
42+
// TODO: JSON columns
43+
// TODO: Computed (virtual) columns
44+
// TODO: Investigate character corner cases (Unicode, [ .,:()])
2345
pub fn select(mut self, column: &str) -> Self {
24-
self.method = Some(Method::GET);
25-
let column = column.chars().filter(|c| !c.is_whitespace()).collect();
26-
self.queries.push(("select".to_string(), column));
46+
self.method = Method::GET;
47+
self.queries
48+
.push(("select".to_string(), column.to_string()));
49+
self
50+
}
51+
52+
// TODO: desc/asc
53+
// TODO: nullsfirst/nullslast
54+
// TODO: Multiple columns
55+
// TODO: Computed columns
56+
pub fn order(mut self, column: &str) -> Self {
57+
self.queries.push(("order".to_string(), column.to_string()));
58+
self
59+
}
60+
61+
// TODO: Open-ended range
62+
pub fn limit(mut self, count: usize) -> Self {
63+
self.headers
64+
.push(("Content-Range".to_string(), format!("0-{}", count - 1)));
65+
self
66+
}
67+
68+
pub fn single(mut self) -> Self {
69+
self.headers.push((
70+
"Accept".to_string(),
71+
"application/vnd.pgrst.object+json".to_string(),
72+
));
2773
self
2874
}
2975

3076
// TODO: Write-only tables
3177
// TODO: URL-encoded payload
3278
// TODO: Allow specifying columns
3379
pub fn insert(mut self, body: &str) -> Self {
34-
self.method = Some(Method::POST);
80+
self.method = Method::POST;
3581
self.headers
3682
.push(("Prefer".to_string(), "return=representation".to_string()));
3783
self.body = Some(body.to_string());
@@ -47,41 +93,55 @@ impl Builder {
4793
// TODO: Allow Prefer: resolution=ignore-duplicates
4894
// TODO: on_conflict (make UPSERT work on UNIQUE columns)
4995
pub fn upsert(mut self, body: &str) -> Self {
50-
self.method = Some(Method::POST);
51-
self.headers
52-
.push(("Prefer".to_string(),
53-
"return=representation; resolution=merge-duplicates".to_string()));
96+
self.method = Method::POST;
97+
self.headers.push((
98+
"Prefer".to_string(),
99+
"return=representation; resolution=merge-duplicates".to_string(),
100+
));
54101
self.body = Some(body.to_string());
55102
self
56103
}
57104

58105
pub fn single_upsert(mut self, primary_column: &str, key: &str, body: &str) -> Self {
59-
self.method = Some(Method::PUT);
106+
self.method = Method::PUT;
60107
self.headers
61108
.push(("Prefer".to_string(), "return=representation".to_string()));
62-
self.queries.push((primary_column.to_string(),
63-
format!("eq.{}", key)));
109+
self.queries
110+
.push((primary_column.to_string(), format!("eq.{}", key)));
64111
self.body = Some(body.to_string());
65112
self
66113
}
67114

68115
pub fn update(mut self, body: &str) -> Self {
69-
self.method = Some(Method::PATCH);
116+
self.method = Method::PATCH;
70117
self.headers
71118
.push(("Prefer".to_string(), "return=representation".to_string()));
72119
self.body = Some(body.to_string());
73120
self
74121
}
75122

76123
pub fn delete(mut self) -> Self {
77-
self.method = Some(Method::DELETE);
124+
self.method = Method::DELETE;
78125
self.headers
79126
.push(("Prefer".to_string(), "return=representation".to_string()));
80127
self
81128
}
82129

130+
pub fn in_set(mut self, column: &str, param: &str) -> Self {
131+
self.queries
132+
.push((column.to_string(), format!("in.{}", param)));
133+
self
134+
}
135+
136+
// It's unfortunate that `in` is a keyword, otherwise it'd belong in the
137+
// collection of filters below
138+
filter!(
139+
eq, gt, gte, lt, lte, neq, like, ilike, is, fts, plfts, phfts, wfts, cs, cd, ov, sl, sr,
140+
nxr, nxl, adj, not
141+
);
142+
83143
pub async fn execute(self) -> Result<Response, Error> {
84-
let mut req = Client::new().request(self.method.unwrap(), &self.url);
144+
let mut req = Client::new().request(self.method, &self.url);
85145
for (k, v) in &self.headers {
86146
req = req.header(k, v);
87147
}

0 commit comments

Comments
 (0)