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}