Skip to content

Commit 2b0dbd7

Browse files
authored
Merge pull request #59 from itowlson/rustdoc-examples-moar-moar-moar
Rustdoc examples: PostgreSQL, MySQL, variables, MQTT
2 parents 00efabd + 3a8154d commit 2b0dbd7

File tree

8 files changed

+469
-51
lines changed

8 files changed

+469
-51
lines changed

src/lib.rs

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -57,61 +57,19 @@ extern "C" fn __spin_sdk_hash() {}
5757
/// Helpers for building Spin `wasi-http` components.
5858
pub mod http;
5959

60-
/// MQTT messaging.
6160
#[allow(missing_docs)]
62-
pub mod mqtt {
63-
pub use super::wit::v2::mqtt::{Connection, Error, Payload, Qos};
64-
}
61+
pub mod mqtt;
6562

66-
/// Redis storage and messaging.
6763
#[allow(missing_docs)]
68-
pub mod redis {
69-
use std::hash::{Hash, Hasher};
70-
71-
pub use super::wit::v2::redis::{Connection, Error, Payload, RedisParameter, RedisResult};
72-
73-
impl PartialEq for RedisResult {
74-
fn eq(&self, other: &Self) -> bool {
75-
use RedisResult::*;
76-
match (self, other) {
77-
(Nil, Nil) => true,
78-
(Status(a), Status(b)) => a == b,
79-
(Int64(a), Int64(b)) => a == b,
80-
(Binary(a), Binary(b)) => a == b,
81-
_ => false,
82-
}
83-
}
84-
}
85-
86-
impl Eq for RedisResult {}
87-
88-
impl Hash for RedisResult {
89-
fn hash<H: Hasher>(&self, state: &mut H) {
90-
use RedisResult::*;
91-
92-
match self {
93-
Nil => (),
94-
Status(s) => s.hash(state),
95-
Int64(v) => v.hash(state),
96-
Binary(v) => v.hash(state),
97-
}
98-
}
99-
}
100-
}
64+
pub mod redis;
10165

102-
/// Spin 2 Postgres relational database storage. Applications that do not require
103-
/// Spin 2 support should use the `pg3` module instead.
10466
pub mod pg;
10567

106-
/// Postgres relational database storage.
10768
pub mod pg3;
10869

109-
/// MySQL relational database storage.
11070
pub mod mysql;
11171

112-
#[doc(inline)]
113-
/// Component configuration variables.
114-
pub use wit::v2::variables;
72+
pub mod variables;
11573

11674
#[doc(hidden)]
11775
pub use wit_bindgen;

src/mqtt.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//! MQTT message publishing.
2+
//!
3+
//! To receive MQTT messages, use the MQTT trigger.
4+
//!
5+
//! # Examples
6+
//!
7+
//! Send an MQTT message.
8+
//!
9+
//! ```no_run
10+
//! use spin_sdk::mqtt::{Connection, Qos};
11+
//!
12+
//! # fn ensure_pet_picture(_: &[u8]) -> anyhow::Result<()> { Ok(()) }
13+
//! # fn use_mqtt(request: spin_sdk::http::Request) -> anyhow::Result<()> {
14+
//! let user = spin_sdk::variables::get("mqtt_username")?;
15+
//! let password = spin_sdk::variables::get("mqtt_password")?;
16+
//!
17+
//! let conn = Connection::open(
18+
//! "mqtt://localhost:1883?client_id=123",
19+
//! &user,
20+
//! &password,
21+
//! 30 /* seconds */
22+
//! )?;
23+
//!
24+
//! let payload = request.body().to_vec();
25+
//! ensure_pet_picture(&payload)?;
26+
//!
27+
//! conn.publish("pet-pictures", &payload, Qos::AtLeastOnce)?;
28+
//! # Ok(())
29+
//! # }
30+
//! ```
31+
32+
/// An open connection to an MQTT queue.
33+
///
34+
/// The address must be in URL form, and must include a `client_id`:
35+
/// `mqtt://hostname?client_id=...`
36+
///
37+
/// # Examples
38+
///
39+
/// Send an MQTT message.
40+
///
41+
/// ```no_run
42+
/// use spin_sdk::mqtt::{Connection, Qos};
43+
///
44+
/// # fn ensure_pet_picture(_: &[u8]) -> anyhow::Result<()> { Ok(()) }
45+
/// # fn use_mqtt(request: spin_sdk::http::Request) -> anyhow::Result<()> {
46+
/// let user = spin_sdk::variables::get("mqtt_username")?;
47+
/// let password = spin_sdk::variables::get("mqtt_password")?;
48+
///
49+
/// let conn = Connection::open(
50+
/// "mqtt://localhost:1883?client_id=123",
51+
/// &user,
52+
/// &password,
53+
/// 30 /* seconds */
54+
/// )?;
55+
///
56+
/// let payload = request.body().to_vec();
57+
/// ensure_pet_picture(&payload)?;
58+
///
59+
/// conn.publish("pet-pictures", &payload, Qos::AtLeastOnce)?;
60+
/// # Ok(())
61+
/// # }
62+
/// ```
63+
pub use super::wit::v2::mqtt::Connection;
64+
65+
pub use super::wit::v2::mqtt::{Error, Payload, Qos};

