Skip to content

Commit 3e20fac

Browse files
committed
Initialise database in Postgres service
Signed-off-by: itowlson <ivan.towlson@fermyon.com>
1 parent dfb0c5d commit 3e20fac

15 files changed

Lines changed: 572 additions & 68 deletions

File tree

Cargo.lock

Lines changed: 388 additions & 33 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/postgres/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ crate-type = ["cdylib"]
99
[dependencies]
1010
anyhow = { workspace = true }
1111
helper = { workspace = true }
12+
rust_decimal = "1.37"
1213
wit-bindgen = { workspace = true }

components/postgres/src/lib.rs

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@ use helper::bindings::{
77
},
88
wasi::http0_2_0::types::{IncomingRequest, OutgoingResponse, ResponseOutparam},
99
};
10+
use rust_decimal::Decimal;
1011

1112
struct Component;
1213
helper::gen_http_trigger_bindings!(Component);
1314

14-
// Format: "host=localhost port=5432 user=postgres password=my_password dbname=mydb"
15+
// Format: "host=localhost port=5432 user=postgres password=postgres dbname=spin_dev"
1516
const PG_CONNECTION_STRING: &str = "PG_CONNECTION_STRING";
1617

1718
impl bindings::Guest for Component {
@@ -24,9 +25,7 @@ fn handle(request: IncomingRequest) -> anyhow::Result<OutgoingResponse> {
2425
let conn_str = get_header(&request, PG_CONNECTION_STRING)?;
2526
let conn = Connection::open(&conn_str)?;
2627

27-
let rowset = numeric_types(&conn)?;
28-
ensure!(rowset.rows.iter().all(|r| r.len() == 12));
29-
ensure!(matches!(rowset.rows[0][11], DbValue::Floating64(f) if f == 1.0));
28+
test_numeric_types(&conn)?;
3029

3130
let rowset = character_types(&conn)?;
3231
ensure!(rowset.rows.iter().all(|r| r.len() == 3));
@@ -82,38 +81,50 @@ fn handle(request: IncomingRequest) -> anyhow::Result<OutgoingResponse> {
8281
Ok(helper::ok_response())
8382
}
8483

85-
fn numeric_types(conn: &Connection) -> Result<RowSet, PgError> {
86-
let create_table_sql = r#"
87-
CREATE TEMPORARY TABLE test_numeric_types (
88-
intid integer GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
89-
rsmallserial smallserial NOT NULL,
90-
rsmallint smallint NOT NULL,
91-
rint2 int2 NOT NULL,
92-
rserial serial NOT NULL,
93-
rint int NOT NULL,
94-
rint4 int4 NOT NULL,
95-
rbigserial bigserial NOT NULL,
96-
rbigint bigint NOT NULL,
97-
rint8 int8 NOT NULL,
98-
rreal real NOT NULL,
99-
rdouble double precision NOT NULL
100-
);
101-
"#;
102-
103-
conn.execute(create_table_sql, &[])?;
84+
fn test_numeric_types(conn: &Connection) -> anyhow::Result<()> {
85+
const R_SMALLINT: i16 = 13;
86+
const R_INT2: i16 = 14;
87+
const R_INT: i32 = 15;
88+
const R_INT4: i32 = 16;
89+
const R_BIGINT: i64 = 17;
90+
const R_INT8: i64 = 18;
91+
const R_REAL: f32 = 19.2;
92+
const R_DOUBLE: f64 = 20.3;
93+
const R_NUMERIC: &str = "123456789.123456789";
10494

105-
let insert_sql = r#"
106-
INSERT INTO test_numeric_types
107-
(rsmallint, rint2, rint, rint4, rbigint, rint8, rreal, rdouble)
108-
VALUES
109-
(0, 0, 0, 0, 0, 0, 0, 1);
95+
let sql = r#"
96+
INSERT INTO test_numeric_types(
97+
id,
98+
rsmallint,
99+
rint2,
100+
rint,
101+
rint4,
102+
rbigint,
103+
rint8,
104+
rreal,
105+
rdouble,
106+
rnumeric
107+
) VALUES (
108+
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10
109+
);
110110
"#;
111111

112-
conn.execute(insert_sql, &[])?;
112+
conn.execute(sql, &[
113+
ParameterValue::Int32(2), // id used only for sorting
114+
ParameterValue::Int16(R_SMALLINT),
115+
ParameterValue::Int16(R_INT2),
116+
ParameterValue::Int32(R_INT),
117+
ParameterValue::Int32(R_INT4),
118+
ParameterValue::Int64(R_BIGINT),
119+
ParameterValue::Int64(R_INT8),
120+
ParameterValue::Floating32(R_REAL),
121+
ParameterValue::Floating64(R_DOUBLE),
122+
ParameterValue::Decimal(R_NUMERIC.to_owned()),
123+
])?;
113124

114125
let sql = r#"
115126
SELECT
116-
intid,
127+
id,
117128
rsmallserial,
118129
rsmallint,
119130
rint2,
@@ -124,11 +135,44 @@ fn numeric_types(conn: &Connection) -> Result<RowSet, PgError> {
124135
rbigint,
125136
rint8,
126137
rreal,
127-
rdouble
128-
FROM test_numeric_types;
138+
rdouble,
139+
rnumeric
140+
FROM test_numeric_types
141+
ORDER BY id;
129142
"#;
130143

131-
conn.query(sql, &[])
144+
let rowset = conn.query(sql, &[])?;
145+
146+
ensure!(rowset.rows.len() == 2);
147+
ensure!(rowset.rows.iter().all(|r| r.len() == 13));
148+
149+
// Spin correctly decodes Postgres values
150+
ensure!(matches!(rowset.rows[0][1], DbValue::Int16(_))); // rsmallserial
151+
ensure!(matches!(rowset.rows[0][2], DbValue::Int16(1))); // rsmallint
152+
ensure!(matches!(rowset.rows[0][3], DbValue::Int16(2))); // rint2
153+
ensure!(matches!(rowset.rows[0][4], DbValue::Int32(_))); // rserial
154+
ensure!(matches!(rowset.rows[0][5], DbValue::Int32(3))); // rint
155+
ensure!(matches!(rowset.rows[0][6], DbValue::Int32(4))); // rint4
156+
ensure!(matches!(rowset.rows[0][7], DbValue::Int64(_))); // rbigserial
157+
ensure!(matches!(rowset.rows[0][8], DbValue::Int64(5))); // rbigint
158+
ensure!(matches!(rowset.rows[0][9], DbValue::Int64(6))); // rint8
159+
ensure!(matches!(rowset.rows[0][10], DbValue::Floating32(7.8))); // rreal
160+
ensure!(matches!(rowset.rows[0][11], DbValue::Floating64(9.1))); // rdouble
161+
ensure!(matches!(rowset.rows[0][12], DbValue::Decimal(ref d) if Decimal::from_str_exact(d)? == Decimal::from_i128_with_scale(123456789i128, 9))); // rnumeric
162+
163+
// Values inserted by Spin round-trip correctly
164+
// (we can omit the serials here as those are set by the database)
165+
ensure!(matches!(rowset.rows[1][2], DbValue::Int16(R_SMALLINT))); // rsmallint
166+
ensure!(matches!(rowset.rows[1][3], DbValue::Int16(R_INT2))); // rint2
167+
ensure!(matches!(rowset.rows[1][5], DbValue::Int32(R_INT))); // rint
168+
ensure!(matches!(rowset.rows[1][6], DbValue::Int32(R_INT4))); // rint4
169+
ensure!(matches!(rowset.rows[1][8], DbValue::Int64(R_BIGINT))); // rbigint
170+
ensure!(matches!(rowset.rows[1][9], DbValue::Int64(R_INT8))); // rint8
171+
ensure!(matches!(rowset.rows[1][10], DbValue::Floating32(R_REAL))); // rreal
172+
ensure!(matches!(rowset.rows[1][11], DbValue::Floating64(R_DOUBLE))); // rdouble
173+
ensure!(matches!(rowset.rows[1][12], DbValue::Decimal(ref d) if Decimal::from_str_exact(d)? == Decimal::from_i128_with_scale(123456789123456789i128, 9))); // rnumeric
174+
175+
Ok(())
132176
}
133177

134178
fn character_types(conn: &Connection) -> Result<RowSet, PgError> {
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE test_array_types (
2+
id integer,
3+
i4arr int4[] NOT NULL,
4+
i8arr int8[] NOT NULL,
5+
numarr numeric[] NOT NULL,
6+
strarr text[] NOT NULL
7+
);
8+
9+
INSERT INTO test_array_types
10+
(id, i4arr, i8arr, numarr, strarr)
11+
VALUES
12+
(1, '{1,2,3}', '{101, 102, 103, 104}', '{1.234, 2.345}', '{"hello", "mum"}');
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CREATE TABLE test_blob_types (
2+
id integer,
3+
blob bytea NOT NULL
4+
);
5+
6+
INSERT INTO test_blob_types
7+
(id, blob)
8+
VALUES
9+
(1, 'abcdef');
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
CREATE TABLE test_date_time_types (
2+
id integer,
3+
rdate date NOT NULL,
4+
rtime time NOT NULL,
5+
rtimestamp timestamp NOT NULL,
6+
rinterval interval NOT NULL
7+
);
8+
9+
INSERT INTO test_date_time_types
10+
(id, rdate, rtime, rtimestamp, rinterval)
11+
VALUES
12+
(0, date '2525-12-25', time '04:05:06.789', timestamp '1989-11-24 01:02:03', 'P1Y2M3DT4H5M6.7S');
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CREATE TABLE test_json_types (
2+
id integer,
3+
j jsonb NOT NULL
4+
);
5+
6+
INSERT INTO test_json_types
7+
(id, j)
8+
VALUES
9+
(1, jsonb('{ "s": "hello", "n": 123, "b": true, "x": null }'));
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
CREATE TABLE test_nullable (
2+
id integer,
3+
rvarchar varchar(40)
4+
);
5+
6+
INSERT INTO test_nullable
7+
(id, rvarchar)
8+
VALUES
9+
(1, NULL);
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
CREATE TABLE test_numeric_types (
2+
id integer,
3+
rsmallserial smallserial NOT NULL,
4+
rsmallint smallint NOT NULL,
5+
rint2 int2 NOT NULL,
6+
rserial serial NOT NULL,
7+
rint int NOT NULL,
8+
rint4 int4 NOT NULL,
9+
rbigserial bigserial NOT NULL,
10+
rbigint bigint NOT NULL,
11+
rint8 int8 NOT NULL,
12+
rreal real NOT NULL,
13+
rdouble double precision NOT NULL,
14+
rnumeric numeric NOT NULL
15+
);
16+
17+
INSERT INTO test_numeric_types
18+
(id, rsmallint, rint2, rint, rint4, rbigint, rint8, rreal, rdouble, rnumeric)
19+
VALUES
20+
(0, 1, 2, 3, 4, 5, 6, 7.8, 9.1, 0.123456789);
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
CREATE TABLE test_range_types (
2+
id integer,
3+
r4 int4range NOT NULL,
4+
r8 int8range NOT NULL,
5+
rnum numrange NOT NULL
6+
);
7+
8+
INSERT INTO test_range_types
9+
(id, r4, r8, rnum)
10+
VALUES
11+
(1, '[1, 5)', '(123456789012, 234567890123]', numrange(NULL, 100));

0 commit comments

Comments
 (0)