Skip to content

Commit 01118c5

Browse files
committed
feat(examples): Expand rust-outbound-pg example
Uncomment write fn and map it to the `/write` endpoint. Also, add basic README. Signed-off-by: Konstantin Shabanov <mail@etehtsea.me>
1 parent f5c6a08 commit 01118c5

File tree

4 files changed

+101
-16
lines changed

4 files changed

+101
-16
lines changed

examples/rust-outbound-pg/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Spin Outbound PostgreSQL example
2+
3+
This example shows how to access a PostgreSQL database from Spin component.
4+
5+
## Spin up
6+
7+
From example root:
8+
9+
```
10+
createdb spin_dev
11+
psql -d spin_dev -f db/testdata.sql
12+
RUST_LOG=spin=trace spin build --up
13+
```
14+
15+
Curl the read route:
16+
17+
```
18+
$ curl -i localhost:3000/read
19+
HTTP/1.1 200 OK
20+
content-length: 501
21+
date: Sun, 25 Sep 2022 15:45:02 GMT
22+
23+
Found 2 article(s) as follows:
24+
article: Article {
25+
id: 1,
26+
title: "My Life as a Goat",
27+
content: "I went to Nepal to live as a goat, and it was much better than being a butler.",
28+
authorname: "E. Blackadder",
29+
}
30+
article: Article {
31+
id: 2,
32+
title: "Magnificent Octopus",
33+
content: "Once upon a time there was a lovely little sausage.",
34+
authorname: "S. Baldrick",
35+
}
36+
37+
(Column info: id:DbDataType::Int32, title:DbDataType::Str, content:DbDataType::Str, authorname:DbDataType::Str)
38+
```
39+
40+
Curl the write route:
41+
42+
```
43+
$ curl -i localhost:3000/write
44+
HTTP/1.1 200 OK
45+
content-length: 9
46+
date: Sun, 25 Sep 2022 15:46:22 GMT
47+
48+
Count: 3
49+
```
Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,18 @@
11
CREATE TABLE articletest (
2-
id integer not null,
3-
title varchar(40) not null,
4-
content varchar(8000) not null,
5-
authorname varchar(40) not null
2+
id integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
3+
title varchar(40) NOT NULL,
4+
content text NOT NULL,
5+
authorname varchar(40) NOT NULL
66
);
77

8-
INSERT INTO articletest VALUES (1, 'My Life as a Goat', 'I went to Nepal to live as a goat, and it was much better than being a butler.', 'E. Blackadder');
9-
INSERT INTO articletest VALUES (2, 'Magnificent Octopus', 'Once upon a time there was a lovely little sausage.', 'S. Baldrick');
8+
INSERT INTO articletest (title, content, authorname) VALUES
9+
(
10+
'My Life as a Goat',
11+
'I went to Nepal to live as a goat, and it was much better than being a butler.',
12+
'E. Blackadder'
13+
),
14+
(
15+
'Magnificent Octopus',
16+
'Once upon a time there was a lovely little sausage.',
17+
'S. Baldrick'
18+
);

examples/rust-outbound-pg/spin.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@ trigger = { type = "http", base = "/" }
55
version = "0.1.0"
66

77
[[component]]
8-
environment = { DB_URL = "host=localhost user=postgres password=123 dbname=postgres" }
8+
environment = { DB_URL = "host=localhost user=postgres dbname=spin_dev" }
99
id = "outbound-pg"
1010
source = "target/wasm32-wasi/release/rust_outbound_pg.wasm"
1111
[component.trigger]
12-
#route = "/write"
13-
route = "/read"
12+
route = "/..."
1413
[component.build]
1514
command = "cargo build --target wasm32-wasi --release"
16-

examples/rust-outbound-pg/src/lib.rs

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,20 @@ struct Article {
1818
}
1919

2020
#[http_component]
21+
fn process(req: Request) -> Result<Response> {
22+
match req.uri().path() {
23+
"/read" => read(req),
24+
"/write" => write(req),
25+
_ => Ok(http::Response::builder()
26+
.status(404)
27+
.body(Some("Not found".into()))?),
28+
}
29+
}
30+
2131
fn read(_req: Request) -> Result<Response> {
2232
let address = std::env::var(DB_URL_ENV)?;
2333

24-
let sql = "select id, title, content, authorname from articletest";
34+
let sql = "SELECT id, title, content, authorname FROM articletest";
2535
let rowset = pg::query(&address, sql, &[])
2636
.map_err(|e| anyhow!("Error executing Postgres query: {:?}", e))?;
2737

@@ -64,18 +74,27 @@ fn read(_req: Request) -> Result<Response> {
6474
.status(200)
6575
.body(Some(response.into()))?)
6676
}
67-
/*
77+
6878
fn write(_req: Request) -> Result<Response> {
6979
let address = std::env::var(DB_URL_ENV)?;
7080

71-
let sql = "insert into articletest values ('aaa', 'bbb', 'ccc')";
72-
let nrow_executed = pg::execute(&address, sql, &vec![]).map_err(|_| anyhow!("Error execute pg command"))?;
81+
let sql = "INSERT INTO articletest (title, content, authorname) VALUES ('aaa', 'bbb', 'ccc')";
82+
let nrow_executed =
83+
pg::execute(&address, sql, &[]).map_err(|_| anyhow!("Error execute pg command"))?;
7384

7485
println!("nrow_executed: {}", nrow_executed);
7586

76-
Ok(http::Response::builder().status(200).body(None)?)
87+
let sql = "SELECT COUNT(id) FROM articletest";
88+
let rowset = pg::query(&address, sql, &[])
89+
.map_err(|e| anyhow!("Error executing Postgres query: {:?}", e))?;
90+
let row = &rowset.rows[0];
91+
let count = as_bigint(&row[0])?;
92+
let response = format!("Count: {}\n", count);
93+
94+
Ok(http::Response::builder()
95+
.status(200)
96+
.body(Some(response.into()))?)
7797
}
78-
*/
7998

8099
fn as_owned_string(value: &pg::DbValue) -> anyhow::Result<String> {
81100
match value {
@@ -94,6 +113,16 @@ fn as_int(value: &pg::DbValue) -> anyhow::Result<i32> {
94113
}
95114
}
96115

116+
fn as_bigint(value: &pg::DbValue) -> anyhow::Result<i64> {
117+
match value {
118+
pg::DbValue::Int64(n) => Ok(*n),
119+
_ => Err(anyhow!(
120+
"Expected integer from database but got {:?}",
121+
value
122+
)),
123+
}
124+
}
125+
97126
fn format_col(column: &pg::Column) -> String {
98127
format!("{}:{:?}", column.name, column.data_type)
99128
}

0 commit comments

Comments
 (0)