drizzle_macros/lib.rs
1//! # Drizzle RS Procedural Macros
2//!
3//! This crate provides the procedural macros for Drizzle RS, a type-safe SQL query builder for Rust.
4//!
5//! ## Core Macros
6//!
7//! ### SQLite
8//! - [`SQLiteTable`] - Define SQLite table schemas with type safety
9//! - [`SQLiteView`] - Define SQLite view schemas with type safety
10//! - [`SQLiteEnum`] - Define enums that can be stored in SQLite
11//! - [`SQLiteIndex`] - Define indexes on SQLite tables
12//! - [`SQLiteSchema`] - Derive macro to group tables and indexes into a schema
13//!
14//! ### PostgreSQL
15//! - [`PostgresTable`] - Define PostgreSQL table schemas with type safety
16//! - [`PostgresView`] - Define PostgreSQL view schemas with type safety
17//! - [`PostgresEnum`] - Define enums for PostgreSQL (text, integer, or native ENUM)
18
19//! - [`PostgresIndex`] - Define indexes on PostgreSQL tables
20//! - [`PostgresSchema`] - Derive macro to group tables and indexes into a schema
21//!
22//! ### Shared
23//! - [`SQLiteFromRow`] - Derive automatic row-to-struct conversion
24//! - [`sql!`] - Build SQL queries with embedded expressions
25//!
26//! ## Example Usage
27//!
28//! ```ignore
29//! use drizzle::sqlite::prelude::*;
30//!
31//! #[SQLiteTable(name = "users")]
32//! struct Users {
33//! #[integer(primary, autoincrement)]
34//! id: i32,
35//! #[text]
36//! name: String,
37//! #[text]
38//! email: Option<String>,
39//! }
40//!
41//! #[derive(SQLiteSchema)]
42//! struct Schema {
43//! users: Users,
44//! }
45//! ```
46//!
47//! For more detailed documentation, see the individual macro documentation below.
48
49extern crate proc_macro;
50
51mod common;
52mod drizzle_test;
53mod fromrow;
54mod generators;
55
56mod paths;
57mod sql;
58
59#[cfg(feature = "sqlite")]
60mod sqlite;
61
62#[cfg(feature = "postgres")]
63mod postgres;
64
65use proc_macro::TokenStream;
66use syn::parse_macro_input;
67
68/// Derive macro for creating SQLite-compatible enums.
69///
70/// This macro allows enums to be stored in SQLite databases as either TEXT (variant names)
71/// or INTEGER (discriminant values) depending on the column attribute used.
72///
73/// The enum can be used with `#[text(enum)]` or `#[integer(enum)]` column attributes.
74///
75/// # Requirements
76///
77/// - Enum must have at least one variant
78/// - For `#[integer(enum)]`, variants can have explicit discriminants
79/// - Must derive `Default` to specify the default variant
80///
81/// # Examples
82///
83/// ## Text Storage (Variant Names)
84///
85/// ```ignore
86/// use drizzle::sqlite::prelude::*;
87///
88/// #[derive(SQLiteEnum, Default, Clone, PartialEq, Debug)]
89/// enum UserRole {
90/// #[default]
91/// User, // Stored as "User"
92/// Admin, // Stored as "Admin"
93/// Moderator, // Stored as "Moderator"
94/// }
95///
96/// #[SQLiteTable(name = "users")]
97/// struct Users {
98/// #[integer(primary, autoincrement)]
99/// id: i32,
100/// #[text(enum)] // Stores variant names as TEXT
101/// role: UserRole,
102/// }
103///
104/// // The enum can be converted to/from strings
105/// assert_eq!(UserRole::Admin.to_string(), "Admin");
106/// ```
107///
108/// ## Integer Storage (Discriminants)
109///
110/// ```ignore
111/// use drizzle::sqlite::prelude::*;
112///
113/// #[derive(SQLiteEnum, Default, Clone, PartialEq, Debug)]
114/// enum Priority {
115/// #[default]
116/// Low = 1, // Stored as 1
117/// Medium = 5, // Stored as 5
118/// High = 10, // Stored as 10
119/// }
120///
121/// #[SQLiteTable(name = "tasks")]
122/// struct Tasks {
123/// #[integer(primary, autoincrement)]
124/// id: i32,
125/// #[integer(enum)] // Stores discriminants as INTEGER
126/// priority: Priority,
127/// }
128///
129/// // The enum can be converted to/from integers
130/// let p: i64 = Priority::High.into();
131/// assert_eq!(p, 10);
132/// ```
133///
134/// ## Generated Implementations
135///
136/// The macro automatically implements:
137/// - `std::fmt::Display` - For TEXT representation
138/// - `TryFrom<i64>` - For INTEGER representation
139/// - `Into<i64>` - For INTEGER representation
140/// - `From<EnumType>` for `SQLiteValue` - Database conversion
141/// - `TryFrom<SQLiteValue>` for `EnumType` - Database conversion
142#[cfg(feature = "sqlite")]
143#[proc_macro_derive(SQLiteEnum)]
144pub fn sqlite_enum_derive(input: TokenStream) -> TokenStream {
145 use quote::quote;
146 use syn::{Data, DeriveInput, parse_macro_input};
147
148 let input = parse_macro_input!(input as DeriveInput);
149 let name = &input.ident;
150
151 // Check if this is an enum or tuple struct
152 match &input.data {
153 Data::Enum(data) => {
154 // Check if the enum has any variants
155 if data.variants.is_empty() {
156 return quote! {
157 compile_error!("SQLiteEnum cannot be derived for empty enums");
158 }
159 .into();
160 }
161
162 // Generate implementation for enum
163 match crate::sqlite::r#enum::generate_enum_impl(name, data) {
164 Ok(ts) => ts.into(),
165 Err(e) => e.to_compile_error().into(),
166 }
167 }
168 _ => quote! {
169 compile_error!("SQLiteEnum can only be derived for enums and tuple structs");
170 }
171 .into(),
172 }
173}
174
175/// Define a SQLite table schema with type-safe column definitions.
176///
177/// This attribute macro transforms a Rust struct into a complete SQLite table definition
178/// with generated types for INSERT, SELECT, and UPDATE operations.
179///
180/// See [SQLite CREATE TABLE documentation](https://sqlite.org/lang_createtable.html) for
181/// the underlying SQL concepts.
182///
183/// # Table Attributes
184///
185/// - `name = "table_name"` - Custom table name (defaults to struct name in snake_case)
186/// - `strict` - Enable [SQLite STRICT mode](https://sqlite.org/stricttables.html)
187/// - `without_rowid` - Create a [WITHOUT ROWID table](https://sqlite.org/withoutrowid.html)
188///
189/// # Field Attributes
190///
191/// ## Column Types
192/// - `#[integer]` - SQLite INTEGER type
193/// - `#[text]` - SQLite TEXT type
194/// - `#[real]` - SQLite REAL type
195/// - `#[blob]` - SQLite BLOB type
196/// - `#[boolean]` - Stored as INTEGER (0/1)
197///
198/// ## Constraints
199/// - `primary` - Primary key constraint
200/// - `autoincrement` - Auto-increment (INTEGER PRIMARY KEY only)
201/// - `unique` - Unique constraint
202///
203/// ## Defaults
204/// - `default = value` - Compile-time default value
205/// - `default_fn = function` - Runtime default function (called at insert time)
206///
207/// ## Special Types
208/// - `enum` - Store enum as TEXT or INTEGER (requires `SQLiteEnum` derive)
209/// - `json` - JSON serialization (requires `serde` feature)
210/// - `references = Table::column` - Foreign key reference
211///
212/// # Examples
213///
214/// ## Basic Table
215///
216/// ```ignore
217/// use drizzle::sqlite::prelude::*;
218///
219/// #[SQLiteTable(name = "users")]
220/// struct Users {
221/// #[integer(primary, autoincrement)]
222/// id: i32,
223/// #[text]
224/// name: String,
225/// #[text(unique)]
226/// email: String,
227/// #[integer]
228/// age: Option<i32>, // Nullable field
229/// }
230///
231/// #[derive(SQLiteSchema)]
232/// struct Schema {
233/// users: Users,
234/// }
235///
236/// let _schema = Schema::new();
237/// ```
238///
239/// ## Table with Defaults
240///
241/// ```ignore
242/// use drizzle::sqlite::prelude::*;
243///
244/// #[SQLiteTable(name = "posts", strict)]
245/// struct Posts {
246/// #[integer(primary, autoincrement)]
247/// id: i32,
248/// #[text]
249/// title: String,
250/// #[text(default = "draft")]
251/// status: String,
252/// }
253///
254/// // Default value is used when not specified
255/// let post = InsertPosts::new("My Title");
256/// ```
257///
258/// ## Enums and JSON
259///
260/// ```ignore
261/// use drizzle::sqlite::prelude::*;
262/// use serde::{Serialize, Deserialize};
263///
264/// #[derive(SQLiteEnum, Default, Clone, PartialEq, Debug)]
265/// enum Role {
266/// #[default]
267/// User,
268/// Admin,
269/// }
270///
271/// #[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
272/// struct Metadata {
273/// theme: String,
274/// }
275///
276/// #[SQLiteTable(name = "accounts")]
277/// struct Accounts {
278/// #[integer(primary, autoincrement)]
279/// id: i32,
280/// #[text(enum)] // Store enum variant name as TEXT
281/// role: Role,
282/// #[text(json)] // Serialize struct as JSON TEXT
283/// metadata: Option<Metadata>,
284/// }
285/// ```
286///
287/// ## Foreign Key References
288///
289/// ```ignore
290/// use drizzle::sqlite::prelude::*;
291///
292/// #[SQLiteTable(name = "users")]
293/// struct Users {
294/// #[integer(primary, autoincrement)]
295/// id: i32,
296/// #[text]
297/// name: String,
298/// }
299///
300/// #[SQLiteTable(name = "posts")]
301/// struct Posts {
302/// #[integer(primary, autoincrement)]
303/// id: i32,
304/// #[integer(references = Users::id)] // Foreign key to users.id
305/// author_id: i32,
306/// #[text]
307/// title: String,
308/// }
309/// ```
310///
311/// # Generated Types
312///
313/// For a table `Users`, the macro generates:
314/// - `SelectUsers` - For SELECT operations (derives `FromRow`)
315/// - `InsertUsers` - Builder for INSERT operations with `new()` and `with_*()` methods
316/// - `UpdateUsers` - Builder for UPDATE operations with `set_*()` methods
317///
318/// # Nullability
319///
320/// Use `Option<T>` for nullable fields. Non-optional fields get a NOT NULL constraint:
321///
322/// ```ignore
323/// use drizzle::sqlite::prelude::*;
324///
325/// #[SQLiteTable]
326/// struct Example {
327/// #[integer(primary, autoincrement)]
328/// id: i32, // NOT NULL, auto-generated
329/// #[text]
330/// name: String, // NOT NULL (required in InsertExample::new())
331/// #[text]
332/// email: Option<String>, // NULL allowed (set via with_email())
333/// }
334///
335/// // Non-optional, non-primary fields are required in new()
336/// let insert = InsertExample::new("Alice").with_email("alice@example.com");
337/// ```
338#[cfg(feature = "sqlite")]
339#[allow(non_snake_case)]
340#[proc_macro_attribute]
341pub fn SQLiteTable(attr: TokenStream, item: TokenStream) -> TokenStream {
342 let input = syn::parse_macro_input!(item as syn::DeriveInput);
343 let attr_result = syn::parse_macro_input!(attr as crate::sqlite::table::TableAttributes);
344
345 match crate::sqlite::table::table_attr_macro(input, attr_result) {
346 Ok(tokens) => tokens.into(),
347 Err(err) => err.to_compile_error().into(),
348 }
349}
350
351/// Attribute macro for defining SQLite views.
352///
353/// This macro generates a typed view schema with column accessors and view metadata.
354///
355/// # Attributes
356///
357/// - `name/NAME = "view_name"` - Optional view name (defaults to struct name in snake_case)
358/// - `definition/DEFINITION = "SELECT ..."` - View definition SQL
359/// - `existing/EXISTING` - Mark view as existing (skip creation)
360#[cfg(feature = "sqlite")]
361#[allow(non_snake_case)]
362#[proc_macro_attribute]
363pub fn SQLiteView(attr: TokenStream, item: TokenStream) -> TokenStream {
364 let input = syn::parse_macro_input!(item as syn::DeriveInput);
365 let attr_result = syn::parse_macro_input!(attr as crate::sqlite::view::ViewAttributes);
366
367 match crate::sqlite::view::view_attr_macro(input, attr_result) {
368 Ok(tokens) => tokens.into(),
369 Err(err) => err.to_compile_error().into(),
370 }
371}
372
373/// Attribute macro for creating SQLite indexes.
374///
375/// This macro generates SQLite-specific index definitions for columns in your tables.
376/// Indexes improve query performance when filtering or sorting by the indexed columns.
377///
378/// # Attributes
379///
380/// - `unique` - Create a unique index (enforces uniqueness constraint)
381/// - No attributes for standard index
382///
383/// # Examples
384///
385/// ## Unique Index
386///
387/// ```ignore
388/// use drizzle::sqlite::prelude::*;
389///
390/// #[SQLiteTable(name = "users")]
391/// struct Users {
392/// #[integer(primary, autoincrement)]
393/// id: i32,
394/// #[text]
395/// email: String,
396/// }
397///
398/// #[SQLiteIndex(unique)]
399/// struct UserEmailIdx(Users::email);
400///
401/// #[derive(SQLiteSchema)]
402/// struct Schema {
403/// users: Users,
404/// user_email_idx: UserEmailIdx,
405/// }
406/// ```
407///
408/// ## Composite Index
409///
410/// Index on multiple columns:
411///
412/// ```ignore
413/// use drizzle::sqlite::prelude::*;
414///
415/// #[SQLiteTable(name = "posts")]
416/// struct Posts {
417/// #[integer(primary, autoincrement)]
418/// id: i32,
419/// #[integer]
420/// author_id: i32,
421/// #[text]
422/// status: String,
423/// }
424///
425/// #[SQLiteIndex]
426/// struct PostAuthorStatusIdx(Posts::author_id, Posts::status);
427/// ```
428///
429/// ## Standard (Non-Unique) Index
430///
431/// ```ignore
432/// use drizzle::sqlite::prelude::*;
433///
434/// #[SQLiteTable(name = "logs")]
435/// struct Logs {
436/// #[integer(primary, autoincrement)]
437/// id: i32,
438/// #[text]
439/// created_at: String,
440/// }
441///
442/// #[SQLiteIndex]
443/// struct LogsCreatedAtIdx(Logs::created_at);
444/// ```
445#[cfg(feature = "sqlite")]
446#[allow(non_snake_case)]
447#[proc_macro_attribute]
448pub fn SQLiteIndex(attr: TokenStream, item: TokenStream) -> TokenStream {
449 let input = syn::parse_macro_input!(item as syn::DeriveInput);
450 let attr_input = syn::parse_macro_input!(attr as crate::sqlite::index::IndexAttributes);
451
452 match crate::sqlite::index::sqlite_index_attr_macro(attr_input, input) {
453 Ok(tokens) => tokens.into(),
454 Err(err) => err.to_compile_error().into(),
455 }
456}
457
458/// Automatically implements row-to-struct conversion for database result types.
459///
460/// This derive macro generates `TryFrom` implementations for all enabled SQLite database
461/// drivers, allowing seamless conversion from database rows to Rust structs.
462///
463/// # Supported Drivers
464///
465/// Implementations are generated based on enabled features:
466/// - **rusqlite** - `TryFrom<&rusqlite::Row<'_>>` (sync)
467/// - **libsql** - `TryFrom<&libsql::Row>` (async)
468/// - **turso** - `TryFrom<&turso::Row>` (async)
469///
470/// # Supported Types
471///
472/// The macro automatically handles type conversion for:
473///
474/// | Rust Type | SQLite Type | Notes |
475/// |-----------|-------------|-------|
476/// | `i8`, `i16`, `i32`, `i64` | INTEGER | Auto-converts from i64 |
477/// | `u8`, `u16`, `u32`, `u64` | INTEGER | Auto-converts from i64 |
478/// | `f32`, `f64` | REAL | Auto-converts from f64 |
479/// | `bool` | INTEGER | 0 = false, non-zero = true |
480/// | `String` | TEXT | |
481/// | `Vec<u8>` | BLOB | |
482/// | `uuid::Uuid` | BLOB | Requires `uuid` feature |
483/// | `Option<T>` | Any | Nullable columns |
484///
485/// # Field Attributes
486///
487/// - `#[column(Table::field)]` - Map to a specific table column (useful for JOINs)
488/// - `#[json]` - Deserialize JSON from TEXT column (requires `serde` feature)
489/// - No attribute - Maps to column with same name as the field
490///
491/// # Struct Types
492///
493/// Both named structs and tuple structs are supported:
494/// - Named structs map fields by column name
495/// - Tuple structs map fields by column index (0-based)
496///
497/// # Examples
498///
499/// ## Basic Usage
500///
501/// ```ignore
502/// use drizzle::sqlite::prelude::*;
503///
504/// #[derive(SQLiteFromRow, Debug, Default)]
505/// struct User {
506/// id: i32,
507/// name: String,
508/// email: Option<String>, // Nullable column
509/// active: bool, // INTEGER 0/1 -> bool
510/// }
511/// ```
512///
513/// ## Custom Column Mapping (for JOINs)
514///
515/// When joining tables with columns of the same name, use `#[column(...)]` to
516/// specify which table's column to use:
517///
518/// ```ignore
519/// use drizzle::sqlite::prelude::*;
520/// use drizzle_macros::{SQLiteTable, SQLiteFromRow};
521///
522/// #[SQLiteTable(name = "users")]
523/// struct Users {
524/// #[column(primary)]
525/// id: i32,
526/// pub name: String,
527/// }
528///
529/// #[SQLiteTable(name = "posts")]
530/// struct Posts {
531/// #[column(primary)]
532/// id: i32,
533/// #[column(references = Users::id)]
534/// user_id: i32,
535/// pub title: String,
536/// }
537///
538/// #[derive(SQLiteFromRow, Debug, Default)]
539/// struct UserPost {
540/// #[column(Users::id)] // Explicitly use users.id
541/// user_id: i32,
542/// #[column(Users::name)]
543/// user_name: String,
544/// #[column(Posts::id)] // Explicitly use posts.id
545/// post_id: i32,
546/// #[column(Posts::title)]
547/// title: String,
548/// }
549/// ```
550///
551/// ## Tuple Structs
552///
553/// For simple single-column or multi-column results:
554///
555/// ```ignore
556/// use drizzle::sqlite::prelude::*;
557///
558/// // Single column result
559/// #[derive(SQLiteFromRow, Default)]
560/// struct Count(i64);
561///
562/// // Multiple columns by index
563/// #[derive(SQLiteFromRow, Default)]
564/// struct IdAndName(i32, String);
565/// ```
566///
567/// ## With UUID (requires `uuid` feature)
568///
569/// ```ignore
570/// use drizzle::sqlite::prelude::*;
571/// use uuid::Uuid;
572///
573/// #[derive(SQLiteFromRow, Debug, Default)]
574/// struct UserWithId {
575/// id: Uuid, // Stored as BLOB (16 bytes)
576/// name: String,
577/// }
578/// ```
579///
580/// ## With JSON (requires `serde` feature)
581///
582/// ```ignore
583/// // This example requires serde feature and specific rusqlite version compatibility
584/// use drizzle::sqlite::prelude::*;
585/// use drizzle_macros::SQLiteFromRow;
586/// use serde::{Serialize, Deserialize};
587///
588/// #[derive(Serialize, Deserialize, Debug, Default, Clone)]
589/// struct Profile {
590/// bio: String,
591/// website: Option<String>,
592/// }
593///
594/// #[derive(SQLiteFromRow, Debug, Default)]
595/// struct UserWithProfile {
596/// id: i32,
597/// name: String,
598/// #[json] // Deserialize from JSON TEXT
599/// profile: Profile,
600/// }
601/// ```
602///
603/// ## Tuple Structs
604///
605/// ```ignore
606/// use drizzle::sqlite::prelude::*;
607///
608/// #[derive(SQLiteFromRow, Default)]
609/// struct NameOnly(String);
610///
611/// // Usage: let names: Vec<NameOnly> = db.select(users.name).from(users).all()?;
612/// ```
613#[cfg(feature = "sqlite")]
614#[proc_macro_derive(SQLiteFromRow, attributes(column, json))]
615pub fn sqlite_from_row_derive(input: TokenStream) -> TokenStream {
616 let input = parse_macro_input!(input as syn::DeriveInput);
617
618 match crate::fromrow::generate_sqlite_from_row_impl(input) {
619 Ok(tokens) => tokens.into(),
620 Err(err) => err.to_compile_error().into(),
621 }
622}
623
624/// Automatically implements row-to-struct conversion for PostgreSQL database drivers.
625///
626/// This derive macro generates `TryFrom` implementations for PostgreSQL database
627/// drivers, allowing seamless conversion from database rows to Rust structs.
628///
629/// # Supported Drivers
630///
631/// Implementations are generated based on enabled features:
632/// - **postgres** - `TryFrom<&postgres::Row>` (sync)
633/// - **tokio-postgres** - `TryFrom<&tokio_postgres::Row>` (async)
634///
635/// # Example
636///
637/// ```ignore
638/// use drizzle::postgres::prelude::*;
639///
640/// #[derive(PostgresFromRow, Debug, Default)]
641/// struct User {
642/// id: i32,
643/// name: String,
644/// email: Option<String>,
645/// }
646/// ```
647#[cfg(feature = "postgres")]
648#[proc_macro_derive(PostgresFromRow, attributes(column))]
649pub fn postgres_from_row_derive(input: TokenStream) -> TokenStream {
650 let input = parse_macro_input!(input as syn::DeriveInput);
651
652 match crate::fromrow::generate_postgres_from_row_impl(input) {
653 Ok(tokens) => tokens.into(),
654 Err(err) => err.to_compile_error().into(),
655 }
656}
657
658/// Derive macro for creating schema structures that manage tables and indexes.
659///
660/// This macro analyzes struct fields to automatically detect tables and indexes,
661/// then generates methods to create all database objects in the correct order.
662///
663/// The schema provides:
664/// - `Schema::new()` - Creates a new schema instance with all tables and indexes
665/// - Integration with `Drizzle::new()` for database operations
666/// - Automatic table and index creation via `db.create()`
667///
668/// # Examples
669///
670/// ## Basic Schema
671///
672/// ```ignore
673/// use drizzle::sqlite::prelude::*;
674///
675/// #[SQLiteTable(name = "users")]
676/// struct Users {
677/// #[integer(primary, autoincrement)]
678/// id: i32,
679/// #[text]
680/// email: String,
681/// }
682///
683/// #[derive(SQLiteSchema)]
684/// struct Schema {
685/// users: Users,
686/// }
687/// // Schema::new() is generated by the derive
688/// let _schema = Schema::new();
689/// ```
690///
691/// ## Schema with Indexes
692///
693/// ```ignore
694/// use drizzle::sqlite::prelude::*;
695///
696/// #[SQLiteTable(name = "users")]
697/// struct Users {
698/// #[integer(primary, autoincrement)]
699/// id: i32,
700/// #[text]
701/// email: String,
702/// #[text]
703/// name: String,
704/// }
705///
706/// #[SQLiteIndex(unique)]
707/// struct UserEmailIdx(Users::email);
708///
709/// #[derive(SQLiteSchema)]
710/// struct Schema {
711/// users: Users,
712/// user_email_idx: UserEmailIdx,
713/// }
714///
715/// let _schema = Schema::new();
716/// ```
717///
718/// ## Async Drivers (libsql, turso)
719///
720/// ```ignore
721/// use drizzle::sqlite::prelude::*;
722///
723/// #[SQLiteTable]
724/// struct Users {
725/// #[column(PRIMARY)]
726/// id: i32,
727/// name: String,
728/// }
729///
730/// #[derive(SQLiteSchema)]
731/// struct Schema {
732/// users: Users,
733/// }
734///
735/// let _schema = Schema::new();
736/// ```
737#[cfg(feature = "sqlite")]
738#[proc_macro_derive(SQLiteSchema)]
739pub fn sqlite_schema_derive(input: TokenStream) -> TokenStream {
740 let input = parse_macro_input!(input as syn::DeriveInput);
741
742 match crate::sqlite::schema::generate_sqlite_schema_derive_impl(input) {
743 Ok(tokens) => tokens.into(),
744 Err(err) => err.to_compile_error().into(),
745 }
746}
747
748#[cfg(feature = "postgres")]
749#[proc_macro_derive(PostgresSchema)]
750pub fn postgres_schema_derive(input: TokenStream) -> TokenStream {
751 let input = parse_macro_input!(input as syn::DeriveInput);
752
753 match crate::postgres::generate_postgres_schema_derive_impl(input) {
754 Ok(tokens) => tokens.into(),
755 Err(err) => err.to_compile_error().into(),
756 }
757}
758
759/// A procedural macro for building SQL queries with embedded expressions.
760///
761/// This macro supports two different syntax forms:
762/// 1. **String literal syntax**: `sql!("SELECT * FROM {table}")`
763/// 2. **Printf-style syntax**: `sql!("SELECT * FROM {} WHERE {} = {}", table, column, value)`
764///
765/// The macro parses SQL templates and generates type-safe SQL code by:
766/// - Converting literal text to `SQL::text()` calls
767/// - Converting expressions in `{braces}` to `.to_sql()` calls on the expression
768///
769/// # Syntax Forms
770///
771/// ## String Literal Syntax
772///
773/// Embed expressions directly in the SQL string using `{expression}`:
774///
775/// ```ignore
776/// use drizzle::sql;
777/// use drizzle::sqlite::prelude::*;
778///
779/// #[SQLiteTable(name = "users")]
780/// pub struct Users {
781/// #[column(primary)]
782/// pub id: i32,
783/// pub name: String,
784/// }
785///
786/// #[derive(SQLiteSchema)]
787/// pub struct Schema { pub users: Users }
788///
789/// let users = Users::default();
790/// let query = sql!("SELECT * FROM {users} WHERE {users.id} = 42");
791/// ```
792///
793/// ## Printf-Style Syntax
794///
795/// Use `{}` placeholders with arguments after the string:
796///
797/// ```ignore
798/// use drizzle::sql;
799/// use drizzle::sqlite::prelude::*;
800///
801/// #[SQLiteTable(name = "users")]
802/// pub struct Users {
803/// #[column(primary)]
804/// pub id: i32,
805/// }
806///
807/// #[derive(SQLiteSchema)]
808/// pub struct Schema { pub users: Users }
809///
810/// let users = Users::default();
811/// let query = sql!("SELECT * FROM {} WHERE {} = {}", users, users.id, 42);
812/// ```
813///
814/// # Examples
815///
816/// ## Basic Usage
817///
818/// ```ignore
819/// use drizzle::sqlite::prelude::*;
820///
821/// #[SQLiteTable(name = "users")]
822/// pub struct Users {
823/// #[column(PRIMARY)]
824/// pub id: i32,
825/// }
826///
827/// let users = Users::default();
828/// let query = drizzle::sql!("SELECT * FROM {users}");
829/// // Generates: SQL::text("SELECT * FROM ").append(users.to_sql())
830/// ```
831///
832/// ## Multiple Expressions
833///
834/// ```ignore
835/// use drizzle::sqlite::prelude::*;
836///
837/// #[SQLiteTable(name = "users")]
838/// pub struct Users {
839/// #[column(PRIMARY)]
840/// pub id: i32,
841/// }
842///
843/// #[SQLiteTable(name = "posts")]
844/// pub struct Posts {
845/// #[column(PRIMARY)]
846/// pub id: i32,
847/// pub author_id: i32,
848/// }
849///
850/// let users = Users::default();
851/// let posts = Posts::default();
852/// let query = drizzle::sql!("SELECT * FROM {users} WHERE {users.id} = {posts.author_id}");
853/// ```
854///
855/// ## Escaped Braces
856///
857/// Use `{{` and `}}` for literal braces in the SQL:
858///
859/// ```ignore
860/// use drizzle::sqlite::prelude::*;
861///
862/// #[SQLiteTable(name = "users")]
863/// pub struct Users {
864/// #[column(PRIMARY)]
865/// pub id: i32,
866/// }
867///
868/// let users = Users::default();
869/// let query = drizzle::sql!("SELECT JSON_OBJECT('key', {{literal}}) FROM {users}");
870/// // Generates: SQL::text("SELECT JSON_OBJECT('key', {literal}) FROM ").append(users.to_sql())
871/// ```
872///
873/// # Requirements
874///
875/// All expressions within `{braces}` must implement the `ToSQL` trait.
876#[proc_macro]
877pub fn sql(input: TokenStream) -> TokenStream {
878 let input = parse_macro_input!(input as crate::sql::SqlInput);
879
880 match crate::sql::sql_impl(input) {
881 Ok(output) => output.into(),
882 Err(err) => err.into_compile_error().into(),
883 }
884}
885
886/// Generates test functions for all enabled SQLite drivers.
887///
888/// This macro creates separate test functions for rusqlite, libsql, and turso drivers,
889/// each with proper async/sync handling and driver-specific setup.
890///
891/// # Syntax
892///
893/// ```ignore
894/// sqlite_test!(test_name, SchemaType, {
895/// // Test body - uses `db` and `schema` variables
896/// let SchemaType { my_table } = schema;
897/// let result = drizzle_exec!(db.insert(my_table).values([data]).execute());
898/// assert_eq!(result, 1);
899/// });
900/// ```
901///
902/// # Generated Functions
903///
904/// For a test named `my_test`, this generates:
905/// - `my_test_rusqlite()` - Sync test for rusqlite (when `rusqlite` feature enabled)
906/// - `my_test_libsql()` - Async test for libsql (when `libsql` feature enabled)
907/// - `my_test_turso()` - Async test for turso (when `turso` feature enabled)
908///
909/// # Available Macros in Test Body
910///
911/// - `drizzle_exec!(operation)` - Execute operation with proper async/sync handling
912/// - `drizzle_try!(operation)` - Try operation, returns early on error
913/// - `drizzle_tx!(tx_type, { body })` - Execute transaction with proper async/sync handling
914///
915/// # Variables Available in Test Body
916///
917/// - `db` - The Drizzle instance for the current driver
918/// - `schema` - The schema instance with all tables
919/// - `tx` - The transaction instance (within `drizzle_tx!` blocks)
920///
921/// # Example
922///
923/// ```ignore
924/// use drizzle::sqlite::prelude::*;
925/// use drizzle_macros::sqlite_test;
926///
927/// #[SQLiteTable(name = "users")]
928/// struct Users {
929/// #[column(PRIMARY, AUTOINCREMENT)]
930/// id: i32,
931/// name: String,
932/// }
933///
934/// #[derive(SQLiteSchema)]
935/// struct TestSchema {
936/// users: Users,
937/// }
938///
939/// sqlite_test!(insert_and_select, TestSchema, {
940/// let TestSchema { users } = schema;
941///
942/// // Insert a user
943/// drizzle_exec!(db.insert(users)
944/// .values([InsertUsers::new("Alice")])
945/// .execute());
946///
947/// // Select all users
948/// let results: Vec<SelectUsers> = drizzle_exec!(
949/// db.select(()).from(users).all()
950/// );
951///
952/// assert_eq!(results.len(), 1);
953/// assert_eq!(results[0].name, "Alice");
954/// });
955/// ```
956#[proc_macro]
957pub fn sqlite_test(input: TokenStream) -> TokenStream {
958 crate::drizzle_test::drizzle_test_impl(input)
959}
960
961/// Generates test functions for all enabled PostgreSQL drivers.
962///
963/// This macro creates separate test functions for PostgreSQL drivers (postgres-sync, tokio-postgres),
964/// each with proper async/sync handling and driver-specific setup.
965///
966/// # Syntax
967///
968/// ```ignore
969/// postgres_test!(test_name, SchemaType, {
970/// // Test body - uses `db` and `schema` variables
971/// let SchemaType { my_table } = schema;
972/// let result = drizzle_exec!(db.insert(my_table).values([data]).execute());
973/// assert_eq!(result, 1);
974/// });
975/// ```
976///
977/// # Generated Functions
978///
979/// For a test named `my_test`, this generates:
980/// - `my_test_postgres_sync()` - Sync test for postgres (when `postgres-sync` feature enabled)
981///
982/// # Available Macros in Test Body
983///
984/// - `drizzle_exec!(operation)` - Execute operation with proper async/sync handling
985/// - `drizzle_try!(operation)` - Try operation, returns early on error
986/// - `drizzle_tx!(tx_type, { body })` - Execute transaction with proper async/sync handling
987///
988/// # Variables Available in Test Body
989///
990/// - `db` - The Drizzle instance for the current driver
991/// - `schema` - The schema instance with all tables
992/// - `tx` - The transaction instance (within `drizzle_tx!` blocks)
993///
994/// # Example
995///
996/// ```ignore
997/// use drizzle::postgres::prelude::*;
998/// use drizzle_macros::postgres_test;
999///
1000/// #[PostgresTable(name = "users")]
1001/// struct Users {
1002/// #[column(serial, primary)]
1003/// id: i32,
1004/// name: String,
1005/// }
1006///
1007/// #[derive(PostgresSchema)]
1008/// struct TestSchema {
1009/// users: Users,
1010/// }
1011///
1012/// postgres_test!(insert_and_select, TestSchema, {
1013/// let TestSchema { users } = schema;
1014///
1015/// // Insert a user
1016/// drizzle_exec!(db.insert(users)
1017/// .values([InsertUsers::new("Alice")])
1018/// .execute());
1019///
1020/// // Select all users
1021/// let results: Vec<SelectUsers> = drizzle_exec!(
1022/// db.select(()).from(users).all()
1023/// );
1024///
1025/// assert_eq!(results.len(), 1);
1026/// assert_eq!(results[0].name, "Alice");
1027/// });
1028/// ```
1029#[proc_macro]
1030pub fn postgres_test(input: TokenStream) -> TokenStream {
1031 crate::drizzle_test::postgres_test_impl(input)
1032}
1033
1034/// Derive macro for creating PostgreSQL-compatible enums.
1035///
1036/// This macro allows enums to be stored in PostgreSQL databases in three ways:
1037/// - **TEXT** - Store variant names as text (`#[text(enum)]`)
1038/// - **INTEGER** - Store discriminant values as integers (`#[integer(enum)]`)
1039/// - **Native ENUM** - Use PostgreSQL's native ENUM type (`#[enum(EnumType)]`)
1040///
1041/// # Requirements
1042///
1043/// - Enum must have at least one variant
1044/// - For `#[integer(enum)]`, variants can have explicit discriminants
1045/// - Must derive `Default` to specify the default variant
1046///
1047/// # Examples
1048///
1049/// ## Text Storage (Variant Names)
1050///
1051/// ```ignore
1052/// use drizzle::postgres::prelude::*;
1053///
1054/// #[derive(PostgresEnum, Default, Clone, PartialEq, Debug)]
1055/// enum UserRole {
1056/// #[default]
1057/// User, // Stored as "User"
1058/// Admin, // Stored as "Admin"
1059/// Moderator, // Stored as "Moderator"
1060/// }
1061///
1062/// #[PostgresTable(name = "users")]
1063/// struct Users {
1064/// #[column(serial, primary)]
1065/// id: i32,
1066/// #[column(enum)] // Stores variant names as TEXT
1067/// role: UserRole,
1068/// }
1069/// ```
1070///
1071/// ## Integer Storage (Discriminants)
1072///
1073/// ```ignore
1074/// use drizzle::postgres::prelude::*;
1075///
1076/// #[derive(PostgresEnum, Default, Clone, PartialEq, Debug)]
1077/// enum Priority {
1078/// #[default]
1079/// Low = 1, // Stored as 1
1080/// Medium = 5, // Stored as 5
1081/// High = 10, // Stored as 10
1082/// }
1083///
1084/// #[PostgresTable(name = "tasks")]
1085/// struct Tasks {
1086/// #[column(serial, primary)]
1087/// id: i32,
1088/// #[column(enum)] // Stores discriminants as INTEGER
1089/// priority: Priority,
1090/// }
1091/// ```
1092///
1093/// ## Native PostgreSQL ENUM Type
1094///
1095/// PostgreSQL supports native ENUM types which are more efficient and type-safe:
1096///
1097/// ```ignore
1098/// use drizzle::postgres::prelude::*;
1099///
1100/// #[derive(PostgresEnum, Default, Clone, PartialEq, Debug)]
1101/// enum Color {
1102/// #[default]
1103/// Red,
1104/// Green,
1105/// Blue,
1106/// }
1107///
1108/// #[PostgresTable(name = "items")]
1109/// struct Items {
1110/// #[column(serial, primary)]
1111/// id: i32,
1112/// #[column(enum)] // Uses PostgreSQL native ENUM type
1113/// color: Color,
1114/// }
1115/// ```
1116///
1117/// ## Generated Implementations
1118///
1119/// The macro automatically implements:
1120/// - `std::fmt::Display` - For TEXT representation
1121/// - `TryFrom<i64>` - For INTEGER representation
1122/// - `Into<i64>` - For INTEGER representation
1123/// - `From<EnumType>` for `PostgresValue` - Database conversion
1124/// - `TryFrom<PostgresValue>` for `EnumType` - Database conversion
1125#[cfg(feature = "postgres")]
1126#[proc_macro_derive(PostgresEnum)]
1127pub fn postgres_enum_derive(input: TokenStream) -> TokenStream {
1128 use quote::quote;
1129 use syn::{Data, DeriveInput, parse_macro_input};
1130
1131 let input = parse_macro_input!(input as DeriveInput);
1132 let name = &input.ident;
1133
1134 // Check if this is an enum
1135 match &input.data {
1136 Data::Enum(data) => {
1137 // Check if the enum has any variants
1138 if data.variants.is_empty() {
1139 return quote! {
1140 compile_error!("PostgresEnum cannot be derived for empty enums");
1141 }
1142 .into();
1143 }
1144
1145 // Generate implementation for enum
1146 match crate::postgres::r#enum::generate_enum_impl(name, data) {
1147 Ok(ts) => ts.into(),
1148 Err(e) => e.to_compile_error().into(),
1149 }
1150 }
1151 _ => quote! {
1152 compile_error!("PostgresEnum can only be derived for enums");
1153 }
1154 .into(),
1155 }
1156}
1157
1158/// Define a PostgreSQL table schema with type-safe column definitions.
1159///
1160/// This attribute macro transforms a Rust struct into a complete PostgreSQL table definition
1161/// with generated types for INSERT, SELECT, and UPDATE operations.
1162///
1163/// See [PostgreSQL CREATE TABLE documentation](https://www.postgresql.org/docs/current/sql-createtable.html) for
1164/// the underlying SQL concepts.
1165///
1166/// # Table Attributes
1167///
1168/// - `name = "table_name"` - Custom table name (defaults to struct name in snake_case)
1169/// - `unlogged` - Create UNLOGGED table for better performance
1170/// - `temporary` - Create TEMPORARY table
1171/// - `if_not_exists` - Add IF NOT EXISTS clause
1172///
1173/// # Field Attributes
1174///
1175/// ## Column Types
1176/// - `#[integer]` - PostgreSQL INTEGER type
1177/// - `#[bigint]` - PostgreSQL BIGINT type
1178/// - `#[smallint]` - PostgreSQL SMALLINT type
1179/// - `#[serial]` - PostgreSQL SERIAL type (auto-increment)
1180/// - `#[bigserial]` - PostgreSQL BIGSERIAL type
1181/// - `#[text]` - PostgreSQL TEXT type
1182/// - `#[varchar(n)]` - PostgreSQL VARCHAR(n) type
1183/// - `#[real]` - PostgreSQL REAL type
1184/// - `#[double_precision]` - PostgreSQL DOUBLE PRECISION type
1185/// - `#[boolean]` - PostgreSQL BOOLEAN type
1186/// - `#[bytea]` - PostgreSQL BYTEA type (binary data)
1187/// - `#[uuid]` - PostgreSQL UUID type (requires `uuid` feature)
1188/// - `#[json]` - PostgreSQL JSON type (requires `serde` feature)
1189/// - `#[jsonb]` - PostgreSQL JSONB type (requires `serde` feature)
1190/// - `#[enum(MyEnum)]` - PostgreSQL native ENUM type
1191///
1192/// ## Constraints
1193/// - `primary` - Primary key constraint
1194/// - `unique` - Unique constraint
1195///
1196/// ## Defaults
1197/// - `default = value` - Compile-time default value
1198/// - `default_fn = function` - Runtime default function
1199///
1200/// ## Special Types
1201/// - `enum` - Store enum as TEXT or INTEGER (`#[text(enum)]` or `#[integer(enum)]`)
1202/// - `json` - JSON serialization (`#[text(json)]` or `#[jsonb]`)
1203/// - `references = Table::column` - Foreign key reference
1204///
1205/// Note: `#[column(enum)]` stores enum names or discriminants in TEXT/INTEGER columns unless
1206/// you use a native PostgreSQL ENUM type via `#[enum(MyEnum)]`.
1207///
1208/// # Examples
1209///
1210/// ## Basic Table
1211///
1212/// ```ignore
1213/// use drizzle::postgres::prelude::*;
1214///
1215/// #[PostgresTable(name = "users")]
1216/// struct Users {
1217/// #[column(serial, primary)]
1218/// id: i32,
1219/// name: String,
1220/// #[column(unique)]
1221/// email: String,
1222/// age: Option<i32>, // Nullable field
1223/// }
1224///
1225/// #[derive(PostgresSchema)]
1226/// struct Schema {
1227/// users: Users,
1228/// }
1229/// ```
1230///
1231/// ## Enums (Text, Integer, and Native)
1232///
1233/// ```ignore
1234/// use drizzle::postgres::prelude::*;
1235///
1236/// #[derive(PostgresEnum, Default, Clone, PartialEq, Debug)]
1237/// enum Status {
1238/// #[default]
1239/// Draft,
1240/// Published,
1241/// Archived,
1242/// }
1243///
1244/// #[derive(PostgresEnum, Default, Clone, PartialEq, Debug)]
1245/// enum Priority {
1246/// #[default]
1247/// Low,
1248/// Medium,
1249/// High,
1250/// }
1251///
1252/// #[PostgresTable(name = "posts")]
1253/// struct Posts {
1254/// #[column(serial, primary)]
1255/// id: i32,
1256/// title: String,
1257/// #[column(enum)] // Store as TEXT: "Draft", "Published", etc.
1258/// status: Status,
1259/// #[column(enum)] // Native PostgreSQL ENUM type
1260/// priority: Priority,
1261/// }
1262/// ```
1263///
1264/// ## JSON and JSONB
1265///
1266/// ```ignore
1267/// use drizzle::postgres::prelude::*;
1268/// use serde::{Serialize, Deserialize};
1269///
1270/// #[derive(Serialize, Deserialize, Clone, PartialEq, Debug, Default)]
1271/// struct Metadata {
1272/// theme: String,
1273/// notifications: bool,
1274/// }
1275///
1276/// #[PostgresTable(name = "settings")]
1277/// struct Settings {
1278/// #[column(serial, primary)]
1279/// id: i32,
1280/// #[column(JSONB)] // Binary JSON for faster queries
1281/// config: Metadata,
1282/// #[column(JSON)] // Standard JSON
1283/// raw_data: Option<serde_json::Value>,
1284/// }
1285/// ```
1286///
1287/// # Generated Types
1288///
1289/// For a table `Users`, the macro generates:
1290/// - `SelectUsers` - For SELECT operations (derives `FromRow`)
1291/// - `InsertUsers` - Builder for INSERT operations with `new()` and `with_*()` methods
1292/// - `UpdateUsers` - Builder for UPDATE operations with `set_*()` methods
1293///
1294/// # Nullability
1295///
1296/// Use `Option<T>` for nullable fields. Non-optional fields get a NOT NULL constraint.
1297#[cfg(feature = "postgres")]
1298#[allow(non_snake_case)]
1299#[proc_macro_attribute]
1300pub fn PostgresTable(attr: TokenStream, item: TokenStream) -> TokenStream {
1301 let input = syn::parse_macro_input!(item as syn::DeriveInput);
1302 let attr_result = syn::parse_macro_input!(attr as crate::postgres::table::TableAttributes);
1303
1304 match crate::postgres::table::table_attr_macro(input, attr_result) {
1305 Ok(tokens) => tokens.into(),
1306 Err(err) => err.to_compile_error().into(),
1307 }
1308}
1309
1310/// Attribute macro for defining PostgreSQL views.
1311///
1312/// This macro generates a typed view schema with column accessors and view metadata.
1313///
1314/// # Attributes
1315///
1316/// - `name/NAME = "view_name"` - Optional view name (defaults to struct name in snake_case)
1317/// - `schema/SCHEMA = "schema_name"` - Optional schema (defaults to public)
1318/// - `definition/DEFINITION = "SELECT ..."` - View definition SQL
1319/// - `materialized/MATERIALIZED` - Mark as materialized view
1320/// - `with/WITH = ViewWithOptionDef::new()...` - WITH options
1321/// - `with_no_data/WITH_NO_DATA` - Materialized view WITH NO DATA
1322/// - `using/USING = "..."` - USING clause for materialized views
1323/// - `tablespace/TABLESPACE = "..."` - Tablespace for materialized views
1324/// - `existing/EXISTING` - Mark view as existing (skip creation)
1325#[cfg(feature = "postgres")]
1326#[allow(non_snake_case)]
1327#[proc_macro_attribute]
1328pub fn PostgresView(attr: TokenStream, item: TokenStream) -> TokenStream {
1329 let input = syn::parse_macro_input!(item as syn::DeriveInput);
1330 let attr_result = syn::parse_macro_input!(attr as crate::postgres::view::ViewAttributes);
1331
1332 match crate::postgres::view::view_attr_macro(input, attr_result) {
1333 Ok(tokens) => tokens.into(),
1334 Err(err) => err.to_compile_error().into(),
1335 }
1336}
1337
1338/// Attribute macro for creating PostgreSQL indexes.
1339///
1340/// This macro generates PostgreSQL-specific index definitions with support for
1341/// various PostgreSQL index features.
1342///
1343/// # Attributes
1344///
1345/// - `unique` - Create a unique index
1346/// - No attributes for standard index
1347///
1348/// # Examples
1349///
1350/// ## Unique Index
1351///
1352/// ```ignore
1353/// use drizzle::postgres::prelude::*;
1354///
1355/// #[PostgresTable(name = "users")]
1356/// struct Users {
1357/// #[column(serial, primary)]
1358/// id: i32,
1359/// email: String,
1360/// }
1361///
1362/// #[PostgresIndex(unique)]
1363/// struct UserEmailIdx(Users::email);
1364///
1365/// #[derive(PostgresSchema)]
1366/// struct Schema {
1367/// users: Users,
1368/// user_email_idx: UserEmailIdx,
1369/// }
1370/// ```
1371///
1372/// ## Composite Index
1373///
1374/// ```ignore
1375/// use drizzle::postgres::prelude::*;
1376///
1377/// #[PostgresTable(name = "users")]
1378/// struct Users {
1379/// #[column(serial, primary)]
1380/// id: i32,
1381/// email: String,
1382/// organization_id: i32,
1383/// }
1384///
1385/// #[PostgresIndex(unique)]
1386/// struct UserOrgIdx(Users::email, Users::organization_id);
1387/// ```
1388#[cfg(feature = "postgres")]
1389#[allow(non_snake_case)]
1390#[proc_macro_attribute]
1391pub fn PostgresIndex(attr: TokenStream, item: TokenStream) -> TokenStream {
1392 let input = syn::parse_macro_input!(item as syn::DeriveInput);
1393 let attr_input = syn::parse_macro_input!(attr as crate::postgres::index::IndexAttributes);
1394
1395 match crate::postgres::index::postgres_index_attr_macro(attr_input, input) {
1396 Ok(tokens) => tokens.into(),
1397 Err(err) => err.to_compile_error().into(),
1398 }
1399}