sqlx_template/lib.rs
1#![allow(warnings)]
2use proc_macro::TokenStream;
3use quote::quote;
4use sqlx_template::raw;
5use syn::{
6 parse_macro_input, Attribute, Data, DeriveInput, Field, Fields, Ident, Lit, Meta,
7 MetaNameValue, NestedMeta,
8};
9
10mod sqlx_template;
11mod columns;
12mod parser;
13
14
15
16/// `InsertTemplate` is a derive macro designed to automatically generate record insert functions
17/// based on `sqlx`. This macro creates `insert` methods for the struct it is applied to, returning
18/// the number of new records added. It assumes that the columns in the database correspond to the fields in the struct.
19///
20/// # Attributes
21///
22/// `InsertTemplate` accepts the following attributes:
23/// - `table_name`: Specifies the name of the table in the database (mandatory).
24/// - `debug_slow`: Configures debug logs for the executed query:
25/// - If set to `0`: Only logs the executed query.
26/// - If set to a value greater than `0`: Only logs the query if the execution time exceeds the configured value (in milliseconds).
27/// - If not configured, no debug logs will be generated.
28/// - `auto`: Applied to fields that should be excluded from the insert statement, typically for auto-incrementing primary keys.
29///
30/// Additionally, if the feature `postgres` is enabled, the library will generate an `insert_return` function that returns the newly inserted record.
31///
32/// # Example
33///
34/// ```rust
35/// use sqlx_template::InsertTemplate;
36///
37/// #[derive(InsertTemplate, sqlx::FromRow)]
38/// #[table_name = "users"]
39/// #[debug_slow = 1000]
40/// pub struct User {
41/// #[auto]
42/// pub id: i32,
43/// pub email: String,
44/// pub password: String,
45/// }
46///
47/// // Insert a new user record
48/// let user = User { id: 0, email: "john.doe@example.com".to_string(), password: "password123".to_string() };
49/// let rows_affected = User::insert(&user, &pool).await?;
50/// println!("Rows affected: {}", rows_affected);
51///
52/// // If the `postgres` feature is enabled
53/// #[cfg(feature = "postgres")]
54/// let new_user = User.insert_return(&user, &pool).await?;
55/// println!("New user: {:?}", new_user);
56/// ```
57///
58/// In the example above:
59/// - `table_name` is set to "users", specifying the table to insert into. (mandatory).
60/// - `debug_slow` is set to 1000 milliseconds, meaning only queries taking longer than 1 second will be logged for debugging.
61/// - The `id` field is marked with `#[auto]`, indicating that it should be excluded from the insert statement, typically for auto-incrementing primary keys.
62///
63
64/// # Note
65///
66/// This macro relies on `sqlx`, so you need to add `sqlx` to your `[dependencies]` in `Cargo.toml`
67/// and properly configure the database connection before using the generated insert methods.
68///
69
70
71#[proc_macro_derive(InsertTemplate, attributes(table_name, auto, debug_slow))]
72pub fn insert_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
73 let input = syn::parse_macro_input!(input as syn::DeriveInput);
74 match sqlx_template::insert::derive_insert(input) {
75 Ok(ok) => ok,
76 Err(err) => err.to_compile_error().into(),
77 }
78 .into()
79}
80
81
82/// `UpdateTemplate` is a derive macro designed to automatically generate record update functions
83/// based on `sqlx`. This macro creates `update` methods for the struct it is applied to, reducing
84/// repetitive code and improving the readability and maintainability of your code.
85/// It assumes that the columns in the database correspond to the fields in the struct.
86///
87/// # Attributes
88///
89/// `UpdateTemplate` accepts the following attributes:
90/// - `table_name`: Specifies the name of the table in the database (mandatory).
91/// - `tp_update`: The main configuration for generating the update function, with the following sub-attributes:
92/// - `by`: List of columns that will be the update condition, will be the function's input (mandatory and non-empty).
93/// - `on`: List of columns that will be updated. If empty, all columns will be updated.
94/// - `fn_name`: The name of the generated function. If empty, the library will automatically generate a function name.
95/// - `op_lock`: The name of the column to apply optimistic locking (optional).
96/// - `returning`: if set = true, generated function will return the newly updated record (feature `postgres only`)
97/// - `debug_slow`: Configures debug logs for the executed query:
98/// - If `0`: Only logs the executed query.
99/// - If `> 0`: Only logs the query if the execution time exceeds the configured value (in milliseconds).
100/// - If not configured, no debug logs will be generated.
101/// - `debug_slow`: Configures debug logs for the executed query, with priority given to the value in `tp_update`.
102/// # Example
103///
104/// ```rust
105/// use sqlx_template::UpdateTemplate;
106///
107/// #[derive(UpdateTemplate, sqlx::FromRow)]
108/// #[table_name = "users"]
109/// #[tp_update(by = "id", op_lock = "version", fn_name = "update_user")]
110/// #[tp_update(by = "id", on = "email, password", fn_name = "update_user_password")]
111/// #[debug_slow = 1000]
112/// pub struct User {
113/// pub id: i32,
114/// pub email: String,
115/// pub password: String,
116/// pub version: i32
117/// }
118/// ```
119///
120/// In the example above:
121/// - `table_name` is set to "users", specifying the table to update.
122/// - The first `tp_update` generates a function named `update_user` to update record, using `id` as the condition and applying optimistic locking on the `version` column.
123/// - The second `tp_update` generates a function named `update_user_password` to update both `email` and `password` columns, using `id` as the condition.
124/// - `debug_slow` is set to 1000 milliseconds, meaning only queries taking longer than 1 second will be logged for debugging.
125///
126
127/// # Note
128///
129/// This macro relies on `sqlx`, so you need to add `sqlx` to your `[dependencies]` in `Cargo.toml`
130/// and properly configure the database connection before using the generated update methods.
131
132#[proc_macro_derive(UpdateTemplate, attributes(table_name, tp_update, debug_slow))]
133pub fn update_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
134 let input = syn::parse_macro_input!(input as syn::DeriveInput);
135 match sqlx_template::update::derive_update(input) {
136 Ok(ok) => ok,
137 Err(err) => err.to_compile_error().into(),
138 }
139 .into()
140}
141
142
143/// `DeleteTemplate` is a derive macro designed to automatically generate record deletion functions
144/// based on `sqlx`. This macro creates `delete` methods for the struct it is applied to, returning
145/// the number of records deleted.
146/// It assumes that the columns in the database correspond to the fields in the struct.
147///
148/// # Attributes
149///
150/// `DeleteTemplate` accepts the following attributes:
151/// - `table_name`: Specifies the name of the table in the database (mandatory).
152/// - `debug_slow`: Configures debug logs for the executed query:
153/// - If set to `0`: Only logs the executed query.
154/// - If set to a value greater than `0`: Only logs the query if the execution time exceeds the configured value (in milliseconds).
155/// - If not configured, no debug logs will be generated.
156/// - `tp_delete`: The main configuration for generating the delete function, with the following sub-attributes:
157/// - `by`: List of columns that will be the delete condition, will be the function's input (mandatory and non-empty).
158/// - `fn_name`: The name of the generated function. If empty, the library will automatically generate a function name.
159/// - `returning`: If set to true, the generated function will return the deleted record (only enabled with the `postgres` feature).
160/// - `debug_slow`: Configures debug logs for the executed query:
161/// - If set to `0`: Only logs the executed query.
162/// - If set to a value greater than `0`: Only logs the query if the execution time exceeds the configured value (in milliseconds).
163/// - If not configured, no debug logs will be generated.
164///
165/// The `debug_slow` attribute at the struct level has priority over the value in `tp_delete`.
166///
167/// # Example
168///
169/// ```rust
170/// use sqlx_template::DeleteTemplate;
171///
172/// #[derive(DeleteTemplate, sqlx::FromRow)]
173/// #[table_name = "users"]
174/// #[tp_delete(by = "id", fn_name = "delete_user", returning = true)]
175/// #[tp_delete(by = "id")]
176/// pub struct User {
177/// pub id: i32,
178/// pub email: String,
179/// pub password: String,
180/// }
181///
182/// // Delete a user record by id
183/// let user = User { id: 1, email: "john.doe@example.com".to_string(), password: "password123".to_string() };
184/// let rows_affected = User::delete_by_id(&user.id, &pool).await?;
185/// println!("Rows affected: {}", rows_affected);
186///
187/// // If the `postgres` feature is enabled and `returning` is set to true
188/// #[cfg(feature = "postgres")]
189/// let deleted_user = User::delete_user(&user.id, &pool).await?;
190/// println!("Deleted user: {:?}", deleted_user);
191/// ```
192///
193/// In the example above:
194/// - `table_name` is set to "users", specifying the table to delete from.
195/// - The first `tp_delete` generates a function named `delete_user` to delete a record based on the `id` column and return the deleted record (with the `postgres` feature enabled).
196/// - `debug_slow` is set to 1000 milliseconds, meaning only queries taking longer than 1 second will be logged for debugging.
197///
198/// # Note
199///
200/// This macro relies on `sqlx`, so you need to add `sqlx` to your `[dependencies]` in `Cargo.toml`
201/// and properly configure the database connection before using the generated delete methods.
202///
203
204#[proc_macro_derive(DeleteTemplate, attributes(table_name, tp_delete, debug_slow))]
205pub fn delete_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
206 let input = syn::parse_macro_input!(input as syn::DeriveInput);
207 match sqlx_template::delete::derive_delete(input) {
208 Ok(ok) => ok,
209 Err(err) => err.to_compile_error().into(),
210 }
211 .into()
212}
213
214
215/// `SelectTemplate` is a derive macro designed to automatically generate record retrieval functions
216/// based on `sqlx`. This macro creates various `query` methods for the struct it is applied to,
217/// returning records from the database, assuming that the columns in the database correspond to the fields in the struct.
218///
219/// # Attributes
220///
221/// `SelectTemplate` accepts the following attributes:
222/// - `table_name`: Specifies the name of the table in the database (mandatory).
223/// - `debug_slow`: Configures debug logs for the executed query:
224/// - If set to `0`: Only logs the executed query.
225/// - If set to a value greater than `0`: Only logs the query if the execution time exceeds the configured value (in milliseconds).
226/// - If not configured, no debug logs will be generated.
227/// - `tp_select_all`: Generates a function that returns all records as a `Vec<T>`. It has the following sub-attributes:
228/// - `by`: List of columns for the `WHERE` condition, used as function input (can be empty).
229/// - `fn_name`: The name of the generated function. If empty, the library will automatically generate a function name.
230/// - `order`: Adds an `ORDER BY` clause based on the specified columns and order (supports `asc|desc`, default is `asc`).
231/// - `debug_slow`: Configures debug logs for the executed query:
232/// - If set to `0`: Only logs the executed query.
233/// - If set to a value greater than `0`: Only logs the query if the execution time exceeds the configured value (in milliseconds).
234/// - If not configured, no debug logs will be generated.
235/// - `tp_select_one`: Similar to `tp_select_all`, but returns a single record as `Option<T>`.
236/// - `tp_select_stream`: Similar to `tp_select_all`, but returns an `impl Stream<Item = T>`.
237/// - `tp_select_count`: Similar to `tp_select_all`, but returns the count of records as `i64`.
238/// - `tp_select_page`: Similar to `tp_select_all`, but accepts `offset` and `limit` as inputs, and returns a tuple of all records and the total count.
239///
240/// The `debug_slow` attribute at the struct level has priority over the value in `tp_select_*`.
241///
242/// Additionally, the library will automatically generate the following default functions when `SelectTemplate` is derived:
243/// - `find_all`: Returns all records in the table.
244/// - `count_all`: Counts all records in the table.
245/// - `find_page_all`: Returns all records and the total count in the table based on pagination parameters.
246///
247/// # Example
248///
249/// ```rust
250/// use sqlx_template::SelectTemplate;
251/// use sqlx::FromRow;
252///
253/// #[derive(SelectTemplate, FromRow)]
254/// #[table_name = "users"]
255/// #[tp_select_one(by = "id", fn_name = "find_user_by_id")]
256/// #[tp_select_all(by = "id, email", order = "id desc", fn_name = "find_all_users")]
257/// #[tp_select_count(by = "id", fn_name = "count_users_by_id")]
258/// #[tp_select_page(by = "id", fn_name = "find_users_page")]
259/// #[tp_select_stream(by = "email", order = "id desc, email", fn_name = "stream_users_by_email", debug_slow = -1)]
260/// #[debug_slow = 1000]
261/// pub struct User {
262/// #[auto]
263/// pub id: i32,
264/// pub email: String,
265/// pub password: String,
266/// }
267///
268/// // Example usage:
269/// // Find user by id
270/// let user = User::find_user_by_id(&pool, 1).await?;
271/// println!("Found user: {:?}", user);
272///
273/// // Find all users
274/// let users = User::find_all_users(&pool, Some("example@example.com")).await?;
275/// println!("All users: {:?}", users);
276///
277/// // Count users by id
278/// let user_count = User::count_users_by_id(&pool, Some(1)).await?;
279/// println!("User count: {}", user_count);
280///
281/// // Find users with pagination
282/// let (users, total_count) = User::find_users_page(&pool, 0, 10).await?;
283/// println!("Users: {:?}, Total count: {}", users, total_count);
284///
285/// // Stream users by email
286/// let mut user_stream = User::stream_users_by_email(&pool, "example@example.com").await?;
287/// while let Some(user) = user_stream.next().await {
288/// println!("Streamed user: {:?}", user);
289/// }
290/// ```
291///
292/// In the example above:
293/// - `table_name` is set to "users", specifying the table to query from.
294/// - `tp_select_one` generates a function named `find_user_by_id` to find a user by `id`.
295/// - `tp_select_all` generates a function named `find_all_users` to find all users by `id` and `email`, ordered by `id` in descending order.
296/// - `tp_select_count` generates a function named `count_users_by_id` to count users by `id`.
297/// - `tp_select_page` generates a function named `find_users_page` to find users with pagination by `id`.
298/// - `tp_select_stream` generates a function named `stream_users_by_email` to stream users by `email`, ordered by `id` in descending order and then by `email`, with debug logging if the query execution time exceeds the configured value.
299///
300
301///
302/// # Note
303///
304/// This macro relies on `sqlx`, so you need to add `sqlx` to your `[dependencies]` in `Cargo.toml`
305/// and properly configure the database connection before using the generated query methods.
306///
307
308#[proc_macro_derive(SelectTemplate, attributes(table_name, debug_slow, tp_select_all, tp_select_one, tp_select_page, tp_select_stream, tp_select_count))]
309pub fn select_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
310 let input = syn::parse_macro_input!(input as syn::DeriveInput);
311 match sqlx_template::select::derive_select(input) {
312 Ok(ok) => ok,
313 Err(err) => err.to_compile_error().into(),
314 }
315 .into()
316}
317
318#[proc_macro_derive(Columns)]
319pub fn columns_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
320 let input = syn::parse_macro_input!(input as syn::DeriveInput);
321 match columns::derive(input) {
322 Ok(ok) => ok,
323 Err(err) => err.to_compile_error().into(),
324 }
325 .into()
326}
327
328
329
330/// The `TableName` derive macro automatically generates a `table_name` function
331/// for a struct, returning the value specified in the `table_name` attribute.
332///
333/// # Syntax
334///
335/// ```rust
336/// #[derive(TableName)]
337/// #[table_name = "<table_name>"]
338/// pub struct <StructName> { ... }
339/// ```
340///
341/// # Attributes
342///
343/// - `table_name`: Specifies the name of the table as a string (e.g., `#[table_name = "users"]`).
344///
345/// # Function Signature
346///
347/// The macro generates a const function named table_name() which returns a `&'static str` containing the table name
348///
349/// # Example Usage
350///
351/// ```rust
352/// #[derive(TableName)]
353/// #[table_name = "users"]
354/// pub struct User {
355/// pub id: i32,
356/// pub name: String,
357/// pub age: i32,
358/// }
359///
360///
361/// fn main() {
362/// assert_eq!(User::table_name(), "users");
363/// }
364#[proc_macro_derive(TableName, attributes(table_name))]
365pub fn table_name_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
366 let input = syn::parse_macro_input!(input as syn::DeriveInput);
367 match sqlx_template::table_name_derive(input) {
368 Ok(ok) => ok,
369 Err(err) => err.to_compile_error().into(),
370 }
371 .into()
372}
373
374/// The `multi_query` procedural macro transforms a series of SQL queries with named parameters into
375/// an asynchronous function that interacts with the database. It provides various
376/// features, including debugging options, and is designed to handle multiple SQL statements with no return value (`void`).
377///
378/// # Syntax
379///
380/// ```rust
381/// #[multi_query(
382/// sql = "<query>" | file = "<path to file query>" | "<query>",
383/// debug = <integer>
384/// )]
385/// pub async fn <function_name>(<parameters>) {}
386/// ```
387///
388/// # Attributes
389///
390/// - `sql`: Specifies the SQL queries to be executed. This can be:
391/// - A raw SQL query as a string (e.g., `sql = "BEGIN; UPDATE user SET age = :age WHERE name = :name; COMMIT;"`).
392/// - A path to a file containing the SQL queries (e.g., `file = "path/to/queries.sql"`).
393/// - The queries directly as a string without the `sql` or `file` keyword.
394///
395/// **Constraints:**
396/// - The queries can contain multiple SQL statements.
397/// - Named parameters (if exist) must be in the format `:<param_name>` and must correspond to the function's parameters.
398///
399/// - `debug`: Controls the debug behavior of the macro. It can be:
400/// - An integer value. If not provided, the default is no debugging.
401/// - `0`: Prints the queries before execution.
402/// - Greater than `0`: Prints the queries and execution time if it exceeds the specified number of milliseconds.
403///
404/// # Function Signature
405///
406/// The macro generates an asynchronous function with the following characteristics:
407/// - The function signature remains unchanged (e.g., `pub async fn <function_name>`).
408/// - The function parameters are preserved in their original order.
409/// - An additional parameter for the database connection is required.
410///
411/// # Return Types
412///
413/// The macro only supports the void return type:
414///
415/// - **Void:**
416/// - : Returns nothing.
417///
418/// # Example Usage
419///
420/// ```rust
421/// #[multi_query(
422/// sql = "BEGIN; UPDATE user SET age = :age WHERE name = :name; DELETE FROM session WHERE user_name = :name; COMMIT;",
423/// debug = 100
424/// )]
425/// pub async fn update_user_and_clear_sessions(name: &str, age: i32) {}
426///
427/// #[multi_query(
428/// sql = "INSERT INTO user (name, age) VALUES (:name, :age); INSERT INTO log (user_name, action) VALUES (:name, 'created')",
429/// debug = 0
430/// )]
431/// pub async fn insert_user_with_log(name: &str, age: i32) {}
432/// ```
433///
434
435
436#[proc_macro_attribute]
437pub fn multi_query(args: TokenStream, item: TokenStream) -> proc_macro::TokenStream {
438 let input = syn::parse_macro_input!(item as syn::ItemFn);
439 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
440 match raw::multi_query_derive(input, args, None) {
441 Ok(ok) => ok,
442 Err(err) => err.to_compile_error().into(),
443 }
444 .into()
445}
446
447
448/// The `query` procedural macro transforms an SQL query with named parameters into
449/// an asynchronous function that interacts with the database. It provides various
450/// features, including debugging options and support for multiple return types.
451///
452/// # Syntax
453///
454/// ```rust
455/// #[query(
456/// sql = "<query>" | file = "<path to file query>" | "<query>",
457/// debug = <integer>
458/// )]
459/// pub async fn <function_name>(<parameters>) -> <return_type> {}
460/// ```
461///
462/// # Attributes
463///
464/// - `sql`: Specifies the SQL query to be executed. This can be:
465/// - A raw SQL query as a string (e.g., `sql = "SELECT * FROM user WHERE (name = :name and age = :age) OR name LIKE '%:name%'"`).
466/// - A path to a file containing the SQL query (e.g., `file = "path/to/query.sql"`).
467/// - The query directly as a string without the `sql` or `file` keyword.
468///
469/// **Constraints:**
470/// - The query must contain a single SQL statement.
471/// - Named parameters (if exist) must be in the format `:<param_name>` and must correspond to the function's parameters.
472///
473/// - `debug`: Controls the debug behavior of the macro. It can be:
474/// - An integer value. If not provided, the default is no debugging.
475/// - `0`: Prints the query before execution.
476/// - Greater than `0`: Prints the query and execution time if it exceeds the specified number of milliseconds.
477///
478/// # Function Signature
479///
480/// The macro generates an asynchronous function with the following characteristics:
481/// - The function signature remains unchanged (e.g., `pub async fn <function_name>`).
482/// - The function parameters are preserved in their original order.
483/// - An additional parameter for the database connection is required.
484///
485/// # Return Types
486///
487/// The macro supports various return types based on the SQL query:
488///
489/// - **Single Record:**
490/// - `T`: Returns a single record, which must be present. If no record is found, an error is returned.
491/// - `Option<T>`: Returns a single record if present, or `None` if no record is found.
492///
493/// - **Multiple Records:**
494/// - `Vec<T>`: Returns all matching records as a vector.
495///
496/// - **Asynchronous Stream:**
497/// - `Stream<T>`: Returns an asynchronous stream of records.
498///
499/// - **Paged Records:**
500/// - `Page<T>`: Returns paginated results. Requires an additional parameter for pagination (e.g., `impl Into<(i64, i32, bool)>`). The function returns a tuple `(Vec<T>, Option<i64>)`, where the vector contains the paginated records, and the optional value represents the total number of records if requested.
501///
502/// - **Scalar Value:**
503/// - `Scalar<T>`: Returns a single scalar value from the query.
504///
505/// - **Affected Rows:**
506/// - `RowAffected`: Returns the number of affected rows.
507///
508/// - **Void:**
509/// - : Returns nothing.
510///
511/// # Example Usage
512///
513/// ```rust
514/// #[query(
515/// sql = "SELECT * FROM user WHERE (name = :name and age = :age) OR name LIKE '%:name%'",
516/// debug = 100
517/// )]
518/// pub async fn query_user_info(name: &str, age: i32) -> Vec<UserInfo> {}
519///
520/// #[query(
521/// sql = "INSERT INTO user (name, age) VALUES (:name, :age)",
522/// debug = 0
523/// )]
524/// pub async fn insert_user(name: &str, age: i32) -> RowAffected {}
525///
526/// #[query("DELETE FROM user WHERE name = :name")]
527/// pub async fn delete_user(name: &str) {}
528/// ```
529///
530
531#[proc_macro_attribute]
532pub fn query(args: TokenStream, item: TokenStream) -> proc_macro::TokenStream {
533 let input = syn::parse_macro_input!(item as syn::ItemFn);
534 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
535 match raw::query_derive(input, args, None) {
536 Ok(ok) => ok,
537 Err(err) => err.to_compile_error().into(),
538 }
539 .into()
540}
541
542
543
544/// The `select` procedural macro transforms a SQL query with named parameters into
545/// an asynchronous function that interacts with the database. It provides various
546/// features, including debugging options and support for multiple return types.
547///
548/// # Syntax
549///
550/// ```rust
551/// #[select(
552/// sql = "<query>" | file = "<path to file query>" | "<query>",
553/// debug = <integer>
554/// )]
555/// pub async fn <function_name>(<parameters>) -> <return_type> {}
556/// ```
557///
558/// # Attributes
559///
560/// - `sql`: Specifies the SQL query to be executed. This can be:
561/// - A raw SQL query as a string (e.g., `sql = "SELECT * FROM user WHERE (name = :name and age = :age) OR name LIKE '%:name%'`).
562/// - A path to a file containing the SQL query (e.g., `file = "path/to/query.sql"`).
563/// - The query directly as a string without the `sql` or `file` keyword.
564///
565/// **Constraints:**
566/// - The query must contain a single SQL SELECT statement.
567/// - Named parameters (if exist) must be in the format `:<param_name>` and must correspond to the function's parameters.
568///
569/// - `debug`: Controls the debug behavior of the macro. It can be:
570/// - An integer value. If not provided, the default is no debugging.
571/// - `0`: Prints the query before execution.
572/// - Greater than `0`: Prints the query and execution time if it exceeds the specified number of milliseconds.
573///
574/// # Function Signature
575///
576/// The macro generates an asynchronous function with the following characteristics:
577/// - The function signature remains unchanged (e.g., `pub async fn <function_name>`).
578/// - The function parameters are preserved in their original order.
579/// - An additional parameter for the database connection is required.
580///
581/// # Return Types
582///
583/// The macro supports various return types based on the SQL query:
584///
585/// - **Single Record:**
586/// - `T`: Returns a single record, which must be present. If no record is found, an error is returned.
587/// - `Option<T>`: Returns a single record if present, or `None` if no record is found.
588///
589/// - **Multiple Records:**
590/// - `Vec<T>`: Returns all matching records as a vector.
591///
592/// - **Asynchronous Stream:**
593/// - `Stream<T>`: Returns an asynchronous stream of records.
594///
595/// - **Paged Records:**
596/// - `Page<T>`: Returns paginated results. Requires an additional parameter for pagination (e.g., `impl Into<(i64, i32, bool)>`). The function returns a tuple `(Vec<T>, Option<i64>)`, where the vector contains the paginated records, and the optional value represents the total number of records if requested.
597///
598/// - **Scalar Value:**
599/// - `Scalar<T>`: Returns a single scalar value from the query.
600///
601/// - **Affected Rows:**
602/// - `RowAffected`: Returns the number of affected rows.
603///
604/// - **Void:**
605/// - : Returns nothing.
606/// # Example Usage
607///
608/// ```rust
609/// #[select(
610/// sql = "
611/// SELECT *
612/// FROM user
613/// WHERE (name = :name and age = :age) OR name LIKE '%:name%'
614/// ",
615/// debug = 100
616/// )]
617/// pub async fn query_user_info(name: &str, age: i32) -> Vec<UserInfo> {}
618
619#[proc_macro_attribute]
620pub fn select(args: TokenStream, item: TokenStream) -> proc_macro::TokenStream {
621 let input = syn::parse_macro_input!(item as syn::ItemFn);
622 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
623 match raw::query_derive(input, args, Some(parser::Mode::Select)) {
624 Ok(ok) => ok,
625 Err(err) => err.to_compile_error().into(),
626 }
627 .into()
628}
629
630
631/// The `update` procedural macro transforms an SQL `UPDATE` query with named parameters into
632/// an asynchronous function that interacts with the database. It provides various
633/// features, including debugging options and support for returning the number of affected rows.
634///
635/// # Syntax
636///
637/// ```rust
638/// #[update(
639/// sql = "<query>" | file = "<path to file query>" | "<query>",
640/// debug = <integer>
641/// )]
642/// pub async fn <function_name>(<parameters>) -> <return_type> {}
643/// ```
644///
645/// # Attributes
646///
647/// - `sql`: Specifies the SQL `UPDATE` query to be executed. This can be:
648/// - A raw SQL query as a string (e.g., `sql = "UPDATE user SET age = :age WHERE name = :name"`).
649/// - A path to a file containing the SQL query (e.g., `file = "path/to/query.sql"`).
650/// - The query directly as a string without the `sql` or `file` keyword.
651///
652/// **Constraints:**
653/// - The query must be a single SQL `UPDATE` statement.
654/// - Named parameters (if exist) must be in the format `:<param_name>` and must correspond to the function's parameters.
655///
656/// - `debug`: Controls the debug behavior of the macro. It can be:
657/// - An integer value. If not provided, the default is no debugging.
658/// - `0`: Prints the query before execution.
659/// - Greater than `0`: Prints the query and execution time if it exceeds the specified number of milliseconds.
660///
661/// # Function Signature
662///
663/// The macro generates an asynchronous function with the following characteristics:
664/// - The function signature remains unchanged (e.g., `pub async fn <function_name>`).
665/// - The function parameters are preserved in their original order.
666/// - An additional parameter for the database connection is required.
667///
668/// # Return Types
669///
670/// The macro supports the following return type based on the SQL query:
671///
672/// - **Single Record:**
673/// - `T`: Returns a single record, which must be present. If no record is found, an error is returned.
674/// - `Option<T>`: Returns a single record if present, or `None` if no record is found.
675///
676/// - **Multiple Records:**
677/// - `Vec<T>`: Returns all matching records as a vector.
678///
679/// - **Asynchronous Stream:**
680/// - `Stream<T>`: Returns an asynchronous stream of records.
681///
682/// - **Paged Records:**
683/// - `Page<T>`: Returns paginated results. Requires an additional parameter for pagination (e.g., `impl Into<(i64, i32, bool)>`). The function returns a tuple `(Vec<T>, Option<i64>)`, where the vector contains the paginated records, and the optional value represents the total number of records if requested.
684///
685/// - **Scalar Value:**
686/// - `Scalar<T>`: Returns a single scalar value from the query.
687///
688/// - **Affected Rows:**
689/// - `RowAffected`: Returns the number of affected rows.
690///
691/// - **Void:**
692/// - : Returns nothing.
693///
694/// # Example Usage
695///
696/// ```rust
697/// #[update(
698/// sql = "UPDATE user SET age = :age WHERE name = :name",
699/// debug = 100
700/// )]
701/// pub async fn update_user_age(name: &str, age: i32) -> RowAffected {}
702/// ```
703///
704
705
706#[proc_macro_attribute]
707pub fn update(args: TokenStream, item: TokenStream) -> proc_macro::TokenStream {
708 let input = syn::parse_macro_input!(item as syn::ItemFn);
709 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
710 match raw::query_derive(input, args, Some(parser::Mode::Update)) {
711 Ok(ok) => ok,
712 Err(err) => err.to_compile_error().into(),
713 }
714 .into()
715}
716
717
718/// The `insert` procedural macro transforms an SQL `INSERT` query with named parameters into
719/// an asynchronous function that interacts with the database. It provides various
720/// features, including debugging options and support for returning the number of affected rows
721/// or no return value (`void`).
722///
723/// # Syntax
724///
725/// ```rust
726/// #[insert(
727/// sql = "<query>" | file = "<path to file query>" | "<query>",
728/// debug = <integer>
729/// )]
730/// pub async fn <function_name>(<parameters>) -> <return_type> {}
731/// ```
732///
733/// # Attributes
734///
735/// - `sql`: Specifies the SQL `INSERT` query to be executed. This can be:
736/// - A raw SQL query as a string (e.g., `sql = "INSERT INTO user (name, age) VALUES (:name, :age)"`).
737/// - A path to a file containing the SQL query (e.g., `file = "path/to/query.sql"`).
738/// - The query directly as a string without the `sql` or `file` keyword.
739///
740/// **Constraints:**
741/// - The query must be a single SQL `INSERT` statement.
742/// - Named parameters (if exist) must be in the format `:<param_name>` and must correspond to the function's parameters.
743///
744/// - `debug`: Controls the debug behavior of the macro. It can be:
745/// - An integer value. If not provided, the default is no debugging.
746/// - `0`: Prints the query before execution.
747/// - Greater than `0`: Prints the query and execution time if it exceeds the specified number of milliseconds.
748///
749/// # Function Signature
750///
751/// The macro generates an asynchronous function with the following characteristics:
752/// - The function signature remains unchanged (e.g., `pub async fn <function_name>`).
753/// - The function parameters are preserved in their original order.
754/// - An additional parameter for the database connection is required.
755///
756/// # Return Types
757///
758/// The macro supports the following return type based on the SQL query:
759///
760/// - **Single Record:**
761/// - `T`: Returns a single record, which must be present. If no record is found, an error is returned.
762/// - `Option<T>`: Returns a single record if present, or `None` if no record is found.
763///
764/// - **Multiple Records:**
765/// - `Vec<T>`: Returns all matching records as a vector.
766///
767/// - **Asynchronous Stream:**
768/// - `Stream<T>`: Returns an asynchronous stream of records.
769///
770/// - **Paged Records:**
771/// - `Page<T>`: Returns paginated results. Requires an additional parameter for pagination (e.g., `impl Into<(i64, i32, bool)>`). The function returns a tuple `(Vec<T>, Option<i64>)`, where the vector contains the paginated records, and the optional value represents the total number of records if requested.
772///
773/// - **Scalar Value:**
774/// - `Scalar<T>`: Returns a single scalar value from the query.
775///
776/// - **Affected Rows:**
777/// - `RowAffected`: Returns the number of affected rows.
778///
779/// - **Void:**
780/// - : Returns nothing.
781///
782/// # Example Usage
783///
784/// ```rust
785/// #[insert(
786/// sql = "INSERT INTO user (name, age) VALUES (:name, :age)",
787/// debug = 100
788/// )]
789/// pub async fn insert_user(name: &str, age: i32) -> RowAffected {}
790///
791/// #[insert("INSERT INTO user (name, age) VALUES (:name, :age)")]
792/// pub async fn insert_user_no_return(name: &str, age: i32) {}
793/// ```
794///
795
796
797#[proc_macro_attribute]
798pub fn insert(args: TokenStream, item: TokenStream) -> proc_macro::TokenStream {
799 let input = syn::parse_macro_input!(item as syn::ItemFn);
800 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
801 match raw::query_derive(input, args, Some(parser::Mode::Insert)) {
802 Ok(ok) => ok,
803 Err(err) => err.to_compile_error().into(),
804 }
805 .into()
806}
807
808
809/// The `delete` procedural macro transforms an SQL `DELETE` query with named parameters into
810/// an asynchronous function that interacts with the database. It provides various
811/// features, including debugging options and support for returning the number of affected rows
812/// or no return value (`void`).
813///
814/// # Syntax
815///
816/// ```rust
817/// #[delete(
818/// sql = "<query>" | file = "<path to file query>" | "<query>",
819/// debug = <integer>
820/// )]
821/// pub async fn <function_name>(<parameters>) -> <return_type> {}
822/// ```
823///
824/// # Attributes
825///
826/// - `sql`: Specifies the SQL `DELETE` query to be executed. This can be:
827/// - A raw SQL query as a string (e.g., `sql = "DELETE FROM user WHERE name = :name"`).
828/// - A path to a file containing the SQL query (e.g., `file = "path/to/query.sql"`).
829/// - The query directly as a string without the `sql` or `file` keyword.
830///
831/// **Constraints:**
832/// - The query must be a single SQL `DELETE` statement.
833/// - Named parameters (if exist) must be in the format `:<param_name>` and must correspond to the function's parameters.
834///
835/// - `debug`: Controls the debug behavior of the macro. It can be:
836/// - An integer value. If not provided, the default is no debugging.
837/// - `0`: Prints the query before execution.
838/// - Greater than `0`: Prints the query and execution time if it exceeds the specified number of milliseconds.
839///
840/// # Function Signature
841///
842/// The macro generates an asynchronous function with the following characteristics:
843/// - The function signature remains unchanged (e.g., `pub async fn <function_name>`).
844/// - The function parameters are preserved in their original order.
845/// - An additional parameter for the database connection is required.
846///
847/// # Return Types
848///
849/// The macro supports the following return type based on the SQL query:
850///
851/// - **Single Record:**
852/// - `T`: Returns a single record, which must be present. If no record is found, an error is returned.
853/// - `Option<T>`: Returns a single record if present, or `None` if no record is found.
854///
855/// - **Multiple Records:**
856/// - `Vec<T>`: Returns all matching records as a vector.
857///
858/// - **Asynchronous Stream:**
859/// - `Stream<T>`: Returns an asynchronous stream of records.
860///
861/// - **Paged Records:**
862/// - `Page<T>`: Returns paginated results. Requires an additional parameter for pagination (e.g., `impl Into<(i64, i32, bool)>`). The function returns a tuple `(Vec<T>, Option<i64>)`, where the vector contains the paginated records, and the optional value represents the total number of records if requested.
863///
864/// - **Scalar Value:**
865/// - `Scalar<T>`: Returns a single scalar value from the query.
866///
867/// - **Affected Rows:**
868/// - `RowAffected`: Returns the number of affected rows.
869///
870/// - **Void:**
871/// - : Returns nothing.
872///
873/// # Example Usage
874///
875/// ```rust
876/// #[delete(
877/// sql = "DELETE FROM user WHERE name = :name",
878/// debug = 100
879/// )]
880/// pub async fn delete_user(name: &str) -> RowAffected {}
881///
882/// #[delete(
883/// sql = "DELETE FROM user WHERE name = :name",
884/// debug = 0
885/// )]
886/// pub async fn delete_user_no_return(name: &str) {}
887/// ```
888///
889
890#[proc_macro_attribute]
891pub fn delete(args: TokenStream, item: TokenStream) -> proc_macro::TokenStream {
892 let input = syn::parse_macro_input!(item as syn::ItemFn);
893 let args = syn::parse_macro_input!(args as syn::AttributeArgs);
894 match raw::query_derive(input, args, Some(parser::Mode::Delete)) {
895 Ok(ok) => ok,
896 Err(err) => err.to_compile_error().into(),
897 }
898 .into()
899}