inline_sql/lib.rs
1//! Write SQL queries inside Rust functions.
2//!
3//! The `inline-sql` crate lets you annotate a function to directly write an SQL query as the function body.
4//! You can use the function parameters as placeholders in your query,
5//! and the query result will automatically be converted to the return type.
6//!
7//! See the documentation of the [`#[inline_sql]`][`inline_sql`] macro for more details and examples.
8//!
9//! Currently, only [`tokio-postgres`][`tokio_postgres`] is supported as backend.
10//!
11//! # Example: Return a [`Vec`] of rows.
12//! ```
13//! # #[derive(pg_mapper::TryFromRow)]
14//! # struct Pet {
15//! # name: String,
16//! # species: String,
17//! # }
18//! use inline_sql::inline_sql;
19//!
20//! #[inline_sql]
21//! async fn get_pets_by_species(
22//! client: &tokio_postgres::Client,
23//! species: &str,
24//! ) -> Result<Vec<Pet>, tokio_postgres::Error> {
25//! query!(SELECT * FROM pets WHERE species = $species)
26//! }
27//! ```
28//!
29//! # Planned features:
30//! * Support for more backends, including synchronous backends.
31//! * Parsing the function arguments to determine the name of the `client` object.
32//! * Support for queries that return exactly one row or an error.
33//! * More attribute arguments to allow:
34//! * Specifying the query type instead of deducing it from the return type.
35//! * Changing how the `client` is obtained in the generated code (for example, from a member of `self`).
36
37#![warn(missing_docs)]
38#![warn(clippy::missing_docs_in_private_items)]
39
40
41/// Mark a function that executes an SQL query.
42///
43/// The function body must follow the form
44/// `query! { ... }` or `query!(...)`.
45///
46/// The return type of the function determines the behavior of the function.
47/// There are a few options for the return type:
48/// * [`Result`]`<(), E>`: Execute the query without returning anything. Errors are still reported.
49/// * [`Result`]`<`[`u64`]`, E>`: Execute the query and return the number of affected rows.
50/// * [`Result`]`<`[`Vec`]`<T>, E>`: Execute the query and return the rows as a vector.
51/// * [`Result`]`<`[`Option`]`<T>, E>`: Execute the query and return a single optional row.
52/// * [`Result`]`<`[`RowStream`][`tokio_postgres::RowStream`]`, E>`: Execute the query and return a [`RowStream`][`tokio_postgres::RowStream`].
53///
54/// The row type `T` must implement [`TryFrom<`][TryFrom][`tokio_postgres::Row`]`>`.
55/// The [`TryFrom::Error`] type must implement [`Into<E>`].
56///
57/// The error type `E` must implement [`From<`][From][`tokio_postgres::Error`]>`.
58///
59/// For functions that return a `Result<Option<T>, E>`, an error is reported if the query returned more than one row.
60///
61/// You can generally not use a type alias in the return type of the function.
62/// The proc macro can not resolve the alias, and will not know which variant to generate.
63///
64/// # Macro arguments
65///
66/// The attribute macro also accepts a arguments.
67/// Multiple arguments may be specified separated by a comma.
68///
69///
70/// ##### `#[inline_sql(client = ...)]`
71///
72/// Specify the SQL client object to use.
73/// The argument value must be an expression that gives a [`tokio_postgres::Client`], preferably by reference.
74///
75/// #### `#[inline_sql(map_row = ...)]`
76///
77/// Specify a custom function to convert a row from the query result to the return value.
78/// The argument value must be an expression that gives a function with the signature `Fn(`[`tokio_postgres::Row`]`) -> Result<T, E>`.
79///
80/// You can specify the name of a function or a closure.
81///
82/// #### `#[inline_sql(map_err = ...)]`
83///
84/// Specify a custom function to convert the SQL error to the error from the function return type.
85/// The argument value must be an expression that gives a function with the signature `Fn(`[`tokio_postgres::Error`]`) -> E`.
86///
87/// You can specify the name of a function or a closure.
88///
89/// # Example 1: Ignore the query output.
90/// ```
91/// use inline_sql::inline_sql;
92///
93/// #[inline_sql]
94/// async fn create_pets_table(
95/// client: &tokio_postgres::Client
96/// ) -> Result<(), tokio_postgres::Error> {
97/// query! {
98/// CREATE TABLE pets (
99/// name TEXT PRIMARY KEY,
100/// species TEXT NOT NULL
101/// )
102/// }
103/// }
104/// ```
105///
106/// # Example: Return a [`Vec`] of rows.
107/// ```
108/// use inline_sql::inline_sql;
109///
110/// # #[derive(pg_mapper::TryFromRow)]
111/// # struct Pet {
112/// # name: String,
113/// # species: String,
114/// # }
115///
116/// #[inline_sql]
117/// async fn get_pets_by_species(
118/// client: &tokio_postgres::Client,
119/// species: &str,
120/// ) -> Result<Vec<Pet>, tokio_postgres::Error> {
121/// query!(SELECT * FROM pets WHERE species = #species)
122/// }
123/// ```
124///
125/// # Example: Return an [`Option`].
126/// ```
127/// use inline_sql::inline_sql;
128///
129/// # #[derive(pg_mapper::TryFromRow)]
130/// # struct Pet {
131/// # name: String,
132/// # species: String,
133/// # }
134///
135/// #[inline_sql]
136/// async fn get_pet_by_name(
137/// client: &tokio_postgres::Client,
138/// name: &str,
139/// ) -> Result<Option<Pet>, tokio_postgres::Error> {
140/// query!(SELECT * FROM pets WHERE name = #name)
141/// }
142/// ```
143///
144/// # Example: Return the number of affected rows.
145/// ```
146/// use inline_sql::inline_sql;
147///
148/// # #[derive(pg_mapper::TryFromRow)]
149/// # struct Pet {
150/// # name: String,
151/// # species: String,
152/// # }
153///
154/// #[inline_sql]
155/// async fn rename_species(
156/// client: &tokio_postgres::Client,
157/// old_species: &str,
158/// new_species: &str,
159/// ) -> Result<u64, tokio_postgres::Error> {
160/// query!(UPDATE pets SET species = #new_species WHERE species = #old_species)
161/// }
162/// ```
163pub use inline_sql_macros::inline_sql;
164
165#[doc(hidden)]
166pub mod macro_export__ {
167 pub mod prelude {
168 pub use futures::StreamExt;
169 }
170
171 pub fn convert_row<F, T, E>(fun: F, row: tokio_postgres::Row) -> Result<T, E>
172 where
173 F: Fn(tokio_postgres::Row) -> Result<T, E>
174 {
175 (fun)(row)
176 }
177}