Skip to content

Commit 9e335b2

Browse files
committed
feat(spin_sdk::pg): Extract type conversions into sdk
This has to be the starting point on the way to providing the API that is able to automatically map a DB response into the user-defined struct. Signed-off-by: Konstantin Shabanov <[email protected]>
1 parent 99803d9 commit 9e335b2

File tree

3 files changed

+70
-72
lines changed
  • examples/rust-outbound-pg/src
  • sdk/rust/src
  • tests/outbound-pg/http-rust-outbound-pg/src

3 files changed

+70
-72
lines changed

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

Lines changed: 24 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
use anyhow::{anyhow, Result};
33
use spin_sdk::{
44
http::{Request, Response},
5-
http_component, pg,
5+
http_component,
6+
pg,
67
};
78

89
// The environment variable set in `spin.toml` that points to the
@@ -17,6 +18,24 @@ struct Article {
1718
authorname: String,
1819
}
1920

21+
impl TryFrom<&pg::Row> for Article {
22+
type Error = anyhow::Error;
23+
24+
fn try_from(row: &pg::Row) -> Result<Self, Self::Error> {
25+
let id: i32 = (&row[0]).try_into()?;
26+
let title: String = (&row[1]).try_into()?;
27+
let content: String = (&row[2]).try_into()?;
28+
let authorname: String = (&row[3]).try_into()?;
29+
30+
Ok(Self {
31+
id,
32+
title,
33+
content,
34+
authorname,
35+
})
36+
}
37+
}
38+
2039
#[http_component]
2140
fn process(req: Request) -> Result<Response> {
2241
match req.uri().path() {
@@ -46,17 +65,7 @@ fn read(_req: Request) -> Result<Response> {
4665
let mut response_lines = vec![];
4766

4867
for row in rowset.rows {
49-
let id = as_int(&row[0])?;
50-
let title = as_owned_string(&row[1])?;
51-
let content = as_owned_string(&row[2])?;
52-
let authorname = as_owned_string(&row[3])?;
53-
54-
let article = Article {
55-
id,
56-
title,
57-
content,
58-
authorname,
59-
};
68+
let article = Article::try_from(&row)?;
6069

6170
println!("article: {:#?}", article);
6271
response_lines.push(format!("article: {:#?}", article));
@@ -89,7 +98,7 @@ fn write(_req: Request) -> Result<Response> {
8998
let rowset = pg::query(&address, sql, &[])
9099
.map_err(|e| anyhow!("Error executing Postgres query: {:?}", e))?;
91100
let row = &rowset.rows[0];
92-
let count = as_bigint(&row[0])?;
101+
let count: i64 = (&row[0]).try_into()?;
93102
let response = format!("Count: {}\n", count);
94103

95104
Ok(http::Response::builder()
@@ -106,7 +115,8 @@ fn pg_backend_pid(_req: Request) -> Result<Response> {
106115
.map_err(|e| anyhow!("Error executing Postgres query: {:?}", e))?;
107116

108117
let row = &rowset.rows[0];
109-
as_int(&row[0])
118+
119+
i32::try_from(&row[0])
110120
};
111121

112122
assert_eq!(get_pid()?, get_pid()?);
@@ -118,33 +128,6 @@ fn pg_backend_pid(_req: Request) -> Result<Response> {
118128
.body(Some(response.into()))?)
119129
}
120130

121-
fn as_owned_string(value: &pg::DbValue) -> anyhow::Result<String> {
122-
match value {
123-
pg::DbValue::Str(s) => Ok(s.to_owned()),
124-
_ => Err(anyhow!("Expected string from database but got {:?}", value)),
125-
}
126-
}
127-
128-
fn as_int(value: &pg::DbValue) -> anyhow::Result<i32> {
129-
match value {
130-
pg::DbValue::Int32(n) => Ok(*n),
131-
_ => Err(anyhow!(
132-
"Expected integer from database but got {:?}",
133-
value
134-
)),
135-
}
136-
}
137-
138-
fn as_bigint(value: &pg::DbValue) -> anyhow::Result<i64> {
139-
match value {
140-
pg::DbValue::Int64(n) => Ok(*n),
141-
_ => Err(anyhow!(
142-
"Expected integer from database but got {:?}",
143-
value
144-
)),
145-
}
146-
}
147-
148131
fn format_col(column: &pg::Column) -> String {
149132
format!("{}:{:?}", column.name, column.data_type)
150133
}

sdk/rust/src/lib.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,48 @@ pub mod pg {
5353

5454
/// Exports the generated outbound Pg items.
5555
pub use outbound_pg::*;
56+
57+
impl TryFrom<&DbValue> for i32 {
58+
type Error = anyhow::Error;
59+
60+
fn try_from(value: &DbValue) -> Result<Self, Self::Error> {
61+
match value {
62+
DbValue::Int32(n) => Ok(*n),
63+
_ => Err(anyhow::anyhow!(
64+
"Expected integer from database but got {:?}",
65+
value
66+
)),
67+
}
68+
}
69+
}
70+
71+
impl TryFrom<&DbValue> for String {
72+
type Error = anyhow::Error;
73+
74+
fn try_from(value: &DbValue) -> Result<Self, Self::Error> {
75+
match value {
76+
DbValue::Str(s) => Ok(s.to_owned()),
77+
_ => Err(anyhow::anyhow!(
78+
"Expected string from the DB but got {:?}",
79+
value
80+
)),
81+
}
82+
}
83+
}
84+
85+
impl TryFrom<&DbValue> for i64 {
86+
type Error = anyhow::Error;
87+
88+
fn try_from(value: &DbValue) -> Result<Self, Self::Error> {
89+
match value {
90+
DbValue::Int64(n) => Ok(*n),
91+
_ => Err(anyhow::anyhow!(
92+
"Expected integer from the DB but got {:?}",
93+
value
94+
)),
95+
}
96+
}
97+
}
5698
}
5799

58100
/// Implementation of the spin config interface.

tests/outbound-pg/http-rust-outbound-pg/src/lib.rs

Lines changed: 4 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,9 @@ fn test_read_types(_req: Request) -> Result<Response> {
6767
let mut response_lines = vec![];
6868

6969
for row in rowset.rows {
70-
let id = as_int(&row[0])?;
71-
let rvarchar = as_owned_string(&row[1])?;
72-
let rtext = as_owned_string(&row[2])?;
70+
let id: i32 = (&row[0]).try_into()?;
71+
let rvarchar: String = (&row[1]).try_into()?;
72+
let rtext: String = (&row[2]).try_into()?;
7373

7474
let row = Row {
7575
id,
@@ -101,7 +101,7 @@ fn pg_backend_pid(_req: Request) -> Result<Response> {
101101
.map_err(|e| anyhow!("Error executing Postgres query: {:?}", e))?;
102102

103103
let row = &rowset.rows[0];
104-
as_int(&row[0])
104+
i32::try_from(&row[0])
105105
};
106106

107107
assert_eq!(get_pid()?, get_pid()?);
@@ -113,33 +113,6 @@ fn pg_backend_pid(_req: Request) -> Result<Response> {
113113
.body(Some(response.into()))?)
114114
}
115115

116-
fn as_owned_string(value: &pg::DbValue) -> anyhow::Result<String> {
117-
match value {
118-
pg::DbValue::Str(s) => Ok(s.to_owned()),
119-
_ => Err(anyhow!("Expected string from database but got {:?}", value)),
120-
}
121-
}
122-
123-
fn as_int(value: &pg::DbValue) -> anyhow::Result<i32> {
124-
match value {
125-
pg::DbValue::Int32(n) => Ok(*n),
126-
_ => Err(anyhow!(
127-
"Expected integer from database but got {:?}",
128-
value
129-
)),
130-
}
131-
}
132-
133-
fn as_bigint(value: &pg::DbValue) -> anyhow::Result<i64> {
134-
match value {
135-
pg::DbValue::Int64(n) => Ok(*n),
136-
_ => Err(anyhow!(
137-
"Expected integer from database but got {:?}",
138-
value
139-
)),
140-
}
141-
}
142-
143116
fn format_col(column: &pg::Column) -> String {
144117
format!("{}:{:?}", column.name, column.data_type)
145118
}

0 commit comments

Comments
 (0)