src/mysql.rs

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
//! Conversions between Rust, WIT and **MySQL** types.
1+
//! MySQL relational database storage.
2+
//!
3+
//! You can use the [`Decode`] trait to convert a [`DbValue`] to a
4+
//! suitable Rust type. The following table shows available conversions.
25
//!
36
//! # Types
47
//!
@@ -18,8 +21,109 @@
1821
//! | `String` | str(string) | VARCHAR, CHAR, TEXT |
1922
//! | `Vec<u8>` | binary(list\<u8\>) | VARBINARY, BINARY, BLOB |
2023
24+
/// An open connection to a MySQL database.
25+
///
26+
/// # Examples
27+
///
28+
/// Load a set of rows from a local PostgreSQL database, and iterate over them.
29+
///
30+
/// ```no_run
31+
/// use spin_sdk::mysql::{Connection, Decode, ParameterValue};
32+
///
33+
/// # fn main() -> anyhow::Result<()> {
34+
/// # let min_age = 0;
35+
/// let db = Connection::open("mysql://root:my_password@localhost/mydb")?;
36+
///
37+
/// let query_result = db.query(
38+
/// "SELECT * FROM users WHERE age < ?",
39+
/// &[ParameterValue::Int32(20)]
40+
/// )?;
41+
///
42+
/// let name_index = query_result.columns.iter().position(|c| c.name == "name").unwrap();
43+
///
44+
/// for row in &query_result.rows {
45+
/// let name = String::decode(&row[name_index])?;
46+
/// println!("Found user {name}");
47+
/// }
48+
/// # Ok(())
49+
/// # }
50+
/// ```
51+
///
52+
/// Perform an aggregate (scalar) operation over a table. The result set
53+
/// contains a single column, with a single row.
54+
///
55+
/// ```no_run
56+
/// use spin_sdk::mysql::{Connection, Decode};
57+
///
58+
/// # fn main() -> anyhow::Result<()> {
59+
/// let db = Connection::open("mysql://root:my_password@localhost/mydb")?;
60+
///
61+
/// let query_result = db.query("SELECT COUNT(*) FROM users", &[])?;
62+
///
63+
/// assert_eq!(1, query_result.columns.len());
64+
/// assert_eq!("COUNT(*)", query_result.columns[0].name);
65+
/// assert_eq!(1, query_result.rows.len());
66+
///
67+
/// let count = i64::decode(&query_result.rows[0][0])?;
68+
/// # Ok(())
69+
/// # }
70+
/// ```
71+
///
72+
/// Delete rows from a MySQL table. This uses [Connection::execute()]
73+
/// instead of the `query` method.
74+
///
75+
/// ```no_run
76+
/// use spin_sdk::mysql::{Connection, ParameterValue};
77+
///
78+
/// # fn main() -> anyhow::Result<()> {
79+
/// let db = Connection::open("mysql://root:my_password@localhost/mydb")?;
80+
///
81+
/// let rows_affected = db.execute(
82+
/// "DELETE FROM users WHERE name = ?",
83+
/// &[ParameterValue::Str("Baldrick".to_owned())]
84+
/// )?;
85+
/// # Ok(())
86+
/// # }
87+
/// ```
88+
#[doc(inline)]
89+
pub use super::wit::v2::mysql::Connection;
90+
91+
/// The result of a database query.
92+
///
93+
/// # Examples
94+
///
95+
/// Load a set of rows from a local PostgreSQL database, and iterate over them
96+
/// selecting one field from each. The columns collection allows you to find
97+
/// column indexes for column names; you can bypass this lookup if you name
98+
/// specific columns in the query.
99+
///
100+
/// ```no_run
101+
/// use spin_sdk::mysql::{Connection, Decode, ParameterValue};
102+
///
103+
/// # fn main() -> anyhow::Result<()> {
104+
/// # let min_age = 0;
105+
/// let db = Connection::open("mysql://root:my_password@localhost/mydb")?;
106+
///
107+
/// let query_result = db.query(
108+
/// "SELECT * FROM users WHERE age >= ?",
109+
/// &[ParameterValue::Int32(min_age)]
110+
/// )?;
111+
///
112+
/// let name_index = query_result.columns.iter().position(|c| c.name == "name").unwrap();
113+
///
114+
/// for row in &query_result.rows {
115+
/// let name = String::decode(&row[name_index])?;
116+
/// println!("Found user {name}");
117+
/// }
118+
/// # Ok(())
119+
/// # }
120+
/// ```
21121
#[doc(inline)]
22-
pub use super::wit::v2::mysql::{Connection, Error as MysqlError};
122+
pub use super::wit::v2::mysql::RowSet;
123+
124+
#[doc(inline)]
125+
pub use super::wit::v2::mysql::Error as MysqlError;
126+
23127
#[doc(inline)]
24128
pub use super::wit::v2::rdbms_types::*;
25129

