Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions examples/postgres-v4/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#![allow(dead_code)]
use anyhow::Result;
use http::{Request, Response};
use spin_sdk::{http_component, pg3, pg3::Decode};
use spin_sdk::{http_component, pg4};

// The environment variable set in `spin.toml` that points to the
// address of the Pg server that the component will write to
Expand All @@ -10,7 +10,7 @@ const DB_URL_ENV: &str = "DB_URL";
#[http_component]
fn process(req: Request<()>) -> Result<Response<String>> {
let address = std::env::var(DB_URL_ENV)?;
let conn = pg3::Connection::open(&address)?;
let conn = pg4::Connection::open(&address)?;

let year_header = req
.headers()
Expand All @@ -31,10 +31,9 @@ fn process(req: Request<()>) -> Result<Response<String>> {
"it was anarchy".to_owned()
} else {
let ruler_names = rulers
.rows
.into_iter()
.map(|r| Decode::decode(&r[0]))
.collect::<Result<Vec<String>, _>>()?;
.rows()
.map(|r| r.get::<String>("name").unwrap())
.collect::<Vec<_>>();
ruler_names.join(" and ")
};

Expand Down
61 changes: 61 additions & 0 deletions src/pg4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,67 @@ pub use super::wit::pg4::Connection;
/// ```
pub use super::wit::pg4::RowSet;

impl RowSet {
/// Get all the rows for this query result
pub fn rows(&self) -> impl Iterator<Item = Row<'_>> {
self.rows.iter().map(|r| Row {
columns: self.columns.as_slice(),
result: r,
})
}
}

/// A database row result.
///
/// There are two representations of a SQLite row in the SDK. This type is useful for
/// addressing elements by column name, and is obtained from the [RowSet::rows()] function.
/// The [DbValue] vector representation is obtained from the [field@RowSet::rows] field, and provides
/// index-based lookup or low-level access to row values via a vector.
pub struct Row<'a> {
columns: &'a [super::wit::pg4::Column],
result: &'a [DbValue],
}

impl Row<'_> {
/// Get a value by its column name. The value is converted to the target type as per the
/// conversion table shown in the module documentation.
///
/// This function returns None for both no such column _and_ failed conversion. You should use
/// it only if you do not need to address errors (that is, if you know that conversion should
/// never fail). If your code does not know the type in advance, use the raw [field@RowSet::rows] vector
/// instead of the `Row` wrapper to access the underlying [DbValue] enum: this will allow you to
/// determine the type and process it accordingly.
///
/// Additionally, this function performs a name lookup each time it is called. If you are iterating
/// over a large number of rows, it's more efficient to use column indexes, either calculated or
/// statically known from the column order in the SQL.
///
/// # Examples
///
/// ```no_run
/// use spin_sdk::pg4::{Connection, DbValue};
///
/// # fn main() -> anyhow::Result<()> {
/// # let user_id = 0;
/// let db = Connection::open("host=localhost user=postgres password=my_password dbname=mydb")?;
/// let query_result = db.query(
/// "SELECT * FROM users WHERE id = $1",
/// &[user_id.into()]
/// )?;
/// let user_row = query_result.rows().next().unwrap();
///
/// let name = user_row.get::<String>("name").unwrap();
/// let age = user_row.get::<i16>("age").unwrap();
/// # Ok(())
/// # }
/// ```
pub fn get<T: Decode>(&self, column: &str) -> Option<T> {
let i = self.columns.iter().position(|c| c.name == column)?;
let db_value = self.result.get(i)?;
Decode::decode(db_value).ok()
}
}

#[doc(inline)]
pub use super::wit::pg4::{Error as PgError, *};

Expand Down