Skip to main content

toasty_macros/
lib.rs

1//! Procedural macros for the Toasty ORM.
2//!
3//! This crate provides `#[derive(Model)]`, `#[derive(Embed)]`, and related
4//! attribute macros that generate query builders, schema registration, and
5//! database mapping code.
6
7#![warn(missing_docs)]
8
9extern crate proc_macro;
10
11mod create;
12mod model;
13mod query;
14
15use proc_macro::TokenStream;
16
17/// Derive macro that turns a struct into a Toasty model backed by a database
18/// table.
19///
20/// For a tutorial-style introduction, see the [Toasty guide].
21///
22#[doc = include_str!(concat!(env!("OUT_DIR"), "/guide_link.md"))]
23///
24/// # Overview
25///
26/// Applying `#[derive(Model)]` to a named struct generates:
27///
28/// - A [`Model`] trait implementation, including the associated `Query`,
29///   `Create`, and `Update` builder types.
30/// - A [`Load`] implementation for deserializing rows from the database.
31/// - A [`Register`] implementation for schema registration at runtime.
32/// - Static query methods such as `all()`, `filter(expr)`,
33///   `filter_by_<field>()`, and `get_by_<key>()`.
34/// - Instance methods `update()` and `delete()`.
35/// - A `Fields` struct returned by `<Model>::fields()` for building typed
36///   filter expressions.
37///
38/// The struct must have named fields and no generic parameters.
39///
40/// [`Model`]: toasty::schema::Model
41/// [`Load`]: toasty::schema::Load
42/// [`Register`]: toasty::schema::Register
43///
44/// # Struct-level attributes
45///
46/// ## `#[key(...)]` — primary key
47///
48/// Defines the primary key at the struct level. Mutually exclusive with
49/// field-level `#[key]`.
50///
51/// **Simple form** — every listed field becomes a partition key:
52///
53/// ```
54/// # use toasty::Model;
55/// #[derive(Model)]
56/// #[key(name)]
57/// struct Widget {
58///     name: String,
59///     value: i64,
60/// }
61/// ```
62///
63/// **Composite key with partition/local scoping:**
64///
65/// ```
66/// # use toasty::Model;
67/// #[derive(Model)]
68/// #[key(partition = user_id, local = id)]
69/// struct Todo {
70///     #[auto]
71///     id: uuid::Uuid,
72///     user_id: String,
73///     title: String,
74/// }
75/// ```
76///
77/// The `partition` fields determine data distribution (relevant for
78/// DynamoDB); `local` fields scope within a partition. For SQL databases
79/// both behave as a regular composite primary key.
80///
81/// Multiple `partition` and `local` fields are allowed using bracket syntax:
82///
83/// ```
84/// # use toasty::Model;
85/// # #[derive(Model)]
86/// #[key(partition = [tenant, org], local = [id])]
87/// # struct Example { tenant: String, org: String, id: String }
88/// ```
89///
90/// When using named `partition`/`local` syntax, at least one of each is
91/// required. You cannot mix the simple and named forms.
92///
93/// ## `#[table = "name"]` — custom table name
94///
95/// Overrides the default table name. Without this attribute the table name
96/// is the pluralized, snake_case form of the struct name (e.g. `User` →
97/// `users`).
98///
99/// ```
100/// # use toasty::Model;
101/// #[derive(Model)]
102/// #[table = "legacy_users"]
103/// struct User {
104///     #[key]
105///     #[auto]
106///     id: i64,
107///     name: String,
108/// }
109/// ```
110///
111/// # Field-level attributes
112///
113/// ## `#[key]` — mark a field as a primary key column
114///
115/// Marks one or more fields as the primary key. When used on multiple
116/// fields each becomes a partition key column (equivalent to listing them
117/// in `#[key(...)]` at the struct level).
118///
119/// Cannot be combined with a struct-level `#[key(...)]` attribute.
120///
121/// ```
122/// # use toasty::Model;
123/// #[derive(Model)]
124/// struct User {
125///     #[key]
126///     #[auto]
127///     id: i64,
128///     name: String,
129/// }
130/// ```
131///
132/// ## `#[auto]` — automatic value generation
133///
134/// Tells Toasty to generate this field's value automatically. The strategy
135/// depends on the field type and optional arguments:
136///
137/// | Syntax | Behavior |
138/// |--------|----------|
139/// | `#[auto]` on `uuid::Uuid` | UUID v7 (timestamp-sortable) |
140/// | `#[auto(uuid(v4))]` | UUID v4 (random) |
141/// | `#[auto(uuid(v7))]` | UUID v7 (explicit) |
142/// | `#[auto]` on integer types (`i8`–`i64`, `u8`–`u64`) | Auto-increment |
143/// | `#[auto(increment)]` | Auto-increment (explicit) |
144/// | `#[auto]` on a field named `created_at` | Expands to `#[default(jiff::Timestamp::now())]` |
145/// | `#[auto]` on a field named `updated_at` | Expands to `#[update(jiff::Timestamp::now())]` |
146///
147/// The `created_at`/`updated_at` expansion requires the `jiff` feature and
148/// a field type compatible with `jiff::Timestamp`.
149///
150/// Cannot be combined with `#[default]` or `#[update]` on the same field.
151///
152/// ## `#[default(expr)]` — default value on create
153///
154/// Sets a default value that is used when the field is not explicitly
155/// provided during creation. The expression is any valid Rust expression.
156///
157/// ```
158/// # use toasty::Model;
159/// # #[derive(Model)]
160/// # struct Example {
161/// #     #[key]
162/// #     #[auto]
163/// #     id: i64,
164/// #[default(0)]
165/// view_count: i64,
166///
167/// #[default("draft".to_string())]
168/// status: String,
169/// # }
170/// ```
171///
172/// The default can be overridden by calling the corresponding setter on the
173/// create builder.
174///
175/// Cannot be combined with `#[auto]` on the same field. Can be combined
176/// with `#[update]` (the default applies on create; the update expression
177/// applies on subsequent updates).
178///
179/// ## `#[update(expr)]` — value applied on create and update
180///
181/// Sets a value that Toasty applies every time a record is created or
182/// updated, unless the field is explicitly set on the builder.
183///
184/// ```
185/// # use toasty::Model;
186/// # #[derive(Model)]
187/// # struct Example {
188/// #     #[key]
189/// #     #[auto]
190/// #     id: i64,
191/// #[update(jiff::Timestamp::now())]
192/// updated_at: jiff::Timestamp,
193/// # }
194/// ```
195///
196/// Cannot be combined with `#[auto]` on the same field.
197///
198/// ## `#[index]` — add a database index
199///
200/// Creates a non-unique index on the field. Toasty generates a
201/// `filter_by_<field>` method for indexed fields.
202///
203/// ```
204/// # use toasty::Model;
205/// # #[derive(Model)]
206/// # struct Example {
207/// #     #[key]
208/// #     #[auto]
209/// #     id: i64,
210/// #[index]
211/// email: String,
212/// # }
213/// ```
214///
215/// ## `#[unique]` — add a unique constraint
216///
217/// Creates a unique index on the field. Like `#[index]`, this generates
218/// `filter_by_<field>`. The database enforces uniqueness.
219///
220/// ```
221/// # use toasty::Model;
222/// # #[derive(Model)]
223/// # struct Example {
224/// #     #[key]
225/// #     #[auto]
226/// #     id: i64,
227/// #[unique]
228/// email: String,
229/// # }
230/// ```
231///
232/// ## `#[column(...)]` — customize the database column
233///
234/// Overrides the column name and/or type for a field.
235///
236/// **Custom name:**
237///
238/// ```
239/// # use toasty::Model;
240/// # #[derive(Model)]
241/// # struct Example {
242/// #     #[key]
243/// #     #[auto]
244/// #     id: i64,
245/// #[column("user_email")]
246/// email: String,
247/// # }
248/// ```
249///
250/// **Custom type:**
251///
252/// ```
253/// # use toasty::Model;
254/// # #[derive(Model)]
255/// # struct Example {
256/// #     #[key]
257/// #     #[auto]
258/// #     id: i64,
259/// #[column(type = varchar(255))]
260/// email: String,
261/// # }
262/// ```
263///
264/// **Both:**
265///
266/// ```
267/// # use toasty::Model;
268/// # #[derive(Model)]
269/// # struct Example {
270/// #     #[key]
271/// #     #[auto]
272/// #     id: i64,
273/// #[column("user_email", type = varchar(255))]
274/// email: String,
275/// # }
276/// ```
277///
278/// ### Supported column types
279///
280/// | Syntax | Description |
281/// |--------|-------------|
282/// | `boolean` | Boolean |
283/// | `i8`, `i16`, `i32`, `i64` | Signed integer (1/2/4/8 bytes) |
284/// | `int(N)` | Signed integer with N-byte width |
285/// | `u8`, `u16`, `u32`, `u64` | Unsigned integer (1/2/4/8 bytes) |
286/// | `uint(N)` | Unsigned integer with N-byte width |
287/// | `text` | Unbounded text |
288/// | `varchar(N)` | Text with max length N |
289/// | `numeric` | Arbitrary-precision numeric |
290/// | `numeric(P, S)` | Numeric with precision P and scale S |
291/// | `binary(N)` | Fixed-size binary with N bytes |
292/// | `blob` | Variable-length binary |
293/// | `timestamp(P)` | Timestamp with P fractional-second digits |
294/// | `date` | Date without time |
295/// | `time(P)` | Time with P fractional-second digits |
296/// | `datetime(P)` | Date and time with P fractional-second digits |
297/// | `"custom"` | Arbitrary type string passed through to the driver |
298///
299/// Cannot be used on relation fields.
300///
301/// ## `#[serialize(json)]` — serialize complex types as JSON
302///
303/// Stores the field as a JSON string in the database. Requires the `serde`
304/// feature and that the field type implements `serde::Serialize` and
305/// `serde::Deserialize`.
306///
307/// ```
308/// # use toasty::Model;
309/// # #[derive(Model)]
310/// # struct Example {
311/// #     #[key]
312/// #     #[auto]
313/// #     id: i64,
314/// #[serialize(json)]
315/// tags: Vec<String>,
316/// # }
317/// ```
318///
319/// For `Option<T>` fields, add `nullable` so that `None` maps to SQL
320/// `NULL` rather than the JSON string `"null"`:
321///
322/// ```
323/// # use toasty::Model;
324/// # use std::collections::HashMap;
325/// # #[derive(Model)]
326/// # struct Example {
327/// #     #[key]
328/// #     #[auto]
329/// #     id: i64,
330/// #[serialize(json, nullable)]
331/// metadata: Option<HashMap<String, String>>,
332/// # }
333/// ```
334///
335/// Cannot be used on relation fields.
336///
337/// # Relation attributes
338///
339/// ## `#[belongs_to(...)]` — foreign-key reference
340///
341/// Declares a many-to-one (or one-to-one) association through a foreign
342/// key stored on this model.
343///
344/// ```
345/// # use toasty::Model;
346/// # #[derive(Model)]
347/// # struct User {
348/// #     #[key]
349/// #     #[auto]
350/// #     id: i64,
351/// # }
352/// # #[derive(Model)]
353/// # struct Example {
354/// #     #[key]
355/// #     #[auto]
356/// #     id: i64,
357/// #     user_id: i64,
358/// #[belongs_to(key = user_id, references = id)]
359/// user: toasty::BelongsTo<User>,
360/// # }
361/// ```
362///
363/// | Parameter | Meaning |
364/// |-----------|---------|
365/// | `key = <field>` | Local field holding the foreign key value |
366/// | `references = <field>` | Field on the target model being referenced |
367///
368/// For composite foreign keys, repeat `key`/`references` pairs:
369///
370/// ```
371/// # use toasty::Model;
372/// # #[derive(Model)]
373/// # struct Org {
374/// #     #[key]
375/// #     id: i64,
376/// #     #[key]
377/// #     tenant_id: i64,
378/// # }
379/// # #[derive(Model)]
380/// # struct Example {
381/// #     #[key]
382/// #     #[auto]
383/// #     id: i64,
384/// #     org_id: i64,
385/// #     tenant_id: i64,
386/// #[belongs_to(key = org_id, references = id, key = tenant_id, references = tenant_id)]
387/// org: toasty::BelongsTo<Org>,
388/// # }
389/// ```
390///
391/// The number of `key` entries must equal the number of `references`
392/// entries.
393///
394/// Wrap the target type in `Option` for an optional (nullable) foreign key:
395///
396/// ```
397/// # use toasty::Model;
398/// # #[derive(Model)]
399/// # struct User {
400/// #     #[key]
401/// #     #[auto]
402/// #     id: i64,
403/// # }
404/// # #[derive(Model)]
405/// # struct Example {
406/// #     #[key]
407/// #     #[auto]
408/// #     id: i64,
409/// #[index]
410/// manager_id: Option<i64>,
411///
412/// #[belongs_to(key = manager_id, references = id)]
413/// manager: toasty::BelongsTo<Option<User>>,
414/// # }
415/// ```
416///
417/// ## `#[has_many]` — one-to-many association
418///
419/// Declares a collection of related models. The target model must have a
420/// `#[belongs_to]` field pointing back to this model.
421///
422/// ```
423/// # use toasty::Model;
424/// # #[derive(Model)]
425/// # struct Post {
426/// #     #[key]
427/// #     #[auto]
428/// #     id: i64,
429/// #     #[index]
430/// #     example_id: i64,
431/// #     #[belongs_to(key = example_id, references = id)]
432/// #     example: toasty::BelongsTo<Example>,
433/// # }
434/// # #[derive(Model)]
435/// # struct Example {
436/// #     #[key]
437/// #     #[auto]
438/// #     id: i64,
439/// #[has_many]
440/// posts: toasty::HasMany<Post>,
441/// # }
442/// ```
443///
444/// Toasty generates an accessor method (e.g. `.posts()`) and an insert
445/// helper (e.g. `.insert_post()`), where the insert helper name is the
446/// auto-singularized field name.
447///
448/// ### `pair` — disambiguate self-referential or multiple relations
449///
450/// When the target model has more than one `#[belongs_to]` pointing to
451/// the same model (or points to itself), use `pair` to specify which
452/// `belongs_to` field this `has_many` corresponds to:
453///
454/// ```
455/// # use toasty::Model;
456/// # #[derive(Model)]
457/// # struct Person {
458/// #     #[key]
459/// #     #[auto]
460/// #     id: i64,
461/// #     #[index]
462/// #     parent_id: Option<i64>,
463/// #     #[belongs_to(key = parent_id, references = id)]
464/// #     parent: toasty::BelongsTo<Option<Self>>,
465/// #[has_many(pair = parent)]
466/// children: toasty::HasMany<Person>,
467/// # }
468/// ```
469///
470/// ## `#[has_one]` — one-to-one association
471///
472/// Declares a single related model. The target model must have a
473/// `#[belongs_to]` field pointing back to this model.
474///
475/// ```
476/// # use toasty::Model;
477/// # #[derive(Model)]
478/// # struct Profile {
479/// #     #[key]
480/// #     #[auto]
481/// #     id: i64,
482/// #     #[index]
483/// #     example_id: i64,
484/// #     #[belongs_to(key = example_id, references = id)]
485/// #     example: toasty::BelongsTo<Example>,
486/// # }
487/// # #[derive(Model)]
488/// # struct Example {
489/// #     #[key]
490/// #     #[auto]
491/// #     id: i64,
492/// #[has_one]
493/// profile: toasty::HasOne<Profile>,
494/// # }
495/// ```
496///
497/// Wrap in `Option` for an optional association:
498///
499/// ```
500/// # use toasty::Model;
501/// # #[derive(Model)]
502/// # struct Profile {
503/// #     #[key]
504/// #     #[auto]
505/// #     id: i64,
506/// #     #[index]
507/// #     example_id: i64,
508/// #     #[belongs_to(key = example_id, references = id)]
509/// #     example: toasty::BelongsTo<Example>,
510/// # }
511/// # #[derive(Model)]
512/// # struct Example {
513/// #     #[key]
514/// #     #[auto]
515/// #     id: i64,
516/// #[has_one]
517/// profile: toasty::HasOne<Option<Profile>>,
518/// # }
519/// ```
520///
521/// # Constraints
522///
523/// - The struct must have named fields (tuple structs are not supported).
524/// - Generic parameters are not supported.
525/// - Every root model must have a primary key, defined either by a
526///   struct-level `#[key(...)]` or by one or more field-level `#[key]`
527///   attributes, but not both.
528/// - `#[auto]` cannot be combined with `#[default]` or `#[update]` on the
529///   same field.
530/// - `#[column]`, `#[default]`, `#[update]`, and `#[serialize]` cannot be
531///   used on relation fields (`BelongsTo`, `HasMany`, `HasOne`).
532/// - A field can have at most one relation attribute.
533/// - `Self` can be used as a type in relation fields for self-referential
534///   models.
535///
536/// # Full example
537///
538/// ```
539/// #[derive(Debug, toasty::Model)]
540/// struct User {
541///     #[key]
542///     #[auto]
543///     id: i64,
544///
545///     #[unique]
546///     email: String,
547///
548///     name: String,
549///
550///     #[default(jiff::Timestamp::now())]
551///     created_at: jiff::Timestamp,
552///
553///     #[update(jiff::Timestamp::now())]
554///     updated_at: jiff::Timestamp,
555///
556///     #[has_many]
557///     posts: toasty::HasMany<Post>,
558/// }
559///
560/// #[derive(Debug, toasty::Model)]
561/// struct Post {
562///     #[key]
563///     #[auto]
564///     id: i64,
565///
566///     title: String,
567///
568///     #[serialize(json)]
569///     tags: Vec<String>,
570///
571///     #[index]
572///     user_id: i64,
573///
574///     #[belongs_to(key = user_id, references = id)]
575///     user: toasty::BelongsTo<User>,
576/// }
577/// ```
578#[proc_macro_derive(
579    Model,
580    attributes(
581        key, auto, default, update, column, index, unique, table, has_many, has_one, belongs_to,
582        serialize, version
583    )
584)]
585pub fn derive_model(input: TokenStream) -> TokenStream {
586    match model::generate_model(input.into()) {
587        Ok(output) => output.into(),
588        Err(e) => e.to_compile_error().into(),
589    }
590}
591
592/// Derive macro that turns a struct or enum into an embedded type stored
593/// inline in a parent model's table.
594///
595/// Embedded types do not have their own tables or primary keys. Their
596/// fields are flattened into the parent model's columns. Use `Embed` for
597/// value objects (addresses, coordinates, metadata) and enums
598/// (status codes, contact info variants).
599///
600/// # Structs
601///
602/// An embedded struct's fields become columns in the parent table, prefixed
603/// with the field name. For example, an `address: Address` field with
604/// `street` and `city` produces columns `address_street` and
605/// `address_city`.
606///
607/// ```
608/// #[derive(toasty::Embed)]
609/// struct Address {
610///     street: String,
611///     city: String,
612/// }
613///
614/// #[derive(toasty::Model)]
615/// struct User {
616///     #[key]
617///     #[auto]
618///     id: i64,
619///     name: String,
620///     address: Address,
621/// }
622/// ```
623///
624/// Applying `#[derive(Embed)]` to a struct generates:
625///
626/// - An [`Embed`] trait implementation (which extends [`Register`]).
627/// - A `Fields` struct returned by `<Type>::fields()` for building
628///   filter expressions on individual fields.
629/// - An `Update` struct used by the parent model's update builder for
630///   partial field updates.
631///
632/// ## Nesting
633///
634/// Embedded structs can contain other embedded types. Columns are
635/// flattened with chained prefixes:
636///
637/// ```
638/// #[derive(toasty::Embed)]
639/// struct Location {
640///     lat: i64,
641///     lon: i64,
642/// }
643///
644/// #[derive(toasty::Embed)]
645/// struct Address {
646///     street: String,
647///     city: Location,
648/// }
649/// ```
650///
651/// When `Address` is embedded as `address` in a parent model, this
652/// produces columns `address_street`, `address_city_lat`, and
653/// `address_city_lon`.
654///
655/// # Enums
656///
657/// An embedded enum stores a discriminant value identifying the active
658/// variant. Each variant must have a `#[column(variant = N)]` attribute
659/// assigning a stable integer discriminant.
660///
661/// **Unit-only enum:**
662///
663/// ```
664/// #[derive(toasty::Embed)]
665/// enum Status {
666///     #[column(variant = 1)]
667///     Pending,
668///     #[column(variant = 2)]
669///     Active,
670///     #[column(variant = 3)]
671///     Archived,
672/// }
673/// ```
674///
675/// A unit-only enum occupies a single column in the parent table. The
676/// column stores the discriminant as an integer.
677///
678/// **Data-carrying enum:**
679///
680/// ```
681/// #[derive(toasty::Embed)]
682/// enum ContactInfo {
683///     #[column(variant = 1)]
684///     Email { address: String },
685///     #[column(variant = 2)]
686///     Phone { number: String },
687/// }
688/// ```
689///
690/// A data-carrying enum stores the discriminant column plus one nullable
691/// column per variant field. For example, a `contact: ContactInfo` field
692/// produces columns `contact` (discriminant), `contact_address`, and
693/// `contact_number`. Only the columns belonging to the active variant
694/// contain values; the rest are `NULL`.
695///
696/// **Mixed enum** (unit and data variants together):
697///
698/// ```
699/// #[derive(toasty::Embed)]
700/// enum Status {
701///     #[column(variant = 1)]
702///     Pending,
703///     #[column(variant = 2)]
704///     Failed { reason: String },
705///     #[column(variant = 3)]
706///     Done,
707/// }
708/// ```
709///
710/// Applying `#[derive(Embed)]` to an enum generates:
711///
712/// - An [`Embed`] trait implementation (which extends [`Register`]).
713/// - A `Fields` struct with `is_<variant>()` methods and comparison
714///   methods (`eq`, `ne`, `in_list`).
715/// - For data-carrying variants, per-variant handle types with a
716///   `matches(closure)` method for pattern matching and field access.
717///
718/// # Field-level attributes
719///
720/// ## `#[column(...)]` — customize the database column
721///
722/// **On struct fields**, overrides the column name and/or type:
723///
724/// ```
725/// #[derive(toasty::Embed)]
726/// struct Address {
727///     #[column("addr_street")]
728///     street: String,
729///
730///     #[column(type = varchar(255))]
731///     city: String,
732/// }
733/// ```
734///
735/// See [`Model`][`derive@Model`] for the full list of supported column
736/// types.
737///
738/// **On enum variants**, `#[column(variant = N)]` is **required** and
739/// assigns the integer discriminant stored in the database:
740///
741/// ```
742/// # #[derive(toasty::Embed)]
743/// # enum Example {
744/// #[column(variant = 1)]
745/// Pending,
746/// # }
747/// ```
748///
749/// Discriminant values must be unique across all variants of the enum.
750/// They are stored as `i64`.
751///
752/// ## `#[index]` — add a database index
753///
754/// Creates a non-unique index on the field's flattened column.
755///
756/// ```
757/// #[derive(toasty::Embed)]
758/// struct Contact {
759///     #[index]
760///     country: String,
761/// }
762/// ```
763///
764/// ## `#[unique]` — add a unique constraint
765///
766/// Creates a unique index on the field's flattened column. The database
767/// enforces uniqueness.
768///
769/// ```
770/// #[derive(toasty::Embed)]
771/// struct Contact {
772///     #[unique]
773///     email: String,
774/// }
775/// ```
776///
777/// # Using embedded types in a model
778///
779/// Reference an embedded type as a field on a [`Model`][`derive@Model`]
780/// struct. The parent model's create and update builders gain a setter for
781/// the embedded field. Partial updates of individual sub-fields use
782/// `stmt::patch`:
783///
784/// ```no_run
785/// # #[derive(toasty::Embed)]
786/// # struct Address { street: String, city: String }
787/// # #[derive(toasty::Model)]
788/// # struct User {
789/// #     #[key]
790/// #     #[auto]
791/// #     id: i64,
792/// #     name: String,
793/// #     address: Address,
794/// # }
795/// # async fn example(mut db: toasty::Db, mut user: User) -> toasty::Result<()> {
796/// use toasty::stmt;
797///
798/// // Full replacement
799/// user.update()
800///     .address(Address { street: "456 Oak Ave".into(), city: "Seattle".into() })
801///     .exec(&mut db).await?;
802///
803/// // Partial update — updates city, leaves street unchanged
804/// user.update()
805///     .address(stmt::patch(Address::fields().city(), "Portland"))
806///     .exec(&mut db).await?;
807/// # Ok(())
808/// # }
809/// ```
810///
811/// Embedded struct fields are queryable through the parent model's
812/// `fields()` accessor:
813///
814/// ```no_run
815/// # #[derive(toasty::Embed)]
816/// # struct Address { street: String, city: String }
817/// # #[derive(toasty::Model)]
818/// # struct User {
819/// #     #[key]
820/// #     #[auto]
821/// #     id: i64,
822/// #     name: String,
823/// #     address: Address,
824/// # }
825/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
826/// let users = User::filter(User::fields().address().city().eq("Seattle"))
827///     .exec(&mut db).await?;
828/// # Ok(())
829/// # }
830/// ```
831///
832/// # Constraints
833///
834/// - Embedded structs must have named fields (tuple structs are not
835///   supported).
836/// - Generic parameters are not supported.
837/// - Every enum variant must have a `#[column(variant = N)]` attribute
838///   with a unique discriminant value.
839/// - Enum variants may be unit variants or have named fields. Tuple
840///   variants are not supported.
841/// - Embedded types cannot have primary keys, relations, `#[auto]`,
842///   `#[default]`, `#[update]`, or `#[serialize]` attributes.
843///
844/// # Full example
845///
846/// ```no_run
847/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
848/// #[derive(Debug, PartialEq, toasty::Embed)]
849/// enum Priority {
850///     #[column(variant = 1)]
851///     Low,
852///     #[column(variant = 2)]
853///     Normal,
854///     #[column(variant = 3)]
855///     High,
856/// }
857///
858/// #[derive(Debug, toasty::Embed)]
859/// struct Metadata {
860///     version: i64,
861///     status: String,
862///     priority: Priority,
863/// }
864///
865/// #[derive(Debug, toasty::Model)]
866/// struct Document {
867///     #[key]
868///     #[auto]
869///     id: i64,
870///
871///     title: String,
872///
873///     #[unique]
874///     slug: String,
875///
876///     meta: Metadata,
877/// }
878///
879/// // Create
880/// let mut doc = Document::create()
881///     .title("Design doc")
882///     .slug("design-doc")
883///     .meta(Metadata {
884///         version: 1,
885///         status: "draft".to_string(),
886///         priority: Priority::Normal,
887///     })
888///     .exec(&mut db).await?;
889///
890/// // Query by embedded field
891/// let drafts = Document::filter(
892///     Document::fields().meta().status().eq("draft")
893/// ).exec(&mut db).await?;
894///
895/// // Partial update
896/// use toasty::stmt;
897/// doc.update()
898///     .meta(stmt::apply([
899///         stmt::patch(Metadata::fields().version(), 2),
900///         stmt::patch(Metadata::fields().status(), "published"),
901///     ]))
902///     .exec(&mut db).await?;
903/// # Ok(())
904/// # }
905/// ```
906///
907/// [`Embed`]: toasty::Embed
908/// [`Register`]: toasty::Register
909#[proc_macro_derive(Embed, attributes(column, index, unique))]
910pub fn derive_embed(input: TokenStream) -> TokenStream {
911    match model::generate_embed(input.into()) {
912        Ok(output) => output.into(),
913        Err(e) => e.to_compile_error().into(),
914    }
915}
916
917/// Builds a query using the Toasty query language. The macro expands into
918/// the equivalent method-chain calls on the query builder API. It does
919/// not execute the query — chain `.exec(&mut db).await?` on the result to run
920/// it.
921///
922/// # Syntax
923///
924/// ```text
925/// query!(Source [FILTER expr] [ORDER BY .field ASC|DESC] [OFFSET n] [LIMIT n])
926/// ```
927///
928/// `Source` is a model type path (e.g., `User`). All clauses are optional and
929/// can appear in any combination, but must follow the order shown above when
930/// present. All keywords are case-insensitive: `FILTER`, `filter`, and `Filter`
931/// all work.
932///
933/// # Basic queries
934///
935/// With no clauses, `query!` returns all records of the given model.
936///
937/// ```
938/// # #[derive(toasty::Model)]
939/// # struct User {
940/// #     #[key]
941/// #     id: i64,
942/// #     name: String,
943/// #     age: i64,
944/// #     active: bool,
945/// # }
946/// // Returns all users — expands to User::all()
947/// let _ = toasty::query!(User);
948/// ```
949///
950/// # Filter expressions
951///
952/// The `FILTER` clause accepts an expression built from field comparisons,
953/// boolean operators, and external references.
954///
955/// ## Comparison operators
956///
957/// Dot-prefixed field paths (`.name`, `.age`) refer to fields on the source
958/// model. The right-hand side is a literal or external reference.
959///
960/// | Operator | Expansion         |
961/// |----------|-------------------|
962/// | `==`     | `.eq(val)`        |
963/// | `!=`     | `.ne(val)`        |
964/// | `>`      | `.gt(val)`        |
965/// | `>=`     | `.ge(val)`        |
966/// | `<`      | `.lt(val)`        |
967/// | `<=`     | `.le(val)`        |
968///
969/// ```
970/// # #[derive(toasty::Model)]
971/// # struct User {
972/// #     #[key]
973/// #     id: i64,
974/// #     name: String,
975/// #     age: i64,
976/// #     active: bool,
977/// # }
978/// // Equality — expands to User::filter(User::fields().name().eq("Alice"))
979/// let _ = toasty::query!(User FILTER .name == "Alice");
980///
981/// // Not equal
982/// let _ = toasty::query!(User FILTER .name != "Bob");
983///
984/// // Greater than
985/// let _ = toasty::query!(User FILTER .age > 18);
986///
987/// // Greater than or equal
988/// let _ = toasty::query!(User FILTER .age >= 21);
989///
990/// // Less than
991/// let _ = toasty::query!(User FILTER .age < 65);
992///
993/// // Less than or equal
994/// let _ = toasty::query!(User FILTER .age <= 99);
995/// ```
996///
997/// ## Boolean operators
998///
999/// `AND`, `OR`, and `NOT` combine filter expressions. Precedence follows
1000/// standard boolean logic: `NOT` binds tightest, then `AND`, then `OR`.
1001///
1002/// ```
1003/// # #[derive(toasty::Model)]
1004/// # struct User {
1005/// #     #[key]
1006/// #     id: i64,
1007/// #     name: String,
1008/// #     age: i64,
1009/// #     active: bool,
1010/// # }
1011/// // AND — both conditions must match
1012/// let _ = toasty::query!(User FILTER .name == "Alice" AND .age > 18);
1013///
1014/// // OR — either condition matches
1015/// let _ = toasty::query!(User FILTER .name == "Alice" OR .name == "Bob");
1016///
1017/// // NOT — negates the following expression
1018/// let _ = toasty::query!(User FILTER NOT .active == true);
1019///
1020/// // Combining all three
1021/// let _ = toasty::query!(User FILTER NOT .active == true AND (.name == "Alice" OR .age >= 21));
1022/// ```
1023///
1024/// ## Operator precedence
1025///
1026/// Without parentheses, `NOT` binds tightest, then `AND`, then `OR`. Use
1027/// parentheses to override.
1028///
1029/// ```
1030/// # #[derive(toasty::Model)]
1031/// # struct User {
1032/// #     #[key]
1033/// #     id: i64,
1034/// #     name: String,
1035/// #     age: i64,
1036/// #     active: bool,
1037/// # }
1038/// // Without parens: parsed as (.name == "A" AND .age > 0) OR .active == false
1039/// let _ = toasty::query!(User FILTER .name == "A" AND .age > 0 OR .active == false);
1040///
1041/// // With parens: forces OR to bind first
1042/// let _ = toasty::query!(User FILTER .name == "A" AND (.age > 0 OR .active == false));
1043/// ```
1044///
1045/// ## Boolean and integer literals
1046///
1047/// Boolean fields can be compared against `true` and `false` literals.
1048/// Integer literals work as expected.
1049///
1050/// ```
1051/// # #[derive(toasty::Model)]
1052/// # struct User {
1053/// #     #[key]
1054/// #     id: i64,
1055/// #     name: String,
1056/// #     age: i64,
1057/// #     active: bool,
1058/// # }
1059/// let _ = toasty::query!(User FILTER .active == true);
1060/// let _ = toasty::query!(User FILTER .active == false);
1061/// let _ = toasty::query!(User FILTER .age == 42);
1062/// ```
1063///
1064/// # Referencing surrounding code
1065///
1066/// `#ident` pulls a variable from the surrounding scope. `#(expr)` embeds an
1067/// arbitrary Rust expression.
1068///
1069/// ```
1070/// # #[derive(toasty::Model)]
1071/// # struct User {
1072/// #     #[key]
1073/// #     id: i64,
1074/// #     name: String,
1075/// #     age: i64,
1076/// #     active: bool,
1077/// # }
1078/// // Variable reference — expands to User::filter(User::fields().name().eq(name))
1079/// let name = "Carl";
1080/// let _ = toasty::query!(User FILTER .name == #name);
1081///
1082/// // Expression reference
1083/// fn min_age() -> i64 { 18 }
1084/// let _ = toasty::query!(User FILTER .age > #(min_age()));
1085/// ```
1086///
1087/// # Dot-prefixed field paths
1088///
1089/// A leading `.` starts a field path rooted at the source model's `fields()`
1090/// method. Chained dots navigate multi-segment paths.
1091///
1092/// ```
1093/// # #[derive(toasty::Model)]
1094/// # struct User {
1095/// #     #[key]
1096/// #     id: i64,
1097/// #     name: String,
1098/// #     age: i64,
1099/// #     active: bool,
1100/// # }
1101/// // .name expands to User::fields().name()
1102/// let _ = toasty::query!(User FILTER .name == "Alice");
1103///
1104/// // Multiple fields in a single expression
1105/// let _ = toasty::query!(User FILTER .id == 1 AND .name == "X" AND .age > 0);
1106/// ```
1107///
1108/// # ORDER BY
1109///
1110/// Sort results by a field in ascending (`ASC`) or descending (`DESC`) order.
1111/// If no direction is specified, ascending is the default.
1112///
1113/// ```
1114/// # #[derive(toasty::Model)]
1115/// # struct User {
1116/// #     #[key]
1117/// #     id: i64,
1118/// #     name: String,
1119/// #     age: i64,
1120/// #     active: bool,
1121/// # }
1122/// // Ascending order (explicit)
1123/// let _ = toasty::query!(User ORDER BY .name ASC);
1124///
1125/// // Descending order
1126/// let _ = toasty::query!(User ORDER BY .age DESC);
1127///
1128/// // Combined with filter
1129/// let _ = toasty::query!(User FILTER .active == true ORDER BY .name ASC);
1130/// ```
1131///
1132/// # LIMIT and OFFSET
1133///
1134/// `LIMIT` restricts the number of returned records. `OFFSET` skips a number
1135/// of records before returning. Both accept integer literals, `#ident`
1136/// variables, and `#(expr)` expressions.
1137///
1138/// ```
1139/// # #[derive(toasty::Model)]
1140/// # struct User {
1141/// #     #[key]
1142/// #     id: i64,
1143/// #     name: String,
1144/// #     age: i64,
1145/// #     active: bool,
1146/// # }
1147/// // Return at most 10 records
1148/// let _ = toasty::query!(User LIMIT 10);
1149///
1150/// // Skip 20, then return 10
1151/// let _ = toasty::query!(User OFFSET 20 LIMIT 10);
1152///
1153/// // Variable pagination
1154/// let page_size = 25usize;
1155/// let _ = toasty::query!(User LIMIT #page_size);
1156///
1157/// // Expression pagination
1158/// let _ = toasty::query!(User LIMIT #(5 + 5));
1159/// ```
1160///
1161/// # Combining clauses
1162///
1163/// All clauses can be combined. When present, they must appear in this order:
1164/// `FILTER`, `ORDER BY`, `OFFSET`, `LIMIT`.
1165///
1166/// ```
1167/// # #[derive(toasty::Model)]
1168/// # struct User {
1169/// #     #[key]
1170/// #     id: i64,
1171/// #     name: String,
1172/// #     age: i64,
1173/// #     active: bool,
1174/// # }
1175/// let _ = toasty::query!(User FILTER .active == true ORDER BY .name ASC LIMIT 10);
1176/// let _ = toasty::query!(User FILTER .age > 18 ORDER BY .age DESC OFFSET 0 LIMIT 50);
1177/// ```
1178///
1179/// # Case-insensitive keywords
1180///
1181/// All keywords — `FILTER`, `AND`, `OR`, `NOT`, `ORDER`, `BY`, `ASC`, `DESC`,
1182/// `OFFSET`, `LIMIT` — are matched case-insensitively. Any casing works.
1183///
1184/// ```
1185/// # #[derive(toasty::Model)]
1186/// # struct User {
1187/// #     #[key]
1188/// #     id: i64,
1189/// #     name: String,
1190/// #     age: i64,
1191/// #     active: bool,
1192/// # }
1193/// // These are all equivalent
1194/// let _ = toasty::query!(User FILTER .name == "A");
1195/// let _ = toasty::query!(User filter .name == "A");
1196/// let _ = toasty::query!(User Filter .name == "A");
1197/// ```
1198///
1199/// # Expansion details
1200///
1201/// The macro translates each syntactic element into method-chain calls on the
1202/// query builder.
1203///
1204/// ## No filter
1205///
1206/// ```text
1207/// query!(User)          →  User::all()
1208/// ```
1209///
1210/// ## Filter
1211///
1212/// ```text
1213/// query!(User FILTER .name == "A")
1214///     →  User::filter(User::fields().name().eq("A"))
1215/// ```
1216///
1217/// ## Logical operators
1218///
1219/// ```text
1220/// query!(User FILTER .a == 1 AND .b == 2)
1221///     →  User::filter(User::fields().a().eq(1).and(User::fields().b().eq(2)))
1222///
1223/// query!(User FILTER .a == 1 OR .b == 2)
1224///     →  User::filter(User::fields().a().eq(1).or(User::fields().b().eq(2)))
1225///
1226/// query!(User FILTER NOT .a == 1)
1227///     →  User::filter((User::fields().a().eq(1)).not())
1228/// ```
1229///
1230/// ## ORDER BY
1231///
1232/// ```text
1233/// query!(User ORDER BY .name ASC)
1234///     →  { let mut q = User::all(); q = q.order_by(User::fields().name().asc()); q }
1235/// ```
1236///
1237/// ## LIMIT / OFFSET
1238///
1239/// ```text
1240/// query!(User LIMIT 10)
1241///     →  { let mut q = User::all(); q = q.limit(10); q }
1242///
1243/// query!(User OFFSET 5 LIMIT 10)
1244///     →  { let mut q = User::all(); q = q.limit(10); q = q.offset(5); q }
1245/// ```
1246///
1247/// Note: in the expansion, `limit` is called before `offset` because the
1248/// API requires it.
1249///
1250/// ## External references
1251///
1252/// ```text
1253/// let x = "Carl";
1254/// query!(User FILTER .name == #x)
1255///     →  User::filter(User::fields().name().eq(x))
1256///
1257/// query!(User FILTER .age > #(compute()))
1258///     →  User::filter(User::fields().age().gt(compute()))
1259/// ```
1260///
1261/// # Errors
1262///
1263/// The macro produces compile-time errors for:
1264///
1265/// - **Missing model path**: the first token must be a valid type path.
1266/// - **Unknown fields**: dot-prefixed paths that don't match a field on the
1267///   model produce a type error from the generated `fields()` method.
1268/// - **Type mismatches**: comparing a field to a value of the wrong type
1269///   produces a standard Rust type error (e.g., `.age == "not a number"`).
1270/// - **Unexpected tokens**: tokens after the last recognized clause cause
1271///   `"unexpected tokens after query"`.
1272/// - **Invalid clause order**: placing `FILTER` after `ORDER BY` or `LIMIT`
1273///   before `OFFSET` causes a parse error since the clauses are parsed in
1274///   fixed order.
1275/// - **Missing `BY` after `ORDER`**: writing `ORDER .name` instead of
1276///   `ORDER BY .name` produces `"expected 'BY' after 'ORDER'"`.
1277/// - **Invalid pagination value**: `LIMIT` and `OFFSET` require an integer
1278///   literal, `#variable`, or `#(expression)`.
1279#[proc_macro]
1280pub fn query(input: TokenStream) -> TokenStream {
1281    match query::generate(input.into()) {
1282        Ok(output) => output.into(),
1283        Err(e) => e.to_compile_error().into(),
1284    }
1285}
1286
1287/// Expands struct-literal syntax into create builder method chains. Returns one
1288/// or more create builders — call `.exec(&mut db).await?` to insert the
1289/// record(s).
1290///
1291/// # Syntax forms
1292///
1293/// ## Field syntax
1294///
1295/// Fields inside `{ ... }` can use either explicit or shorthand syntax:
1296///
1297/// - **Explicit:** `field: expr` — sets the field to the given expression.
1298/// - **Shorthand:** `field` — equivalent to `field: field`, using a variable
1299///   with the same name as the field.
1300///
1301/// These can be mixed freely, just like Rust struct literals:
1302///
1303/// ```ignore
1304/// let name = "Alice".to_string();
1305/// toasty::create!(User { name, email: "alice@example.com" })
1306/// ```
1307///
1308/// ## Single creation
1309///
1310/// ```ignore
1311/// toasty::create!(Type { field: value, ... })
1312/// ```
1313///
1314/// Expands to `Type::create().field(value)...` and returns the model's create
1315/// builder (e.g., `UserCreate`).
1316///
1317/// ```no_run
1318/// # #[derive(toasty::Model)]
1319/// # struct User {
1320/// #     #[key]
1321/// #     #[auto]
1322/// #     id: i64,
1323/// #     name: String,
1324/// #     email: String,
1325/// # }
1326/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1327/// let user = toasty::create!(User {
1328///     name: "Alice",
1329///     email: "alice@example.com"
1330/// })
1331/// .exec(&mut db)
1332/// .await?;
1333/// # Ok(())
1334/// # }
1335/// ```
1336///
1337/// ## Scoped creation
1338///
1339/// ```ignore
1340/// toasty::create!(in expr { field: value, ... })
1341/// ```
1342///
1343/// Expands to `expr.create().field(value)...`. Creates a record through a
1344/// relation accessor. The foreign key is set automatically.
1345///
1346/// ```no_run
1347/// # #[derive(toasty::Model)]
1348/// # struct User {
1349/// #     #[key]
1350/// #     #[auto]
1351/// #     id: i64,
1352/// #     name: String,
1353/// #     #[has_many]
1354/// #     todos: toasty::HasMany<Todo>,
1355/// # }
1356/// # #[derive(toasty::Model)]
1357/// # struct Todo {
1358/// #     #[key]
1359/// #     #[auto]
1360/// #     id: i64,
1361/// #     title: String,
1362/// #     #[index]
1363/// #     user_id: i64,
1364/// #     #[belongs_to(key = user_id, references = id)]
1365/// #     user: toasty::BelongsTo<User>,
1366/// # }
1367/// # async fn example(mut db: toasty::Db, user: User) -> toasty::Result<()> {
1368/// let todo = toasty::create!(in user.todos() { title: "buy milk" })
1369///     .exec(&mut db)
1370///     .await?;
1371///
1372/// // todo.user_id == user.id
1373/// # Ok(())
1374/// # }
1375/// ```
1376///
1377/// ## Typed batch
1378///
1379/// ```ignore
1380/// toasty::create!(Type::[ { fields }, { fields }, ... ])
1381/// ```
1382///
1383/// Expands to `toasty::batch([builder1, builder2, ...])` and returns
1384/// `Vec<Type>` when executed:
1385///
1386/// ```no_run
1387/// # #[derive(toasty::Model)]
1388/// # struct User {
1389/// #     #[key]
1390/// #     #[auto]
1391/// #     id: i64,
1392/// #     name: String,
1393/// # }
1394/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1395/// let users = toasty::create!(User::[
1396///     { name: "Alice" },
1397///     { name: "Bob" },
1398/// ])
1399/// .exec(&mut db)
1400/// .await?;
1401/// // users: Vec<User>
1402/// # Ok(())
1403/// # }
1404/// ```
1405///
1406/// ## Tuple
1407///
1408/// ```ignore
1409/// toasty::create!((
1410///     Type1 { fields },
1411///     Type2 { fields },
1412///     ...
1413/// ))
1414/// ```
1415///
1416/// Expands to `toasty::batch((builder1, builder2, ...))` and returns a
1417/// tuple matching the input types:
1418///
1419/// ```no_run
1420/// # #[derive(toasty::Model)]
1421/// # struct User {
1422/// #     #[key]
1423/// #     #[auto]
1424/// #     id: i64,
1425/// #     name: String,
1426/// # }
1427/// # #[derive(toasty::Model)]
1428/// # struct Post {
1429/// #     #[key]
1430/// #     #[auto]
1431/// #     id: i64,
1432/// #     title: String,
1433/// # }
1434/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1435/// let (user, post) = toasty::create!((
1436///     User { name: "Alice" },
1437///     Post { title: "Hello" },
1438/// ))
1439/// .exec(&mut db)
1440/// .await?;
1441/// // (User, Post)
1442/// # Ok(())
1443/// # }
1444/// ```
1445///
1446/// ## Mixed tuple
1447///
1448/// Typed batches and single creates can be mixed inside a tuple:
1449///
1450/// ```no_run
1451/// # #[derive(toasty::Model)]
1452/// # struct User {
1453/// #     #[key]
1454/// #     #[auto]
1455/// #     id: i64,
1456/// #     name: String,
1457/// # }
1458/// # #[derive(toasty::Model)]
1459/// # struct Post {
1460/// #     #[key]
1461/// #     #[auto]
1462/// #     id: i64,
1463/// #     title: String,
1464/// # }
1465/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1466/// let (users, post) = toasty::create!((
1467///     User::[ { name: "Alice" }, { name: "Bob" } ],
1468///     Post { title: "Hello" },
1469/// ))
1470/// .exec(&mut db)
1471/// .await?;
1472/// // (Vec<User>, Post)
1473/// # Ok(())
1474/// # }
1475/// ```
1476///
1477/// # Field values
1478///
1479/// ## Expressions
1480///
1481/// Any Rust expression is valid as a field value — literals, variables, and
1482/// function calls all work. When a variable has the same name as the field,
1483/// you can use the shorthand syntax (just `name` instead of `name: name`):
1484///
1485/// ```
1486/// # #[derive(toasty::Model)]
1487/// # struct User {
1488/// #     #[key]
1489/// #     #[auto]
1490/// #     id: i64,
1491/// #     name: String,
1492/// #     email: String,
1493/// # }
1494/// let name = "Alice";
1495/// let _ = toasty::create!(User { name, email: format!("{}@example.com", name) });
1496/// ```
1497///
1498/// When the variable name differs from the field name, use the explicit
1499/// `field: expr` form:
1500///
1501/// ```
1502/// # #[derive(toasty::Model)]
1503/// # struct User {
1504/// #     #[key]
1505/// #     #[auto]
1506/// #     id: i64,
1507/// #     name: String,
1508/// # }
1509/// let user_name = "Alice";
1510/// let _ = toasty::create!(User { name: user_name });
1511/// ```
1512///
1513/// ## Nested struct (BelongsTo / HasOne)
1514///
1515/// Use `{ ... }` **without** a type prefix to create a related record inline.
1516/// The macro expands the nested fields into a create builder and passes it
1517/// to the field's setter method.
1518///
1519/// ```
1520/// # #[derive(toasty::Model)]
1521/// # struct User {
1522/// #     #[key]
1523/// #     #[auto]
1524/// #     id: i64,
1525/// #     name: String,
1526/// # }
1527/// # #[derive(toasty::Model)]
1528/// # struct Todo {
1529/// #     #[key]
1530/// #     #[auto]
1531/// #     id: i64,
1532/// #     title: String,
1533/// #     #[index]
1534/// #     user_id: i64,
1535/// #     #[belongs_to(key = user_id, references = id)]
1536/// #     user: toasty::BelongsTo<User>,
1537/// # }
1538/// let _ = toasty::create!(Todo {
1539///     title: "buy milk",
1540///     user: { name: "Alice" }
1541/// });
1542/// // Expands to:
1543/// // Todo::create()
1544/// //     .title("buy milk")
1545/// //     .user(Todo::fields().user().create().name("Alice"))
1546/// ```
1547///
1548/// The related record is created first and the foreign key is set
1549/// automatically.
1550///
1551/// ## Nested list (HasMany)
1552///
1553/// Use `[{ ... }, { ... }]` to create multiple related records. The macro
1554/// expands each entry into a create builder and passes them as an array to
1555/// the plural field setter.
1556///
1557/// ```
1558/// # #[derive(toasty::Model)]
1559/// # struct User {
1560/// #     #[key]
1561/// #     #[auto]
1562/// #     id: i64,
1563/// #     name: String,
1564/// #     #[has_many]
1565/// #     todos: toasty::HasMany<Todo>,
1566/// # }
1567/// # #[derive(toasty::Model)]
1568/// # struct Todo {
1569/// #     #[key]
1570/// #     #[auto]
1571/// #     id: i64,
1572/// #     title: String,
1573/// #     #[index]
1574/// #     user_id: i64,
1575/// #     #[belongs_to(key = user_id, references = id)]
1576/// #     user: toasty::BelongsTo<User>,
1577/// # }
1578/// let _ = toasty::create!(User {
1579///     name: "Alice",
1580///     todos: [{ title: "first" }, { title: "second" }]
1581/// });
1582/// // Expands to:
1583/// // User::create()
1584/// //     .name("Alice")
1585/// //     .todos([
1586/// //         User::fields().todos().create().title("first"),
1587/// //         User::fields().todos().create().title("second"),
1588/// //     ])
1589/// ```
1590///
1591/// Items in a nested list can also be plain expressions (e.g., an existing
1592/// builder value).
1593///
1594/// ## Deep nesting
1595///
1596/// Nesting composes to arbitrary depth:
1597///
1598/// ```
1599/// # #[derive(toasty::Model)]
1600/// # struct User {
1601/// #     #[key]
1602/// #     #[auto]
1603/// #     id: i64,
1604/// #     name: String,
1605/// #     #[has_many]
1606/// #     todos: toasty::HasMany<Todo>,
1607/// # }
1608/// # #[derive(toasty::Model)]
1609/// # struct Todo {
1610/// #     #[key]
1611/// #     #[auto]
1612/// #     id: i64,
1613/// #     title: String,
1614/// #     #[index]
1615/// #     user_id: i64,
1616/// #     #[belongs_to(key = user_id, references = id)]
1617/// #     user: toasty::BelongsTo<User>,
1618/// #     #[has_many]
1619/// #     tags: toasty::HasMany<Tag>,
1620/// # }
1621/// # #[derive(toasty::Model)]
1622/// # struct Tag {
1623/// #     #[key]
1624/// #     #[auto]
1625/// #     id: i64,
1626/// #     name: String,
1627/// #     #[index]
1628/// #     todo_id: i64,
1629/// #     #[belongs_to(key = todo_id, references = id)]
1630/// #     todo: toasty::BelongsTo<Todo>,
1631/// # }
1632/// let _ = toasty::create!(User {
1633///     name: "Alice",
1634///     todos: [{
1635///         title: "task",
1636///         tags: [{ name: "urgent" }, { name: "work" }]
1637///     }]
1638/// });
1639/// ```
1640///
1641/// This creates a `User`, then a `Todo` linked to that user, then two `Tag`
1642/// records linked to that todo.
1643///
1644/// # Fields that can be omitted
1645///
1646/// | Field type | Behavior when omitted |
1647/// |---|---|
1648/// | `#[auto]` | Value generated by the database or Toasty |
1649/// | `Option<T>` | Defaults to `None` (`NULL`) |
1650/// | `#[default(expr)]` | Uses the default expression |
1651/// | `#[update(expr)]` | Uses the expression as the initial value |
1652/// | `HasMany<T>` | No related records created |
1653/// | `HasOne<Option<T>>` | No related record created |
1654/// | `BelongsTo<Option<T>>` | Foreign key set to `NULL` |
1655///
1656/// Required fields (`String`, `i64`, non-optional `BelongsTo`, etc.) that are
1657/// missing do not cause a compile-time error. The insert fails at runtime with
1658/// a database constraint violation.
1659///
1660/// # Compile errors
1661///
1662/// **Type prefix on nested struct:**
1663///
1664/// ```compile_fail
1665/// # #[derive(toasty::Model)]
1666/// # struct User {
1667/// #     #[key]
1668/// #     #[auto]
1669/// #     id: i64,
1670/// #     name: String,
1671/// # }
1672/// # #[derive(toasty::Model)]
1673/// # struct Todo {
1674/// #     #[key]
1675/// #     #[auto]
1676/// #     id: i64,
1677/// #     #[index]
1678/// #     user_id: i64,
1679/// #     #[belongs_to(key = user_id, references = id)]
1680/// #     user: toasty::BelongsTo<User>,
1681/// # }
1682/// // Error: remove the type prefix `User` — use `{ ... }` without a type name
1683/// toasty::create!(Todo { user: User { name: "Alice" } })
1684/// ```
1685///
1686/// Correct:
1687///
1688/// ```
1689/// # #[derive(toasty::Model)]
1690/// # struct User {
1691/// #     #[key]
1692/// #     #[auto]
1693/// #     id: i64,
1694/// #     name: String,
1695/// # }
1696/// # #[derive(toasty::Model)]
1697/// # struct Todo {
1698/// #     #[key]
1699/// #     #[auto]
1700/// #     id: i64,
1701/// #     #[index]
1702/// #     user_id: i64,
1703/// #     #[belongs_to(key = user_id, references = id)]
1704/// #     user: toasty::BelongsTo<User>,
1705/// # }
1706/// let _ = toasty::create!(Todo { user: { name: "Alice" } });
1707/// ```
1708///
1709/// Nested struct values infer their type from the field.
1710///
1711/// **Nested lists:**
1712///
1713/// ```compile_fail
1714/// # #[derive(toasty::Model)]
1715/// # struct User {
1716/// #     #[key]
1717/// #     #[auto]
1718/// #     id: i64,
1719/// #     field: String,
1720/// # }
1721/// // Error: nested lists are not supported in create!
1722/// toasty::create!(User { field: [[{ }]] })
1723/// ```
1724///
1725/// **Missing braces or batch bracket:**
1726///
1727/// ```compile_fail
1728/// # #[derive(toasty::Model)]
1729/// # struct User {
1730/// #     #[key]
1731/// #     #[auto]
1732/// #     id: i64,
1733/// # }
1734/// // Error: expected `{` for single creation or `::[` for batch creation after type path
1735/// toasty::create!(User)
1736/// ```
1737///
1738/// # Return type
1739///
1740/// | Form | Returns |
1741/// |---|---|
1742/// | `Type { ... }` | `TypeCreate` (single builder) |
1743/// | `in expr { ... }` | Builder for the relation's model |
1744/// | `Type::[ ... ]` | `Batch` — executes to `Vec<Type>` |
1745/// | `( ... )` | `Batch` — executes to tuple of results |
1746///
1747/// Single and scoped forms return a builder — call `.exec(&mut db).await?`.
1748/// Batch and tuple forms return a `Batch` — also call `.exec(&mut db).await?`.
1749#[proc_macro]
1750pub fn create(input: TokenStream) -> TokenStream {
1751    match create::generate(input.into()) {
1752        Ok(output) => output.into(),
1753        Err(e) => e.to_compile_error().into(),
1754    }
1755}