src/pg.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
//! Spin 2 Postgres relational database storage. Applications that do not require
2+
//! Spin 2 support should use the [`pg3`](crate::pg3) module instead.
3+
//!
14
//! Conversions between Rust, WIT and **Postgres** types.
25
//!
36
//! # Types

src/pg3.rs

Lines changed: 107 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
//! Conversions between Rust, WIT and **Postgres** types.
1+
//! Postgres relational database storage.
2+
//!
3+
//! You can use the [`into()`](std::convert::Into) method to convert
4+
//! a Rust value into a [`ParameterValue`]. You can use the
5+
//! [`Decode`] trait to convert a [`DbValue`] to a suitable Rust type.
6+
//! The following table shows available conversions.
27
//!
38
//! # Types
49
//!
@@ -17,18 +22,117 @@
1722
//! | `chrono::NaiveDateTime` | datetime(tuple<s32, u8, u8, u8, u8, u8, u32>) | TIMESTAMP |
1823
//! | `chrono::Duration` | timestamp(s64) | BIGINT |
1924
25+
/// An open connection to a PostgreSQL database.
26+
///
27+
/// # Examples
28+
///
29+
/// Load a set of rows from a local PostgreSQL database, and iterate over them.
30+
///
31+
/// ```no_run
32+
/// use spin_sdk::pg3::{Connection, Decode};
33+
///
34+
/// # fn main() -> anyhow::Result<()> {
35+
/// # let min_age = 0;
36+
/// let db = Connection::open("host=localhost user=postgres password=my_password dbname=mydb")?;
37+
///
38+
/// let query_result = db.query(
39+
/// "SELECT * FROM users WHERE age >= $1",
40+
/// &[min_age.into()]
41+
/// )?;
42+
///
43+
/// let name_index = query_result.columns.iter().position(|c| c.name == "name").unwrap();
44+
///
45+
/// for row in &query_result.rows {
46+
/// let name = String::decode(&row[name_index])?;
47+
/// println!("Found user {name}");
48+
/// }
49+
/// # Ok(())
50+
/// # }
51+
/// ```
52+
///
53+
/// Perform an aggregate (scalar) operation over a table. The result set
54+
/// contains a single column, with a single row.
55+
///
56+
/// ```no_run
57+
/// use spin_sdk::pg3::{Connection, Decode};
58+
///
59+
/// # fn main() -> anyhow::Result<()> {
60+
/// let db = Connection::open("host=localhost user=postgres password=my_password dbname=mydb")?;
61+
///
62+
/// let query_result = db.query("SELECT COUNT(*) FROM users", &[])?;
63+
///
64+
/// assert_eq!(1, query_result.columns.len());
65+
/// assert_eq!("count", query_result.columns[0].name);
66+
/// assert_eq!(1, query_result.rows.len());
67+
///
68+
/// let count = i64::decode(&query_result.rows[0][0])?;
69+
/// # Ok(())
70+
/// # }
71+
/// ```
72+
///
73+
/// Delete rows from a PostgreSQL table. This uses [Connection::execute()]
74+
/// instead of the `query` method.
75+
///
76+
/// ```no_run
77+
/// use spin_sdk::pg3::Connection;
78+
///
79+
/// # fn main() -> anyhow::Result<()> {
80+
/// let db = Connection::open("host=localhost user=postgres password=my_password dbname=mydb")?;
81+
///
82+
/// let rows_affected = db.execute(
83+
/// "DELETE FROM users WHERE name = $1",
84+
/// &["Baldrick".to_owned().into()]
85+
/// )?;
86+
/// # Ok(())
87+
/// # }
88+
/// ```
89+
#[doc(inline)]
90+
pub use super::wit::pg3::Connection;
91+
92+
/// The result of a database query.
93+
///
94+
/// # Examples
95+
///
96+
/// Load a set of rows from a local PostgreSQL database, and iterate over them
97+
/// selecting one field from each. The columns collection allows you to find
98+
/// column indexes for column names; you can bypass this lookup if you name
99+
/// specific columns in the query.
100+
///
101+
/// ```no_run
102+
/// use spin_sdk::pg3::{Connection, Decode};
103+
///
104+
/// # fn main() -> anyhow::Result<()> {
105+
/// # let min_age = 0;
106+
/// let db = Connection::open("host=localhost user=postgres password=my_password dbname=mydb")?;
107+
///
108+
/// let query_result = db.query(
109+
/// "SELECT * FROM users WHERE age >= $1",
110+
/// &[min_age.into()]
111+
/// )?;
112+
///
113+
/// let name_index = query_result.columns.iter().position(|c| c.name == "name").unwrap();
114+
///
115+
/// for row in &query_result.rows {
116+
/// let name = String::decode(&row[name_index])?;
117+
/// println!("Found user {name}");
118+
/// }
119+
/// # Ok(())
120+
/// # }
121+
/// ```
122+
pub use super::wit::pg3::RowSet;
123+
20124
#[doc(inline)]
21125
pub use super::wit::pg3::{Error as PgError, *};
22126

23127
use chrono::{Datelike, Timelike};
24128

25-
/// A pg error
129+
/// A Postgres error
26130
#[derive(Debug, thiserror::Error)]
27131
pub enum Error {
28132
/// Failed to deserialize [`DbValue`]
29133
#[error("error value decoding: {0}")]
30134
Decode(String),
31-
/// Pg query failed with an error
135+
/// Postgres query failed with an error
32136
#[error(transparent)]
33137
PgError(#[from] PgError),
34138
}

0 commit comments

Comments
 (0)