sqlx_utils_macro/
lib.rs

1use crate::filter::expand;
2use proc_macro::TokenStream;
3
4const CRATE_NAME_STR: &str = "sqlx_utils";
5
6mod error;
7mod filter;
8mod types;
9
10/// Creates a type-safe SQL filter struct with builder methods using SQL-like syntax.
11///
12/// This macro generates a struct that implements the `SqlFilter` trait, making it
13/// suitable for use with repository query methods that accept SQL filters.
14///
15/// # Syntax
16///
17/// ```ignore
18/// sql_filter! {
19///     [attributes]
20///     visibility struct StructName {
21///         SELECT columns FROM table_name WHERE
22///         condition [AND|OR] condition ...
23///     }
24/// }
25/// ```
26///
27/// ## Columns
28///
29/// You can select all columns with `*` or specify individual columns:
30/// - `SELECT * FROM ...`: Select all columns
31/// - `SELECT col1, col2 as alias FROM ...`: Select specific columns with optional aliases
32///
33/// ## Conditions
34///
35/// Conditions use SQL-like syntax:
36/// ```ignore
37/// [?]column_name [as field_name] OPERATOR type
38/// ```
39///
40/// - Optional `?` prefix marks the field as optional in the filter
41/// - `column_name` is the database column name
42/// - Optional `as field_name` to use a different field name in the generated struct
43/// - `OPERATOR` is one of: `=`, `!=`, `>`, `<`, `>=`, `<=`, `LIKE`, `ILIKE`, `IN`, `NOT IN`
44/// - `type` is either a Rust type (e.g., `i32`, `String`) or a raw SQL string literal
45///
46/// Conditions can be combined with logical operators `AND`, `OR`, and `NOT`.
47///
48/// # Generated Code
49///
50/// The macro generates:
51/// 1. A struct with fields for each condition
52/// 2. A constructor method for required fields
53/// 3. Builder methods for optional fields
54/// 4. Implementation of the `SqlFilter` trait
55///
56/// # Examples
57///
58/// ## Basic Filter
59///
60/// ```rust,ignore
61/// # use sqlx_utils_macro::sql_filter;
62/// sql_filter! {
63///     pub struct UserFilter {
64///         SELECT * FROM users WHERE
65///         id = i32
66///     }
67/// }
68///
69/// // Usage:
70/// let filter = UserFilter::new(1);
71/// ```
72///
73/// ## Filter with Optional Fields
74///
75/// ```rust,ignore
76/// # use sqlx_utils_macro::sql_filter;
77/// sql_filter! {
78///     pub struct UserFilter {
79///         SELECT * FROM users WHERE
80///         ?name LIKE String AND
81///         ?age >= i32
82///     }
83/// }
84///
85/// // Usage:
86/// let filter = UserFilter::new()
87///     .name("John%")
88///     .age(18);
89/// ```
90///
91/// ## Filter with Raw SQL
92///
93/// ```rust,ignore
94/// # use sqlx_utils_macro::sql_filter;
95/// sql_filter! {
96///     pub struct UserFilter {
97///         SELECT * FROM users WHERE
98///         created_at > "NOW() - INTERVAL '1 day'"
99///     }
100/// }
101/// ```
102///
103/// ## Complex Filter
104///
105/// ```rust,ignore
106/// # use sqlx_utils_macro::sql_filter;
107/// sql_filter! {
108///     pub struct OrderFilter {
109///         SELECT id, total, name as customer_name FROM orders WHERE
110///         id = i32 OR
111///         (total > f64 AND ?customer_id = i32)
112///     }
113/// }
114/// ```
115#[proc_macro_error2::proc_macro_error]
116#[proc_macro]
117pub fn sql_filter(token_stream: TokenStream) -> TokenStream {
118    expand(token_stream)
119}