Skip to content

Commit 81107d4

Browse files
authored
Merge pull request #14 from supabase/test/integration
Add integration tests
2 parents 11d6ae7 + cd36422 commit 81107d4

File tree

6 files changed

+347
-12
lines changed

6 files changed

+347
-12
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ edition = "2018"
77
[dependencies]
88
reqwest = { version = "0.10", features = ["json"] }
99
tokio = { version = "0.2", features = ["full"] }
10+
11+
[dev-dependencies]
12+
json = "0.12"

src/builder.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
extern crate reqwest;
2-
31
use reqwest::{
42
header::{HeaderMap, HeaderValue},
53
Client, Error, Method, Response,
@@ -19,8 +17,9 @@ pub struct Builder {
1917
// TODO: Complex filters (not, and, or)
2018
// TODO: Exact, planned, estimated count (HEAD verb)
2119
// TODO: Response format
22-
// TODO: Embedded resources
23-
// TODO: Content type (csv, etc.)
20+
// TODO: Resource embedding (embedded filters, etc.)
21+
// TODO: Content-Type (text/csv, etc.)
22+
// TODO: Reject update/delete w/o filters
2423
impl Builder {
2524
pub fn new<S>(url: S, schema: Option<String>) -> Self
2625
where
@@ -126,10 +125,9 @@ impl Builder {
126125
S: Into<String>,
127126
{
128127
self.method = Method::POST;
129-
self.headers.append(
128+
self.headers.insert(
130129
"Prefer",
131-
// Maybe check if this works as intended...
132-
HeaderValue::from_static("return=representation; resolution=merge-duplicates"),
130+
HeaderValue::from_static("return=representation,resolution=merge-duplicates"),
133131
);
134132
self.body = Some(body.into());
135133
self
@@ -143,7 +141,7 @@ impl Builder {
143141
{
144142
self.method = Method::PUT;
145143
self.headers
146-
.append("Prefer", HeaderValue::from_static("return=representation"));
144+
.insert("Prefer", HeaderValue::from_static("return=representation"));
147145
self.queries
148146
.push((primary_column.into(), format!("eq.{}", key.into())));
149147
self.body = Some(body.into());
@@ -156,15 +154,15 @@ impl Builder {
156154
{
157155
self.method = Method::PATCH;
158156
self.headers
159-
.append("Prefer", HeaderValue::from_static("return=representation"));
157+
.insert("Prefer", HeaderValue::from_static("return=representation"));
160158
self.body = Some(body.into());
161159
self
162160
}
163161

164162
pub fn delete(mut self) -> Self {
165163
self.method = Method::DELETE;
166164
self.headers
167-
.append("Prefer", HeaderValue::from_static("return=representation"));
165+
.insert("Prefer", HeaderValue::from_static("return=representation"));
168166
self
169167
}
170168

@@ -189,6 +187,10 @@ impl Builder {
189187
self.headers
190188
.append(key, HeaderValue::from_str(&schema).unwrap());
191189
}
190+
if self.method != Method::GET && self.method != Method::HEAD {
191+
self.headers
192+
.insert("Content-Type", HeaderValue::from_static("application/json"));
193+
}
192194
req = req.headers(self.headers).query(&self.queries);
193195
if let Some(body) = self.body {
194196
req = req.body(body);
@@ -278,7 +280,7 @@ mod tests {
278280
let builder = Builder::new(TABLE_URL, None).upsert("ignored");
279281
assert_eq!(
280282
builder.headers.get("Prefer").unwrap(),
281-
HeaderValue::from_static("return=representation; resolution=merge-duplicates")
283+
HeaderValue::from_static("return=representation,resolution=merge-duplicates")
282284
);
283285
}
284286

@@ -303,4 +305,21 @@ mod tests {
303305
assert_eq!(builder.body.unwrap(), "{\"a\": 1, \"b\": 2}");
304306
assert_eq!(builder.is_rpc, true);
305307
}
308+
309+
#[test]
310+
fn chain_filters() -> Result<(), Box<dyn std::error::Error>> {
311+
let builder = Builder::new(TABLE_URL, None)
312+
.eq("username", "supabot")
313+
.neq("message", "hello world")
314+
.gte("channel_id", "1")
315+
.select("*");
316+
317+
let queries = builder.queries;
318+
assert_eq!(queries.len(), 4);
319+
assert!(queries.contains(&("username".into(), "eq.supabot".into())));
320+
assert!(queries.contains(&("message".into(), "neq.hello world".into())));
321+
assert!(queries.contains(&("channel_id".into(), "gte.1".into())));
322+
323+
Ok(())
324+
}
306325
}

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
extern crate reqwest;
2+
13
mod builder;
24
mod filter;
35

tests/client.rs

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
use postgrest::Postgrest;
2+
3+
use std::error::Error;
4+
5+
const REST_URL: &str = "http://localhost:3000";
6+
7+
#[tokio::test]
8+
async fn basic_data() -> Result<(), Box<dyn Error>> {
9+
let client = Postgrest::new(REST_URL);
10+
let resp = client
11+
.from("users")
12+
.select("username")
13+
.eq("status", "OFFLINE")
14+
.execute()
15+
.await?;
16+
let body = resp.text().await?;
17+
let body = json::parse(&body)?;
18+
19+
assert_eq!(body[0]["username"], "kiwicopple");
20+
21+
Ok(())
22+
}
23+
24+
#[tokio::test]
25+
async fn relational_join() -> Result<(), Box<dyn Error>> {
26+
let client = Postgrest::new(REST_URL);
27+
let resp = client
28+
.from("channels")
29+
.select("slug, messages(message)")
30+
.eq("slug", "public")
31+
.execute()
32+
.await?;
33+
let body = resp.text().await?;
34+
let body = json::parse(&body)?;
35+
36+
assert_eq!(body[0]["messages"][0]["message"], "Hello World 👋");
37+
assert_eq!(body[0]["slug"], "public");
38+
39+
Ok(())
40+
}
41+
42+
#[tokio::test]
43+
async fn insert() -> Result<(), Box<dyn Error>> {
44+
let client = Postgrest::new(REST_URL);
45+
let resp = client
46+
.from("messages")
47+
.insert(r#"[{"message": "Test message 0", "channel_id": 1, "username": "kiwicopple"}]"#)
48+
.execute()
49+
.await?;
50+
let status = resp.status();
51+
52+
assert_eq!(status.as_u16(), 201);
53+
54+
Ok(())
55+
}
56+
57+
#[tokio::test]
58+
async fn upsert() -> Result<(), Box<dyn Error>> {
59+
let client = Postgrest::new(REST_URL);
60+
let resp = client
61+
.from("users")
62+
.upsert(
63+
r#"[{"username": "dragarcia", "status": "OFFLINE"},
64+
{"username": "supabot2", "status": "ONLINE"}]"#,
65+
)
66+
.execute()
67+
.await?;
68+
let body = resp.text().await?;
69+
let body = json::parse(&body)?;
70+
71+
assert_eq!(body[0]["username"], "dragarcia");
72+
assert_eq!(body[1]["username"], "supabot2");
73+
74+
Ok(())
75+
}
76+
77+
#[tokio::test]
78+
async fn upsert_existing() -> Result<(), Box<dyn Error>> {
79+
let client = Postgrest::new(REST_URL);
80+
let resp = client
81+
.from("users")
82+
.upsert(r#"{"username": "dragarcia", "status": "ONLINE"}"#)
83+
.execute()
84+
.await?;
85+
let body = resp.text().await?;
86+
let body = json::parse(&body)?;
87+
88+
assert_eq!(body[0]["username"], "dragarcia");
89+
assert_eq!(body[0]["status"], "ONLINE");
90+
91+
Ok(())
92+
}
93+
94+
#[tokio::test]
95+
async fn upsert_nonexisting() -> Result<(), Box<dyn Error>> {
96+
let client = Postgrest::new(REST_URL);
97+
let resp = client
98+
.from("users")
99+
.upsert(r#"{"username": "supabot3", "status": "ONLINE"}"#)
100+
.execute()
101+
.await?;
102+
let body = resp.text().await?;
103+
let body = json::parse(&body)?;
104+
105+
assert_eq!(body[0]["username"], "supabot3");
106+
assert_eq!(body[0]["status"], "ONLINE");
107+
108+
Ok(())
109+
}
110+
111+
#[tokio::test]
112+
async fn update() -> Result<(), Box<dyn Error>> {
113+
let client = Postgrest::new(REST_URL);
114+
let resp = client
115+
.from("users")
116+
.eq("status", "ONLINE")
117+
.update(r#"{"status": "ONLINE"}"#)
118+
.execute()
119+
.await?;
120+
let status = resp.status();
121+
let body = resp.text().await?;
122+
let body = json::parse(&body)?;
123+
124+
assert_eq!(status.as_u16(), 200);
125+
assert_eq!(body[0]["status"], "ONLINE");
126+
127+
Ok(())
128+
}
129+
130+
#[tokio::test]
131+
async fn delete() -> Result<(), Box<dyn Error>> {
132+
let client = Postgrest::new(REST_URL);
133+
let resp = client
134+
.from("messages")
135+
.neq("username", "supabot")
136+
.delete()
137+
.execute()
138+
.await?;
139+
let status = resp.status();
140+
141+
assert_eq!(status.as_u16(), 200);
142+
143+
Ok(())
144+
}
145+
146+
#[tokio::test]
147+
async fn rpc() -> Result<(), Box<dyn Error>> {
148+
let client = Postgrest::new(REST_URL);
149+
let resp = client
150+
.rpc("get_status", r#"{"name_param": "leroyjenkins"}"#)
151+
.execute()
152+
.await?;
153+
let body = resp.text().await?;
154+
let body = json::parse(&body)?;
155+
156+
assert!(body.is_null());
157+
158+
Ok(())
159+
}

tests/db/docker-compose.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
version: "3"
22
services:
33
rest:
4-
image: postgrest/postgrest
4+
image: postgrest/postgrest:v7.0.1
55
ports:
66
- "3000:3000"
77
environment:

0 commit comments

Comments
 (0)