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}