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 embed_migrations;
13mod model;
14mod query;
15mod update;
16
17use proc_macro::TokenStream;
18
19/// Embeds a Toasty migration directory into the application binary.
20///
21/// With no argument, the macro reads `toasty/` relative to
22/// `CARGO_MANIFEST_DIR`. Pass a string literal to embed a different directory
23/// that contains `history.toml` plus the `migrations/*.sql` files named by
24/// that history. The macro is available through `toasty` when its `migration`
25/// feature is enabled.
26#[proc_macro]
27pub fn embed_migrations(input: TokenStream) -> TokenStream {
28    match embed_migrations::generate(input.into()) {
29        Ok(output) => output.into(),
30        Err(error) => error.to_compile_error().into(),
31    }
32}
33
34/// Derive macro that turns a struct into a Toasty model backed by a database
35/// table.
36///
37/// For a tutorial-style introduction, see the [Toasty guide].
38///
39#[doc = include_str!(concat!(env!("OUT_DIR"), "/guide_link.md"))]
40///
41/// # Overview
42///
43/// Applying `#[derive(Model)]` to a named struct generates:
44///
45/// - A [`Model`] trait implementation, including the associated `Query`,
46///   `Create`, and `Update` builder types.
47/// - A [`Load`] implementation for deserializing rows from the database.
48/// - The [`Model`] trait's schema-registration methods (`id`, `schema`,
49///   `register`) used to register the model at runtime.
50/// - Static query and mutation methods such as `all()`, `filter(expr)`,
51///   `filter_by_<field>()`, `get_by_<key>()`, and `upsert_by_<field>()`.
52/// - Instance methods `update()` and `delete()`.
53/// - A `Fields` struct returned by `<Model>::fields()` for building typed
54///   filter expressions.
55///
56/// The struct must have named fields and no generic parameters.
57///
58/// [`Model`]: toasty::schema::Model
59/// [`Load`]: toasty::schema::Load
60///
61/// # Struct-level attributes
62///
63/// ## `#[key(...)]` — primary key
64///
65/// Defines the primary key at the struct level. Mutually exclusive with
66/// field-level `#[key]`.
67///
68/// Toasty generates an `upsert_by_*` method that takes every primary-key field.
69///
70/// **Simple form** — every listed field becomes a partition key:
71///
72/// ```
73/// # use toasty::Model;
74/// #[derive(Model)]
75/// #[key(name)]
76/// struct Widget {
77///     name: String,
78///     value: i64,
79/// }
80/// ```
81///
82/// **Composite key with partition/local scoping:**
83///
84/// ```
85/// # use toasty::Model;
86/// #[derive(Model)]
87/// #[key(partition = user_id, local = id)]
88/// struct Todo {
89///     #[auto]
90///     id: toasty::stmt::Uuid,
91///     user_id: String,
92///     title: String,
93/// }
94/// ```
95///
96/// The `partition` fields determine data distribution (relevant for
97/// DynamoDB); `local` fields scope within a partition. For SQL databases
98/// both behave as a regular composite primary key.
99///
100/// Multiple `partition` and `local` fields are allowed using bracket syntax:
101///
102/// ```
103/// # use toasty::Model;
104/// # #[derive(Model)]
105/// #[key(partition = [tenant, org], local = [id])]
106/// # struct Example { tenant: String, org: String, id: String }
107/// ```
108///
109/// When using named `partition`/`local` syntax, at least one of each is
110/// required. You cannot mix the simple and named forms.
111///
112/// ## `#[table = "name"]` — custom table name
113///
114/// Overrides the default table name. Without this attribute the table name
115/// is the pluralized, snake_case form of the struct name (e.g. `User` →
116/// `users`).
117///
118/// ```
119/// # use toasty::Model;
120/// #[derive(Model)]
121/// #[table = "legacy_users"]
122/// struct User {
123///     #[key]
124///     #[auto]
125///     id: i64,
126///     name: String,
127/// }
128/// ```
129///
130/// # Field-level attributes
131///
132/// ## `#[key]` — mark a field as a primary key column
133///
134/// Marks one or more fields as the primary key. When used on multiple
135/// fields each becomes a partition key column (equivalent to listing them
136/// in `#[key(...)]` at the struct level).
137///
138/// Toasty generates an `upsert_by_*` method that takes every primary-key field.
139///
140/// Cannot be combined with a struct-level `#[key(...)]` attribute.
141///
142/// ```
143/// # use toasty::Model;
144/// #[derive(Model)]
145/// struct User {
146///     #[key]
147///     #[auto]
148///     id: i64,
149///     name: String,
150/// }
151/// ```
152///
153/// ## `#[auto]` — automatic value generation
154///
155/// Tells Toasty to generate this field's value automatically. The strategy
156/// depends on the field type and optional arguments:
157///
158/// | Syntax | Behavior |
159/// |--------|----------|
160/// | `#[auto]` on `toasty::stmt::Uuid` | UUID v7 (timestamp-sortable) |
161/// | `#[auto(uuid(v4))]` | UUID v4 (random) |
162/// | `#[auto(uuid(v7))]` | UUID v7 (explicit) |
163/// | `#[auto]` on integer types (`i8`–`i64`, `u8`–`u64`) | Auto-increment |
164/// | `#[auto(increment)]` | Auto-increment (explicit) |
165/// | `#[auto]` on a field named `created_at` | Expands to `#[default(toasty::stmt::Timestamp::now())]` |
166/// | `#[auto]` on a field named `updated_at` | Expands to `#[update(toasty::stmt::Timestamp::now())]` |
167///
168/// The `created_at`/`updated_at` expansion requires the `jiff` feature and
169/// a field type compatible with `toasty::stmt::Timestamp`.
170///
171/// Cannot be combined with `#[default]` or `#[update]` on the same field.
172///
173/// ## `#[default(expr)]` — default value on create
174///
175/// Sets a default value that is used when the field is not explicitly
176/// provided during creation or on an upsert's create branch. The expression is
177/// any valid Rust expression.
178///
179/// ```
180/// # use toasty::Model;
181/// # #[derive(Model)]
182/// # struct Example {
183/// #     #[key]
184/// #     #[auto]
185/// #     id: i64,
186/// #[default(0)]
187/// view_count: i64,
188///
189/// #[default("draft".to_string())]
190/// status: String,
191/// # }
192/// ```
193///
194/// The default can be overridden by calling the corresponding setter on the
195/// create builder.
196///
197/// Cannot be combined with `#[auto]` on the same field. Can be combined
198/// with `#[update]` (the default applies on create; the update expression
199/// applies on subsequent updates).
200///
201/// ## `#[update(expr)]` — value applied on create and update
202///
203/// Sets a value that Toasty applies every time a record is created or updated,
204/// including both branches of an upsert, unless the field is explicitly set on
205/// the builder.
206///
207/// ```
208/// # use toasty::Model;
209/// # #[derive(Model)]
210/// # struct Example {
211/// #     #[key]
212/// #     #[auto]
213/// #     id: i64,
214/// #[update(toasty::stmt::Timestamp::now())]
215/// updated_at: toasty::stmt::Timestamp,
216/// # }
217/// ```
218///
219/// Cannot be combined with `#[auto]` on the same field.
220///
221/// ## `#[index]` — add a database index
222///
223/// Creates a non-unique index on the field. Toasty generates a
224/// `filter_by_<field>` method for indexed fields.
225///
226/// ```
227/// # use toasty::Model;
228/// # #[derive(Model)]
229/// # struct Example {
230/// #     #[key]
231/// #     #[auto]
232/// #     id: i64,
233/// #[index]
234/// email: String,
235/// # }
236/// ```
237///
238/// ## `#[unique]` — add a unique constraint
239///
240/// Creates a unique index on the field. Like `#[index]`, this generates
241/// `filter_by_<field>`. It also generates `upsert_by_<field>`, which creates a
242/// record or updates the record selected by this constraint. The database
243/// enforces uniqueness.
244///
245/// ```
246/// # use toasty::Model;
247/// # #[derive(Model)]
248/// # struct Example {
249/// #     #[key]
250/// #     #[auto]
251/// #     id: i64,
252/// #[unique]
253/// email: String,
254/// # }
255/// ```
256///
257/// ## `#[column(...)]` — customize the database column
258///
259/// Overrides the column name and/or type for a field.
260///
261/// **Custom name:**
262///
263/// ```
264/// # use toasty::Model;
265/// # #[derive(Model)]
266/// # struct Example {
267/// #     #[key]
268/// #     #[auto]
269/// #     id: i64,
270/// #[column("user_email")]
271/// email: String,
272/// # }
273/// ```
274///
275/// **Custom type:**
276///
277/// ```
278/// # use toasty::Model;
279/// # #[derive(Model)]
280/// # struct Example {
281/// #     #[key]
282/// #     #[auto]
283/// #     id: i64,
284/// #[column(type = varchar(255))]
285/// email: String,
286/// # }
287/// ```
288///
289/// **Both:**
290///
291/// ```
292/// # use toasty::Model;
293/// # #[derive(Model)]
294/// # struct Example {
295/// #     #[key]
296/// #     #[auto]
297/// #     id: i64,
298/// #[column("user_email", type = varchar(255))]
299/// email: String,
300/// # }
301/// ```
302///
303/// ### Supported column types
304///
305/// | Syntax | Description |
306/// |--------|-------------|
307/// | `boolean` | Boolean |
308/// | `i8`, `i16`, `i32`, `i64` | Signed integer (1/2/4/8 bytes) |
309/// | `int(N)` | Signed integer with N-byte width |
310/// | `u8`, `u16`, `u32`, `u64` | Unsigned integer (1/2/4/8 bytes) |
311/// | `uint(N)` | Unsigned integer with N-byte width |
312/// | `text` | Unbounded text |
313/// | `varchar(N)` | Text with max length N |
314/// | `numeric` | Arbitrary-precision numeric |
315/// | `numeric(P, S)` | Numeric with precision P and scale S |
316/// | `binary(N)` | Fixed-size binary with N bytes |
317/// | `blob` | Variable-length binary |
318/// | `timestamp(P)` | Timestamp with P fractional-second digits |
319/// | `date` | Date without time |
320/// | `time(P)` | Time with P fractional-second digits |
321/// | `datetime(P)` | Date and time with P fractional-second digits |
322/// | `cidr` | IPv4 or IPv6 network prefix |
323/// | `inet` | IPv4 or IPv6 host address with a network prefix |
324/// | `macaddr` | Six-byte IEEE EUI-48 address |
325/// | `macaddr8` | Eight-byte IEEE EUI-64 address |
326/// | `"custom"` | Arbitrary type string passed through to the driver |
327///
328/// Cannot be used on relation fields.
329///
330/// ## JSON-encoded fields via [`Json<T>`](toasty::stmt::Json)
331///
332/// Wrap a serde-typed value in [`toasty::Json<T>`](toasty::stmt::Json) to
333/// serialize it as JSON in the database. Every JSON field must select its
334/// database column type with `#[column(type = ...)]`. Use `text` for
335/// text-backed JSON, `json` for PostgreSQL or MySQL native JSON, and `jsonb`
336/// for PostgreSQL JSONB. JSON fields require the `serde` feature and
337/// `T: serde::Serialize + serde::Deserialize`.
338///
339/// ```
340/// # use toasty::Model;
341/// # #[derive(Model)]
342/// # struct Example {
343/// #     #[key]
344/// #     #[auto]
345/// #     id: i64,
346/// #[column(type = text)]
347/// tags: toasty::Json<Vec<String>>,
348/// # }
349/// ```
350///
351/// Use `serde_json::Value` directly when the field already contains a
352/// dynamic JSON value:
353///
354/// ```
355/// # use toasty::Model;
356/// # use toasty::codegen_support::serde_json;
357/// # #[derive(Model)]
358/// # struct Example {
359/// #     #[key]
360/// #     #[auto]
361/// #     id: i64,
362/// #[column(type = json)]
363/// payload: serde_json::Value,
364/// # }
365/// ```
366///
367/// For nullable JSON columns, wrap `Json<T>` in `Option` — `None` maps to
368/// SQL `NULL`:
369///
370/// ```
371/// # use toasty::Model;
372/// # use std::collections::HashMap;
373/// # #[derive(Model)]
374/// # struct Example {
375/// #     #[key]
376/// #     #[auto]
377/// #     id: i64,
378/// #[column(type = text)]
379/// metadata: Option<toasty::Json<HashMap<String, String>>>,
380/// # }
381/// ```
382///
383/// To instead store `None` as the JSON literal `"null"` (no SQL `NULL`),
384/// wrap the other way: `Json<Option<T>>`.
385///
386/// # Relation attributes
387///
388/// Relation fields can be lazy or eager. Wrap the relation value in
389/// `toasty::Deferred<_>` for lazy loading; ordinary queries leave the field
390/// unloaded until the generated relation accessor or `.include(...)` loads it.
391/// Use the relation value directly for eager loading; every query that returns
392/// the model loads the relation as if the query included that field.
393///
394/// | Attribute | Lazy field type | Eager field type |
395/// |-----------|-----------------|------------------|
396/// | `#[belongs_to]` | `toasty::Deferred<T>` or `toasty::Deferred<Option<T>>` | `T` or `Option<T>` |
397/// | `#[has_many]` | `toasty::Deferred<Vec<T>>` | `Vec<T>` |
398/// | `#[has_one]` | `toasty::Deferred<T>` or `toasty::Deferred<Option<T>>` | `T` or `Option<T>` |
399///
400/// Toasty rejects schemas with eager-load cycles. If two relation paths point
401/// back to each other, wrap at least one field in `toasty::Deferred<_>`.
402///
403/// ## `#[belongs_to(...)]` — foreign-key reference
404///
405/// Declares a many-to-one (or one-to-one) association through a foreign
406/// key stored on this model.
407///
408/// ```
409/// # use toasty::Model;
410/// # #[derive(Model)]
411/// # struct User {
412/// #     #[key]
413/// #     #[auto]
414/// #     id: i64,
415/// # }
416/// # #[derive(Model)]
417/// # struct Example {
418/// #     #[key]
419/// #     #[auto]
420/// #     id: i64,
421/// #     user_id: i64,
422/// #[belongs_to(key = user_id, references = id)]
423/// user: toasty::Deferred<User>,
424/// # }
425/// ```
426///
427/// To load the relation with every `Example` query, omit `Deferred`:
428///
429/// ```ignore
430/// #[belongs_to(key = user_id, references = id)]
431/// user: User,
432/// ```
433///
434/// | Parameter | Meaning |
435/// |-----------|---------|
436/// | `key = <field>` | Local field holding the foreign key value |
437/// | `references = <field>` | Field on the target model being referenced |
438///
439/// For composite foreign keys, pass arrays to `key` and `references`:
440///
441/// ```
442/// # use toasty::Model;
443/// # #[derive(Model)]
444/// # #[key(id, tenant_id)]
445/// # struct Org {
446/// #     id: i64,
447/// #     tenant_id: i64,
448/// # }
449/// # #[derive(Model)]
450/// # struct Example {
451/// #     #[key]
452/// #     #[auto]
453/// #     id: i64,
454/// #     org_id: i64,
455/// #     tenant_id: i64,
456/// #[belongs_to(key = [org_id, tenant_id], references = [id, tenant_id])]
457/// org: toasty::Deferred<Org>,
458/// # }
459/// ```
460///
461/// The number of fields in `key` must equal the number of fields in
462/// `references`.
463///
464/// Wrap the target type in `Option` for an optional (nullable) foreign key:
465///
466/// ```
467/// # use toasty::Model;
468/// # #[derive(Model)]
469/// # struct User {
470/// #     #[key]
471/// #     #[auto]
472/// #     id: i64,
473/// # }
474/// # #[derive(Model)]
475/// # struct Example {
476/// #     #[key]
477/// #     #[auto]
478/// #     id: i64,
479/// #[index]
480/// manager_id: Option<i64>,
481///
482/// #[belongs_to(key = manager_id, references = id)]
483/// manager: toasty::Deferred<Option<User>>,
484/// # }
485/// ```
486///
487/// ## `#[has_many]` — one-to-many association
488///
489/// Declares a collection of related models. The target model must have a
490/// `#[belongs_to]` field pointing back to this model.
491///
492/// ```
493/// # use toasty::Model;
494/// # #[derive(Model)]
495/// # struct Post {
496/// #     #[key]
497/// #     #[auto]
498/// #     id: i64,
499/// #     #[index]
500/// #     example_id: i64,
501/// #     #[belongs_to(key = example_id, references = id)]
502/// #     example: toasty::Deferred<Example>,
503/// # }
504/// # #[derive(Model)]
505/// # struct Example {
506/// #     #[key]
507/// #     #[auto]
508/// #     id: i64,
509/// #[has_many]
510/// posts: toasty::Deferred<Vec<Post>>,
511/// # }
512/// ```
513///
514/// To load the collection with every `Example` query, use `Vec<Post>`:
515///
516/// ```ignore
517/// #[has_many]
518/// posts: Vec<Post>,
519/// ```
520///
521/// Toasty generates an accessor method (e.g. `.posts()`) and an insert
522/// helper (e.g. `.insert_post()`), where the insert helper name is the
523/// auto-singularized field name.
524///
525/// ### `pair` — disambiguate self-referential or multiple relations
526///
527/// When the target model has more than one `#[belongs_to]` pointing to
528/// the same model (or points to itself), use `pair` to specify which
529/// `belongs_to` field this `has_many` corresponds to:
530///
531/// ```
532/// # use toasty::Model;
533/// # #[derive(Model)]
534/// # struct Person {
535/// #     #[key]
536/// #     #[auto]
537/// #     id: i64,
538/// #     #[index]
539/// #     parent_id: Option<i64>,
540/// #     #[belongs_to(key = parent_id, references = id)]
541/// #     parent: toasty::Deferred<Option<Self>>,
542/// #[has_many(pair = parent)]
543/// children: toasty::Deferred<Vec<Person>>,
544/// # }
545/// ```
546///
547/// ### `via` — multi-step relations
548///
549/// Instead of pairing with a `belongs_to`, a `has_many` can reach its target
550/// through a path of existing relations with `via`. The path is a dotted
551/// chain of relation fields, read left to right starting from this model. A
552/// `via` relation owns no foreign key — it is derived from the relations it
553/// traverses — so it takes no `pair`:
554///
555/// ```
556/// # use toasty::Model;
557/// # #[derive(Model)]
558/// # struct Comment {
559/// #     #[key]
560/// #     #[auto]
561/// #     id: i64,
562/// #     #[index]
563/// #     user_id: i64,
564/// #     #[belongs_to(key = user_id, references = id)]
565/// #     user: toasty::Deferred<User>,
566/// #     #[index]
567/// #     article_id: i64,
568/// #     #[belongs_to(key = article_id, references = id)]
569/// #     article: toasty::Deferred<Article>,
570/// # }
571/// # #[derive(Model)]
572/// # struct Article {
573/// #     #[key]
574/// #     #[auto]
575/// #     id: i64,
576/// #     #[has_many]
577/// #     comments: toasty::Deferred<Vec<Comment>>,
578/// # }
579/// # #[derive(Model)]
580/// # struct User {
581/// #     #[key]
582/// #     #[auto]
583/// #     id: i64,
584/// #     #[has_many]
585/// #     comments: toasty::Deferred<Vec<Comment>>,
586/// // User → comments → article
587/// #[has_many(via = comments.article)]
588/// commented_articles: toasty::Deferred<Vec<Article>>,
589/// # }
590/// ```
591///
592/// The target type is `Article` because the path `comments.article` ends
593/// there. A `via` relation is read-only and yields distinct targets — a target
594/// reached through several intermediates appears once. Query, filter, and order
595/// it like any other relation. Preloading it with `.include()` or projecting it
596/// with `.select()` is supported on SQL backends; both are not yet available on
597/// DynamoDB.
598///
599/// #### Many-to-many through a join model
600///
601/// Model a many-to-many relationship with a join model that belongs to both
602/// endpoints. Each endpoint has a direct `has_many` relation to the join model
603/// and a derived `has_many(via = ...)` relation to the opposite endpoint:
604///
605/// ```
606/// # use toasty::Model;
607/// #[derive(Debug, toasty::Model)]
608/// struct User {
609///     #[key]
610///     #[auto]
611///     id: i64,
612///
613///     #[has_many]
614///     memberships: toasty::Deferred<Vec<Membership>>,
615///
616///     #[has_many(via = memberships.group)]
617///     groups: toasty::Deferred<Vec<Group>>,
618/// }
619///
620/// #[derive(Debug, toasty::Model)]
621/// struct Group {
622///     #[key]
623///     #[auto]
624///     id: i64,
625///
626///     #[has_many]
627///     memberships: toasty::Deferred<Vec<Membership>>,
628///
629///     #[has_many(via = memberships.user)]
630///     users: toasty::Deferred<Vec<User>>,
631/// }
632///
633/// #[derive(Debug, toasty::Model)]
634/// #[key(user_id, group_id)]
635/// struct Membership {
636///     #[index]
637///     user_id: i64,
638///
639///     #[belongs_to(key = user_id, references = id)]
640///     user: toasty::Deferred<User>,
641///
642///     #[index]
643///     group_id: i64,
644///
645///     #[belongs_to(key = group_id, references = id)]
646///     group: toasty::Deferred<Group>,
647///
648///     role: String,
649/// }
650/// ```
651///
652/// The composite key prevents duplicate user-group links. Fields such as
653/// `role` belong on the join model because they describe one connection. The
654/// derived `groups` and `users` relations return distinct endpoints and are
655/// read-only; create, update, or delete `Membership` records to change links.
656/// Call `.any()` on a derived field to filter by the opposite endpoint, or on
657/// `memberships` to filter by join-model fields. Traversing, filtering,
658/// preloading, or projecting the derived `via` fields requires a SQL backend.
659///
660/// ## `#[has_one]` — one-to-one association
661///
662/// Declares a single related model. The target model must have a
663/// `#[belongs_to]` field pointing back to this model.
664///
665/// ```
666/// # use toasty::Model;
667/// # #[derive(Model)]
668/// # struct Profile {
669/// #     #[key]
670/// #     #[auto]
671/// #     id: i64,
672/// #     #[index]
673/// #     example_id: i64,
674/// #     #[belongs_to(key = example_id, references = id)]
675/// #     example: toasty::Deferred<Example>,
676/// # }
677/// # #[derive(Model)]
678/// # struct Example {
679/// #     #[key]
680/// #     #[auto]
681/// #     id: i64,
682/// #[has_one]
683/// profile: toasty::Deferred<Profile>,
684/// # }
685/// ```
686///
687/// To load the relation with every `Example` query, omit `Deferred`:
688///
689/// ```ignore
690/// #[has_one]
691/// profile: Profile,
692/// ```
693///
694/// Wrap in `Option` for an optional association:
695///
696/// ```
697/// # use toasty::Model;
698/// # #[derive(Model)]
699/// # struct Profile {
700/// #     #[key]
701/// #     #[auto]
702/// #     id: i64,
703/// #     #[index]
704/// #     example_id: i64,
705/// #     #[belongs_to(key = example_id, references = id)]
706/// #     example: toasty::Deferred<Example>,
707/// # }
708/// # #[derive(Model)]
709/// # struct Example {
710/// #     #[key]
711/// #     #[auto]
712/// #     id: i64,
713/// #[has_one]
714/// profile: toasty::Deferred<Option<Profile>>,
715/// # }
716/// ```
717///
718/// The eager optional form is `Option<Profile>`.
719///
720/// ### `via` — multi-step relations
721///
722/// Like `#[has_many]`, a `#[has_one]` can reach its target through a path of
723/// existing relations with `via` (see the `#[has_many]` `via` section above for
724/// the full rules). Declare it when the path is expected to reach at most one
725/// target:
726///
727/// ```
728/// # use toasty::Model;
729/// # #[derive(Model)]
730/// # struct Subscription {
731/// #     #[key]
732/// #     #[auto]
733/// #     id: i64,
734/// #     #[unique]
735/// #     account_id: Option<i64>,
736/// #     #[belongs_to(key = account_id, references = id)]
737/// #     account: toasty::Deferred<Option<Account>>,
738/// # }
739/// # #[derive(Model)]
740/// # struct Account {
741/// #     #[key]
742/// #     #[auto]
743/// #     id: i64,
744/// #     #[unique]
745/// #     user_id: Option<i64>,
746/// #     #[belongs_to(key = user_id, references = id)]
747/// #     user: toasty::Deferred<Option<User>>,
748/// #     #[has_one]
749/// #     subscription: toasty::Deferred<Option<Subscription>>,
750/// # }
751/// # #[derive(Model)]
752/// # struct User {
753/// #     #[key]
754/// #     #[auto]
755/// #     id: i64,
756/// #     #[has_one]
757/// #     account: toasty::Deferred<Option<Account>>,
758/// // User → account → subscription
759/// #[has_one(via = account.subscription)]
760/// subscription: toasty::Deferred<Option<Subscription>>,
761/// # }
762/// ```
763///
764/// # Constraints
765///
766/// - The struct must have named fields (tuple structs are not supported).
767/// - Generic parameters are not supported.
768/// - Every root model must have a primary key, defined either by a
769///   struct-level `#[key(...)]` or by one or more field-level `#[key]`
770///   attributes, but not both.
771/// - `#[auto]` cannot be combined with `#[default]` or `#[update]` on the
772///   same field.
773/// - `#[column]`, `#[default]`, and `#[update]` cannot be used on relation
774///   fields (`BelongsTo`, `HasMany`, `HasOne`).
775/// - A field can have at most one relation attribute.
776/// - Eager relation fields cannot form a cycle. Use `toasty::Deferred<_>` on at
777///   least one edge of a bidirectional relation.
778/// - `Self` can be used as a type in relation fields for self-referential
779///   models.
780///
781/// # Full example
782///
783/// ```
784/// #[derive(Debug, toasty::Model)]
785/// struct User {
786///     #[key]
787///     #[auto]
788///     id: i64,
789///
790///     #[unique]
791///     email: String,
792///
793///     name: String,
794///
795///     #[default(toasty::stmt::Timestamp::now())]
796///     created_at: toasty::stmt::Timestamp,
797///
798///     #[update(toasty::stmt::Timestamp::now())]
799///     updated_at: toasty::stmt::Timestamp,
800///
801///     #[has_many]
802///     posts: toasty::Deferred<Vec<Post>>,
803/// }
804///
805/// #[derive(Debug, toasty::Model)]
806/// struct Post {
807///     #[key]
808///     #[auto]
809///     id: i64,
810///
811///     title: String,
812///
813///     #[column(type = text)]
814///     tags: toasty::Json<Vec<String>>,
815///
816///     #[index]
817///     user_id: i64,
818///
819///     #[belongs_to(key = user_id, references = id)]
820///     user: toasty::Deferred<User>,
821/// }
822/// ```
823#[proc_macro_derive(
824    Model,
825    attributes(
826        key, auto, default, update, column, index, unique, table, has_many, has_one, belongs_to,
827        version, shared, document
828    )
829)]
830pub fn derive_model(input: TokenStream) -> TokenStream {
831    match model::generate_model(input.into()) {
832        Ok(output) => output.into(),
833        Err(e) => e.to_compile_error().into(),
834    }
835}
836
837/// Derive macro that turns a struct or enum into an embedded type stored
838/// inline in a parent model's table.
839///
840/// Embedded types do not have their own tables or primary keys. Their
841/// fields are flattened into the parent model's columns. Use `Embed` for
842/// value objects (addresses, coordinates, metadata) and enums
843/// (status codes, contact info variants).
844///
845/// # Structs
846///
847/// An embedded struct's fields become columns in the parent table, prefixed
848/// with the field name. For example, an `address: Address` field with
849/// `street` and `city` produces columns `address_street` and
850/// `address_city`.
851///
852/// ```
853/// #[derive(toasty::Embed)]
854/// struct Address {
855///     street: String,
856///     city: String,
857/// }
858///
859/// #[derive(toasty::Model)]
860/// struct User {
861///     #[key]
862///     #[auto]
863///     id: i64,
864///     name: String,
865///     address: Address,
866/// }
867/// ```
868///
869/// Applying `#[derive(Embed)]` to a struct generates:
870///
871/// - An [`Embed`] trait implementation (`id` and `schema` methods).
872/// - A `Fields` struct returned by `<Type>::fields()` for building
873///   filter expressions on individual fields.
874/// - An `Update` struct used by the parent model's update builder for
875///   partial field updates.
876///
877/// A field accessor is named after the field it reads. A newtype's field is
878/// unnamed, so its accessor is `inner()`. It returns a path to the single
879/// column the newtype maps to, which compares against the wrapped type:
880///
881/// ```
882/// #[derive(toasty::Embed)]
883/// struct Email(String);
884///
885/// #[derive(toasty::Model)]
886/// struct User {
887///     #[key]
888///     #[auto]
889///     id: i64,
890///     email: Email,
891/// }
892///
893/// let query = User::filter(User::fields().email().inner().eq("alice@example.com"));
894/// ```
895///
896/// Multi-field structs do not get the ordering methods — multi-column
897/// values have no ordering shared across backends:
898///
899/// ```compile_fail
900/// # #[derive(toasty::Embed)]
901/// # struct Point {
902/// #     x: i64,
903/// #     y: i64,
904/// # }
905/// # #[derive(toasty::Model)]
906/// # struct Pin {
907/// #     #[key]
908/// #     #[auto]
909/// #     id: i64,
910/// #     location: Point,
911/// # }
912/// // Error: no method `ge` on the fields struct of a multi-field embed
913/// let _ = Pin::filter(Pin::fields().location().ge(Point { x: 0, y: 0 }));
914/// ```
915///
916/// The same applies to sorting — `asc`/`desc` exist only on newtype fields:
917///
918/// ```compile_fail
919/// # #[derive(toasty::Embed)]
920/// # struct Point {
921/// #     x: i64,
922/// #     y: i64,
923/// # }
924/// # #[derive(toasty::Model)]
925/// # struct Pin {
926/// #     #[key]
927/// #     #[auto]
928/// #     id: i64,
929/// #     location: Point,
930/// # }
931/// // Error: no method `asc` on the fields struct of a multi-field embed
932/// let _ = Pin::all().order_by(Pin::fields().location().asc());
933/// ```
934///
935/// A tuple-newtype can wrap a non-indexable type, but the wrapper can only
936/// participate in an index when its inner type can. Toasty checks that
937/// requirement when a model uses the wrapper in an index or unique constraint.
938///
939/// ```compile_fail
940/// # #[derive(toasty::Embed)]
941/// # struct Point {
942/// #     x: i64,
943/// #     y: i64,
944/// # }
945/// #[derive(toasty::Embed)]
946/// struct Outer(Point);
947/// # #[derive(toasty::Model)]
948/// # struct Pin {
949/// #     #[key]
950/// #     id: i64,
951/// #     #[index]
952/// #     location: Outer,
953/// # }
954/// ```
955///
956/// ## Nesting
957///
958/// Embedded structs can contain other embedded types. Columns are
959/// flattened with chained prefixes:
960///
961/// ```
962/// #[derive(toasty::Embed)]
963/// struct Location {
964///     lat: i64,
965///     lon: i64,
966/// }
967///
968/// #[derive(toasty::Embed)]
969/// struct Address {
970///     street: String,
971///     city: Location,
972/// }
973/// ```
974///
975/// When `Address` is embedded as `address` in a parent model, this
976/// produces columns `address_street`, `address_city_lat`, and
977/// `address_city_lon`.
978///
979/// # Enums
980///
981/// An embedded enum stores a discriminant value identifying the active
982/// variant. By default, Toasty derives a string label for each variant by
983/// converting its Rust name to `snake_case`. Use
984/// `#[column(rename_all = "...")]` on the enum to select another naming
985/// convention, or `#[column(variant = "...")]` on a variant to set one label.
986///
987/// **Unit-only enum:**
988///
989/// ```
990/// #[derive(toasty::Embed)]
991/// enum Status {
992///     Pending,
993///     InProgress,
994///     Archived,
995/// }
996/// ```
997///
998/// A unit-only enum occupies a single column in the parent table. The
999/// example stores the labels `pending`, `in_progress`, and `archived`.
1000///
1001/// **Data-carrying enum:**
1002///
1003/// ```
1004/// #[derive(toasty::Embed)]
1005/// enum ContactInfo {
1006///     Email { address: String },
1007///     Phone { number: String },
1008/// }
1009/// ```
1010///
1011/// A data-carrying enum stores the discriminant column plus one nullable
1012/// column per variant field. For example, a `contact: ContactInfo` field
1013/// produces columns `contact` (discriminant), `contact_address`, and
1014/// `contact_number`. Only the columns belonging to the active variant
1015/// contain values; the rest are `NULL`.
1016///
1017/// **Mixed enum** (unit and data variants together):
1018///
1019/// ```
1020/// #[derive(toasty::Embed)]
1021/// enum Status {
1022///     Pending,
1023///     Failed { reason: String },
1024///     Done,
1025/// }
1026/// ```
1027///
1028/// Applying `#[derive(Embed)]` to an enum generates:
1029///
1030/// - An [`Embed`] trait implementation (`id` and `schema` methods).
1031/// - A `Fields` struct with `is_<variant>()` methods and comparison
1032///   methods (`eq`, `ne`, `in_list`).
1033/// - For data-carrying variants, per-variant handle types with a
1034///   `matches(closure)` method for pattern matching and field access.
1035///
1036/// # Newtype `Auto` proxying
1037///
1038/// A tuple-newtype embedded struct (one unnamed field) automatically
1039/// implements `Auto` whenever its inner type does — no annotation
1040/// required. Toasty emits a `NewtypeOf` marker carrying the inner type
1041/// and a blanket `Auto` impl resolves through it:
1042///
1043/// ```
1044/// #[derive(toasty::Embed)]
1045/// struct UserId(toasty::stmt::Uuid);
1046///
1047/// #[derive(toasty::Model)]
1048/// struct User {
1049///     #[key]
1050///     #[auto]
1051///     id: UserId,
1052///     name: String,
1053/// }
1054/// ```
1055///
1056/// Newtypes wrapping non-`Auto` types stay non-`Auto`; nesting works
1057/// transparently (`Outer(Inner(u64))` proxies through both layers).
1058///
1059/// # Attributes
1060///
1061/// ## `#[column(...)]` — customize the database column
1062///
1063/// **On struct fields**, overrides the column name and/or type:
1064///
1065/// ```
1066/// #[derive(toasty::Embed)]
1067/// struct Address {
1068///     #[column("addr_street")]
1069///     street: String,
1070///
1071///     #[column(type = varchar(255))]
1072///     city: String,
1073/// }
1074/// ```
1075///
1076/// See [`Model`][`derive@Model`] for the full list of supported column
1077/// types.
1078///
1079/// **Changing stored enum discriminants.** On an enum,
1080/// `#[column(rename_all = "...")]` changes how Toasty derives string labels
1081/// for variants without an explicit label:
1082///
1083/// ```
1084/// #[derive(toasty::Embed)]
1085/// #[column(rename_all = "SCREAMING_SNAKE_CASE")]
1086/// enum PartyKind {
1087///     Customer,
1088///     PreferredSupplier,
1089/// }
1090/// ```
1091///
1092/// This example uses the labels `CUSTOMER` and `PREFERRED_SUPPLIER`. Without
1093/// `rename_all`, Toasty uses `snake_case`.
1094///
1095/// The supported rules and their result for `PreferredSupplier` are:
1096///
1097/// | Rule | Label |
1098/// | --- | --- |
1099/// | `lowercase` | `preferredsupplier` |
1100/// | `UPPERCASE` | `PREFERREDSUPPLIER` |
1101/// | `PascalCase` | `PreferredSupplier` |
1102/// | `camelCase` | `preferredSupplier` |
1103/// | `snake_case` | `preferred_supplier` |
1104/// | `SCREAMING_SNAKE_CASE` | `PREFERRED_SUPPLIER` |
1105/// | `kebab-case` | `preferred-supplier` |
1106/// | `SCREAMING-KEBAB-CASE` | `PREFERRED-SUPPLIER` |
1107///
1108/// Use `#[column(variant = "...")]` to set individual labels:
1109///
1110/// ```
1111/// #[derive(toasty::Embed)]
1112/// enum PartyKind {
1113///     #[column(variant = "customer")]
1114///     Customer,
1115///     #[column(variant = "preferred-supplier")]
1116///     PreferredSupplier,
1117/// }
1118/// ```
1119///
1120/// An explicit variant label takes precedence over `rename_all` when an enum
1121/// uses both attributes.
1122///
1123/// String-label enums use Toasty's enum storage by default. Use
1124/// `#[column(type = enum("type_name"))]` to set the database enum type name,
1125/// or `#[column(type = text)]` or `#[column(type = varchar(N))]` to use a
1126/// plain string column. `rename_all` changes variant labels only; it does not
1127/// change the enum type name.
1128///
1129/// To store integers instead, assign an integer to every variant:
1130///
1131/// ```
1132/// #[derive(toasty::Embed)]
1133/// enum Priority {
1134///     #[column(variant = 10)]
1135///     Low,
1136///     #[column(variant = 20)]
1137///     High,
1138/// }
1139/// ```
1140///
1141/// An enum cannot mix string and integer discriminants. Integer discriminants
1142/// use `i64` storage by default. Add an integer enum-level override such as
1143/// `#[column(type = u8)]` to request narrower storage. The type applies to
1144/// flattened discriminant columns, through transparent field wrappers, and to
1145/// each element of `Vec<unit-enum>`. The same attribute on a model field
1146/// overrides the enum default for that use; on a collection it selects the
1147/// element type. Every discriminant must fit the selected type. Enum embeds
1148/// inside `#[document]` fields are not supported. Integer-discriminant enums do
1149/// not support `rename_all`. All discriminant values must be unique. String
1150/// labels may contain at most 63 bytes.
1151///
1152/// ## `#[index]` — add a database index
1153///
1154/// Creates a non-unique index on the field's flattened column.
1155///
1156/// ```
1157/// #[derive(toasty::Embed)]
1158/// struct Contact {
1159///     #[index]
1160///     country: String,
1161/// }
1162/// ```
1163///
1164/// ## `#[unique]` — add a unique constraint
1165///
1166/// Creates a unique index on the field's flattened column. The database
1167/// enforces uniqueness.
1168///
1169/// ```
1170/// #[derive(toasty::Embed)]
1171/// struct Contact {
1172///     #[unique]
1173///     email: String,
1174/// }
1175/// ```
1176///
1177/// ## `#[shared(ident)]` — share a column across enum variants
1178///
1179/// Declares a shared logical field on the enum. Variant fields declaring
1180/// the same identifier are backed by a single nullable column instead of
1181/// one column per variant. The identifier — not the Rust field names,
1182/// which may differ per variant — names the field: the column name derives
1183/// from it (`{enum_field}_{ident}`), and enum-level `#[index]` /
1184/// `#[unique]` attributes reference it.
1185///
1186/// ```
1187/// #[derive(toasty::Embed)]
1188/// enum Creature {
1189///     #[column(variant = 1)]
1190///     Human {
1191///         #[shared(name)]
1192///         full_name: String,
1193///         profession: String,
1194///     },
1195///     #[column(variant = 2)]
1196///     Animal {
1197///         #[shared(name)]
1198///         nickname: String,
1199///         species: String,
1200///     },
1201/// }
1202/// // Columns: creature, creature_name (shared), creature_profession,
1203/// // creature_species
1204/// ```
1205///
1206/// Fields sharing an identifier must have the same type. To rename the
1207/// shared column, add `#[column("...")]` to any one member of the group
1208/// (if several declare it, they must agree):
1209///
1210/// ```
1211/// # #[derive(toasty::Embed)]
1212/// # enum Example {
1213/// # #[column(variant = 1)]
1214/// # V {
1215/// #[shared(name)]
1216/// #[column("legacy_name")]
1217/// name: String,
1218/// # },
1219/// # }
1220/// ```
1221///
1222/// ## Enum-level `#[index(...)]` / `#[unique(...)]`
1223///
1224/// On the enum itself, `#[index(...)]` and `#[unique(...)]` create an
1225/// index over variant-field columns. Each reference is a shared field
1226/// identifier or a `variant::field` path naming a variant field that owns
1227/// its column; the two forms compose into composite indices.
1228///
1229/// ```
1230/// #[derive(toasty::Embed)]
1231/// #[unique(name)]
1232/// #[index(name, human::profession)]
1233/// enum Creature {
1234///     #[column(variant = 1)]
1235///     Human {
1236///         #[shared(name)]
1237///         name: String,
1238///         profession: String,
1239///     },
1240///     #[column(variant = 2)]
1241///     Animal {
1242///         #[shared(name)]
1243///         name: String,
1244///     },
1245/// }
1246/// ```
1247///
1248/// An index on a shared column covers rows of **every** variant: with
1249/// `#[unique(name)]` above, a `Human` named "Bob" and an `Animal` named
1250/// "Bob" conflict. Rows of variants that do not declare the shared field
1251/// store `NULL` and never conflict. For this reason, field-level
1252/// `#[index]` / `#[unique]` on a `#[shared]` field is a compile error
1253/// pointing at the enum-level form.
1254///
1255/// ## `#[belongs_to(...)]` — relations stored in embedded types
1256///
1257/// A field of an embedded struct or enum variant may declare
1258/// `#[belongs_to]`, with the same parameters as the model-level attribute
1259/// (see [`Model`][`derive@Model`]). The differences:
1260///
1261/// - `key` references a sibling field of the same struct or variant.
1262/// - The field type must be `toasty::Deferred<..>`; the always-loaded
1263///   form is not supported.
1264/// - There is no `.include()`: load the referenced model with an
1265///   ordinary `get_by_*` / `find_by_*` on the stored key.
1266/// - Writes set the key field explicitly and leave the relation unloaded
1267///   (`Deferred::default()`); setting it from a model value is not
1268///   supported.
1269/// - A `has_many` on the target cannot pair with it.
1270///
1271/// ```no_run
1272/// # #[derive(Debug, toasty::Model)]
1273/// # struct Human {
1274/// #     #[key]
1275/// #     #[auto]
1276/// #     id: toasty::stmt::Uuid,
1277/// # }
1278/// #[derive(Debug, toasty::Embed)]
1279/// enum Owner {
1280///     Human {
1281///         #[index]
1282///         id: toasty::stmt::Uuid,
1283///         #[belongs_to(key = id)]
1284///         human: toasty::Deferred<Human>,
1285///     },
1286///     // ... other owner kinds
1287/// }
1288/// ```
1289///
1290/// # Using embedded types in a model
1291///
1292/// Reference an embedded type as a field on a [`Model`][`derive@Model`]
1293/// struct. The parent model's create and update builders gain a setter for
1294/// the embedded field. Partial updates of individual sub-fields use
1295/// `stmt::patch`:
1296///
1297/// ```no_run
1298/// # #[derive(toasty::Embed)]
1299/// # struct Address { street: String, city: String }
1300/// # #[derive(toasty::Model)]
1301/// # struct User {
1302/// #     #[key]
1303/// #     #[auto]
1304/// #     id: i64,
1305/// #     name: String,
1306/// #     address: Address,
1307/// # }
1308/// # async fn example(mut db: toasty::Db, mut user: User) -> toasty::Result<()> {
1309/// use toasty::stmt;
1310///
1311/// // Full replacement
1312/// user.update()
1313///     .address(Address { street: "456 Oak Ave".into(), city: "Seattle".into() })
1314///     .exec(&mut db).await?;
1315///
1316/// // Partial update — updates city, leaves street unchanged
1317/// user.update()
1318///     .address(stmt::patch(Address::fields().city(), "Portland"))
1319///     .exec(&mut db).await?;
1320/// # Ok(())
1321/// # }
1322/// ```
1323///
1324/// Embedded struct fields are queryable through the parent model's
1325/// `fields()` accessor:
1326///
1327/// ```no_run
1328/// # #[derive(toasty::Embed)]
1329/// # struct Address { street: String, city: String }
1330/// # #[derive(toasty::Model)]
1331/// # struct User {
1332/// #     #[key]
1333/// #     #[auto]
1334/// #     id: i64,
1335/// #     name: String,
1336/// #     address: Address,
1337/// # }
1338/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1339/// let users = User::filter(User::fields().address().city().eq("Seattle"))
1340///     .exec(&mut db).await?;
1341/// # Ok(())
1342/// # }
1343/// ```
1344///
1345/// # Constraints
1346///
1347/// - Embedded structs must have named fields (tuple structs are not
1348///   supported).
1349/// - Generic parameters are not supported.
1350/// - Enum discriminants must all be strings or all be integers. Integer
1351///   discriminants must be specified on every variant.
1352/// - `#[column(rename_all = "...")]` applies only to string labels.
1353/// - Enum variants may be unit variants or have named fields. Tuple
1354///   variants are not supported.
1355/// - Embedded types cannot have primary keys, `has_many` / `has_one`
1356///   relations, `#[auto]`, `#[default]`, or `#[update]` attributes.
1357///   `#[belongs_to]` is supported; the field must be
1358///   `toasty::Deferred<..>`.
1359///
1360/// # Full example
1361///
1362/// ```no_run
1363/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1364/// #[derive(Debug, PartialEq, toasty::Embed)]
1365/// #[column(rename_all = "SCREAMING_SNAKE_CASE")]
1366/// enum Priority {
1367///     Low,
1368///     Normal,
1369///     High,
1370/// }
1371///
1372/// #[derive(Debug, toasty::Embed)]
1373/// struct Metadata {
1374///     version: i64,
1375///     status: String,
1376///     priority: Priority,
1377/// }
1378///
1379/// #[derive(Debug, toasty::Model)]
1380/// struct Document {
1381///     #[key]
1382///     #[auto]
1383///     id: i64,
1384///
1385///     title: String,
1386///
1387///     #[unique]
1388///     slug: String,
1389///
1390///     meta: Metadata,
1391/// }
1392///
1393/// // Create
1394/// let mut doc = Document::create()
1395///     .title("Design doc")
1396///     .slug("design-doc")
1397///     .meta(Metadata {
1398///         version: 1,
1399///         status: "draft".to_string(),
1400///         priority: Priority::Normal,
1401///     })
1402///     .exec(&mut db).await?;
1403///
1404/// // Query by embedded field
1405/// let drafts = Document::filter(
1406///     Document::fields().meta().status().eq("draft")
1407/// ).exec(&mut db).await?;
1408///
1409/// // Partial update
1410/// use toasty::stmt;
1411/// doc.update()
1412///     .meta(stmt::apply([
1413///         stmt::patch(Metadata::fields().version(), 2),
1414///         stmt::patch(Metadata::fields().status(), "published"),
1415///     ]))
1416///     .exec(&mut db).await?;
1417/// # Ok(())
1418/// # }
1419/// ```
1420///
1421/// [`Embed`]: toasty::Embed
1422#[proc_macro_derive(Embed, attributes(belongs_to, column, document, index, unique, shared))]
1423pub fn derive_embed(input: TokenStream) -> TokenStream {
1424    match model::generate_embed(input.into()) {
1425        Ok(output) => output.into(),
1426        Err(e) => e.to_compile_error().into(),
1427    }
1428}
1429
1430/// Builds a query using the Toasty query language. The macro expands into
1431/// the equivalent method-chain calls on the query builder API. It does
1432/// not execute the query — chain `.exec(&mut db).await?` on the result to run
1433/// it.
1434///
1435/// # Syntax
1436///
1437/// ```text
1438/// query!(Source [FILTER expr] [ORDER BY .field ASC|DESC] [OFFSET n] [LIMIT n])
1439/// ```
1440///
1441/// `Source` is a model type path (e.g., `User`). All clauses are optional and
1442/// can appear in any combination, but must follow the order shown above when
1443/// present. All keywords are case-insensitive: `FILTER`, `filter`, and `Filter`
1444/// all work.
1445///
1446/// # Basic queries
1447///
1448/// With no clauses, `query!` returns all records of the given model.
1449///
1450/// ```
1451/// # #[derive(toasty::Model)]
1452/// # struct User {
1453/// #     #[key]
1454/// #     id: i64,
1455/// #     name: String,
1456/// #     age: i64,
1457/// #     active: bool,
1458/// # }
1459/// // Returns all users — expands to User::all()
1460/// let _ = toasty::query!(User);
1461/// ```
1462///
1463/// # Filter expressions
1464///
1465/// The `FILTER` clause accepts an expression built from field comparisons,
1466/// boolean operators, and external references.
1467///
1468/// ## Comparison operators
1469///
1470/// Dot-prefixed field paths (`.name`, `.age`) refer to fields on the source
1471/// model. The right-hand side is a literal or external reference.
1472///
1473/// | Operator | Expansion         |
1474/// |----------|-------------------|
1475/// | `==`     | `.eq(val)`        |
1476/// | `!=`     | `.ne(val)`        |
1477/// | `>`      | `.gt(val)`        |
1478/// | `>=`     | `.ge(val)`        |
1479/// | `<`      | `.lt(val)`        |
1480/// | `<=`     | `.le(val)`        |
1481///
1482/// ```
1483/// # #[derive(toasty::Model)]
1484/// # struct User {
1485/// #     #[key]
1486/// #     id: i64,
1487/// #     name: String,
1488/// #     age: i64,
1489/// #     active: bool,
1490/// # }
1491/// // Equality — expands to User::filter(User::fields().name().eq("Alice"))
1492/// let _ = toasty::query!(User FILTER .name == "Alice");
1493///
1494/// // Not equal
1495/// let _ = toasty::query!(User FILTER .name != "Bob");
1496///
1497/// // Greater than
1498/// let _ = toasty::query!(User FILTER .age > 18);
1499///
1500/// // Greater than or equal
1501/// let _ = toasty::query!(User FILTER .age >= 21);
1502///
1503/// // Less than
1504/// let _ = toasty::query!(User FILTER .age < 65);
1505///
1506/// // Less than or equal
1507/// let _ = toasty::query!(User FILTER .age <= 99);
1508/// ```
1509///
1510/// ## Boolean operators
1511///
1512/// `AND`, `OR`, and `NOT` combine filter expressions. Precedence follows
1513/// standard boolean logic: `NOT` binds tightest, then `AND`, then `OR`.
1514///
1515/// ```
1516/// # #[derive(toasty::Model)]
1517/// # struct User {
1518/// #     #[key]
1519/// #     id: i64,
1520/// #     name: String,
1521/// #     age: i64,
1522/// #     active: bool,
1523/// # }
1524/// // AND — both conditions must match
1525/// let _ = toasty::query!(User FILTER .name == "Alice" AND .age > 18);
1526///
1527/// // OR — either condition matches
1528/// let _ = toasty::query!(User FILTER .name == "Alice" OR .name == "Bob");
1529///
1530/// // NOT — negates the following expression
1531/// let _ = toasty::query!(User FILTER NOT .active == true);
1532///
1533/// // Combining all three
1534/// let _ = toasty::query!(User FILTER NOT .active == true AND (.name == "Alice" OR .age >= 21));
1535/// ```
1536///
1537/// ## Operator precedence
1538///
1539/// Without parentheses, `NOT` binds tightest, then `AND`, then `OR`. Use
1540/// parentheses to override.
1541///
1542/// ```
1543/// # #[derive(toasty::Model)]
1544/// # struct User {
1545/// #     #[key]
1546/// #     id: i64,
1547/// #     name: String,
1548/// #     age: i64,
1549/// #     active: bool,
1550/// # }
1551/// // Without parens: parsed as (.name == "A" AND .age > 0) OR .active == false
1552/// let _ = toasty::query!(User FILTER .name == "A" AND .age > 0 OR .active == false);
1553///
1554/// // With parens: forces OR to bind first
1555/// let _ = toasty::query!(User FILTER .name == "A" AND (.age > 0 OR .active == false));
1556/// ```
1557///
1558/// ## Boolean and integer literals
1559///
1560/// Boolean fields can be compared against `true` and `false` literals.
1561/// Integer literals work as expected.
1562///
1563/// ```
1564/// # #[derive(toasty::Model)]
1565/// # struct User {
1566/// #     #[key]
1567/// #     id: i64,
1568/// #     name: String,
1569/// #     age: i64,
1570/// #     active: bool,
1571/// # }
1572/// let _ = toasty::query!(User FILTER .active == true);
1573/// let _ = toasty::query!(User FILTER .active == false);
1574/// let _ = toasty::query!(User FILTER .age == 42);
1575/// ```
1576///
1577/// # Referencing surrounding code
1578///
1579/// `#ident` pulls a variable from the surrounding scope. `#(expr)` embeds an
1580/// arbitrary Rust expression.
1581///
1582/// ```
1583/// # #[derive(toasty::Model)]
1584/// # struct User {
1585/// #     #[key]
1586/// #     id: i64,
1587/// #     name: String,
1588/// #     age: i64,
1589/// #     active: bool,
1590/// # }
1591/// // Variable reference — expands to User::filter(User::fields().name().eq(name))
1592/// let name = "Carl";
1593/// let _ = toasty::query!(User FILTER .name == #name);
1594///
1595/// // Expression reference
1596/// fn min_age() -> i64 { 18 }
1597/// let _ = toasty::query!(User FILTER .age > #(min_age()));
1598/// ```
1599///
1600/// # Dot-prefixed field paths
1601///
1602/// A leading `.` starts a field path rooted at the source model's `fields()`
1603/// method. Chained dots navigate multi-segment paths.
1604///
1605/// ```
1606/// # #[derive(toasty::Model)]
1607/// # struct User {
1608/// #     #[key]
1609/// #     id: i64,
1610/// #     name: String,
1611/// #     age: i64,
1612/// #     active: bool,
1613/// # }
1614/// // .name expands to User::fields().name()
1615/// let _ = toasty::query!(User FILTER .name == "Alice");
1616///
1617/// // Multiple fields in a single expression
1618/// let _ = toasty::query!(User FILTER .id == 1 AND .name == "X" AND .age > 0);
1619/// ```
1620///
1621/// # ORDER BY
1622///
1623/// Sort results by a field in ascending (`ASC`) or descending (`DESC`) order.
1624/// If no direction is specified, ascending is the default.
1625///
1626/// ```
1627/// # #[derive(toasty::Model)]
1628/// # struct User {
1629/// #     #[key]
1630/// #     id: i64,
1631/// #     name: String,
1632/// #     age: i64,
1633/// #     active: bool,
1634/// # }
1635/// // Ascending order (explicit)
1636/// let _ = toasty::query!(User ORDER BY .name ASC);
1637///
1638/// // Descending order
1639/// let _ = toasty::query!(User ORDER BY .age DESC);
1640///
1641/// // Combined with filter
1642/// let _ = toasty::query!(User FILTER .active == true ORDER BY .name ASC);
1643/// ```
1644///
1645/// # LIMIT and OFFSET
1646///
1647/// `LIMIT` restricts the number of returned records. `OFFSET` skips a number
1648/// of records before returning. Both accept integer literals, `#ident`
1649/// variables, and `#(expr)` expressions.
1650///
1651/// ```
1652/// # #[derive(toasty::Model)]
1653/// # struct User {
1654/// #     #[key]
1655/// #     id: i64,
1656/// #     name: String,
1657/// #     age: i64,
1658/// #     active: bool,
1659/// # }
1660/// // Return at most 10 records
1661/// let _ = toasty::query!(User LIMIT 10);
1662///
1663/// // Skip 20, then return 10
1664/// let _ = toasty::query!(User OFFSET 20 LIMIT 10);
1665///
1666/// // Variable pagination
1667/// let page_size = 25usize;
1668/// let _ = toasty::query!(User LIMIT #page_size);
1669///
1670/// // Expression pagination
1671/// let _ = toasty::query!(User LIMIT #(5 + 5));
1672/// ```
1673///
1674/// # Combining clauses
1675///
1676/// All clauses can be combined. When present, they must appear in this order:
1677/// `FILTER`, `ORDER BY`, `OFFSET`, `LIMIT`.
1678///
1679/// ```
1680/// # #[derive(toasty::Model)]
1681/// # struct User {
1682/// #     #[key]
1683/// #     id: i64,
1684/// #     name: String,
1685/// #     age: i64,
1686/// #     active: bool,
1687/// # }
1688/// let _ = toasty::query!(User FILTER .active == true ORDER BY .name ASC LIMIT 10);
1689/// let _ = toasty::query!(User FILTER .age > 18 ORDER BY .age DESC OFFSET 0 LIMIT 50);
1690/// ```
1691///
1692/// # Case-insensitive keywords
1693///
1694/// All keywords — `FILTER`, `AND`, `OR`, `NOT`, `ORDER`, `BY`, `ASC`, `DESC`,
1695/// `OFFSET`, `LIMIT` — are matched case-insensitively. Any casing works.
1696///
1697/// ```
1698/// # #[derive(toasty::Model)]
1699/// # struct User {
1700/// #     #[key]
1701/// #     id: i64,
1702/// #     name: String,
1703/// #     age: i64,
1704/// #     active: bool,
1705/// # }
1706/// // These are all equivalent
1707/// let _ = toasty::query!(User FILTER .name == "A");
1708/// let _ = toasty::query!(User filter .name == "A");
1709/// let _ = toasty::query!(User Filter .name == "A");
1710/// ```
1711///
1712/// # Expansion details
1713///
1714/// The macro translates each syntactic element into method-chain calls on the
1715/// query builder.
1716///
1717/// ## No filter
1718///
1719/// ```text
1720/// query!(User)          →  User::all()
1721/// ```
1722///
1723/// ## Filter
1724///
1725/// ```text
1726/// query!(User FILTER .name == "A")
1727///     →  User::filter(User::fields().name().eq("A"))
1728/// ```
1729///
1730/// ## Logical operators
1731///
1732/// ```text
1733/// query!(User FILTER .a == 1 AND .b == 2)
1734///     →  User::filter(User::fields().a().eq(1).and(User::fields().b().eq(2)))
1735///
1736/// query!(User FILTER .a == 1 OR .b == 2)
1737///     →  User::filter(User::fields().a().eq(1).or(User::fields().b().eq(2)))
1738///
1739/// query!(User FILTER NOT .a == 1)
1740///     →  User::filter((User::fields().a().eq(1)).not())
1741/// ```
1742///
1743/// ## ORDER BY
1744///
1745/// ```text
1746/// query!(User ORDER BY .name ASC)
1747///     →  { let mut q = User::all(); q = q.order_by(User::fields().name().asc()); q }
1748/// ```
1749///
1750/// ## LIMIT / OFFSET
1751///
1752/// ```text
1753/// query!(User LIMIT 10)
1754///     →  { let mut q = User::all(); q = q.limit(10); q }
1755///
1756/// query!(User OFFSET 5 LIMIT 10)
1757///     →  { let mut q = User::all(); q = q.limit(10); q = q.offset(5); q }
1758/// ```
1759///
1760/// Note: in the expansion, `limit` is called before `offset` because the
1761/// API requires it.
1762///
1763/// ## External references
1764///
1765/// ```text
1766/// let x = "Carl";
1767/// query!(User FILTER .name == #x)
1768///     →  User::filter(User::fields().name().eq(x))
1769///
1770/// query!(User FILTER .age > #(compute()))
1771///     →  User::filter(User::fields().age().gt(compute()))
1772/// ```
1773///
1774/// # Errors
1775///
1776/// The macro produces compile-time errors for:
1777///
1778/// - **Missing model path**: the first token must be a valid type path.
1779/// - **Unknown fields**: dot-prefixed paths that don't match a field on the
1780///   model produce a type error from the generated `fields()` method.
1781/// - **Type mismatches**: comparing a field to a value of the wrong type
1782///   produces a standard Rust type error (e.g., `.age == "not a number"`).
1783/// - **Unexpected tokens**: tokens after the last recognized clause cause
1784///   `"unexpected tokens after query"`.
1785/// - **Invalid clause order**: placing `FILTER` after `ORDER BY` or `LIMIT`
1786///   before `OFFSET` causes a parse error since the clauses are parsed in
1787///   fixed order.
1788/// - **Missing `BY` after `ORDER`**: writing `ORDER .name` instead of
1789///   `ORDER BY .name` produces `"expected 'BY' after 'ORDER'"`.
1790/// - **Invalid pagination value**: `LIMIT` and `OFFSET` require an integer
1791///   literal, `#variable`, or `#(expression)`.
1792#[proc_macro]
1793pub fn query(input: TokenStream) -> TokenStream {
1794    match query::generate(input.into()) {
1795        Ok(output) => output.into(),
1796        Err(e) => e.to_compile_error().into(),
1797    }
1798}
1799
1800/// Expands struct-literal syntax into create builder method chains. Returns one
1801/// or more create builders — call `.exec(&mut db).await?` to insert the
1802/// record(s).
1803///
1804/// # Syntax forms
1805///
1806/// ## Field syntax
1807///
1808/// Fields inside `{ ... }` can use either explicit or shorthand syntax:
1809///
1810/// - **Explicit:** `field: expr` — sets the field to the given expression.
1811/// - **Shorthand:** `field` — equivalent to `field: field`, using a variable
1812///   with the same name as the field.
1813///
1814/// These can be mixed freely, just like Rust struct literals:
1815///
1816/// ```ignore
1817/// let name = "Alice".to_string();
1818/// toasty::create!(User { name, email: "alice@example.com" })
1819/// ```
1820///
1821/// ## Single creation
1822///
1823/// ```ignore
1824/// toasty::create!(Type { field: value, ... })
1825/// ```
1826///
1827/// Expands to `Type::create().field(value)...` and returns the model's create
1828/// builder (e.g., `UserCreate`).
1829///
1830/// ```no_run
1831/// # #[derive(toasty::Model)]
1832/// # struct User {
1833/// #     #[key]
1834/// #     #[auto]
1835/// #     id: i64,
1836/// #     name: String,
1837/// #     email: String,
1838/// # }
1839/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1840/// let user = toasty::create!(User {
1841///     name: "Alice",
1842///     email: "alice@example.com"
1843/// })
1844/// .exec(&mut db)
1845/// .await?;
1846/// # Ok(())
1847/// # }
1848/// ```
1849///
1850/// ## Scoped creation
1851///
1852/// ```ignore
1853/// toasty::create!(in expr { field: value, ... })
1854/// ```
1855///
1856/// Expands to `expr.create().field(value)...`. Creates a record through a
1857/// relation accessor. The foreign key is set automatically.
1858///
1859/// ```no_run
1860/// # #[derive(toasty::Model)]
1861/// # struct User {
1862/// #     #[key]
1863/// #     #[auto]
1864/// #     id: i64,
1865/// #     name: String,
1866/// #     #[has_many]
1867/// #     todos: toasty::Deferred<Vec<Todo>>,
1868/// # }
1869/// # #[derive(toasty::Model)]
1870/// # struct Todo {
1871/// #     #[key]
1872/// #     #[auto]
1873/// #     id: i64,
1874/// #     title: String,
1875/// #     #[index]
1876/// #     user_id: i64,
1877/// #     #[belongs_to(key = user_id, references = id)]
1878/// #     user: toasty::Deferred<User>,
1879/// # }
1880/// # async fn example(mut db: toasty::Db, user: User) -> toasty::Result<()> {
1881/// let todo = toasty::create!(in user.todos() { title: "buy milk" })
1882///     .exec(&mut db)
1883///     .await?;
1884///
1885/// // todo.user_id == user.id
1886/// # Ok(())
1887/// # }
1888/// ```
1889///
1890/// ## Typed batch
1891///
1892/// ```ignore
1893/// toasty::create!(Type::[ { fields }, { fields }, ... ])
1894/// ```
1895///
1896/// Expands to `toasty::batch([builder1, builder2, ...])` and returns
1897/// `Vec<Type>` when executed:
1898///
1899/// ```no_run
1900/// # #[derive(toasty::Model)]
1901/// # struct User {
1902/// #     #[key]
1903/// #     #[auto]
1904/// #     id: i64,
1905/// #     name: String,
1906/// # }
1907/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1908/// let users = toasty::create!(User::[
1909///     { name: "Alice" },
1910///     { name: "Bob" },
1911/// ])
1912/// .exec(&mut db)
1913/// .await?;
1914/// // users: Vec<User>
1915/// # Ok(())
1916/// # }
1917/// ```
1918///
1919/// ## Tuple
1920///
1921/// ```ignore
1922/// toasty::create!((
1923///     Type1 { fields },
1924///     Type2 { fields },
1925///     ...
1926/// ))
1927/// ```
1928///
1929/// Expands to `toasty::batch((builder1, builder2, ...))` and returns a
1930/// tuple matching the input types:
1931///
1932/// ```no_run
1933/// # #[derive(toasty::Model)]
1934/// # struct User {
1935/// #     #[key]
1936/// #     #[auto]
1937/// #     id: i64,
1938/// #     name: String,
1939/// # }
1940/// # #[derive(toasty::Model)]
1941/// # struct Post {
1942/// #     #[key]
1943/// #     #[auto]
1944/// #     id: i64,
1945/// #     title: String,
1946/// # }
1947/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1948/// let (user, post) = toasty::create!((
1949///     User { name: "Alice" },
1950///     Post { title: "Hello" },
1951/// ))
1952/// .exec(&mut db)
1953/// .await?;
1954/// // (User, Post)
1955/// # Ok(())
1956/// # }
1957/// ```
1958///
1959/// ## Mixed tuple
1960///
1961/// Typed batches and single creates can be mixed inside a tuple:
1962///
1963/// ```no_run
1964/// # #[derive(toasty::Model)]
1965/// # struct User {
1966/// #     #[key]
1967/// #     #[auto]
1968/// #     id: i64,
1969/// #     name: String,
1970/// # }
1971/// # #[derive(toasty::Model)]
1972/// # struct Post {
1973/// #     #[key]
1974/// #     #[auto]
1975/// #     id: i64,
1976/// #     title: String,
1977/// # }
1978/// # async fn example(mut db: toasty::Db) -> toasty::Result<()> {
1979/// let (users, post) = toasty::create!((
1980///     User::[ { name: "Alice" }, { name: "Bob" } ],
1981///     Post { title: "Hello" },
1982/// ))
1983/// .exec(&mut db)
1984/// .await?;
1985/// // (Vec<User>, Post)
1986/// # Ok(())
1987/// # }
1988/// ```
1989///
1990/// # Field values
1991///
1992/// ## Expressions
1993///
1994/// Any Rust expression is valid as a field value — literals, variables, and
1995/// function calls all work. When a variable has the same name as the field,
1996/// you can use the shorthand syntax (just `name` instead of `name: name`):
1997///
1998/// ```
1999/// # #[derive(toasty::Model)]
2000/// # struct User {
2001/// #     #[key]
2002/// #     #[auto]
2003/// #     id: i64,
2004/// #     name: String,
2005/// #     email: String,
2006/// # }
2007/// let name = "Alice";
2008/// let _ = toasty::create!(User { name, email: format!("{}@example.com", name) });
2009/// ```
2010///
2011/// When the variable name differs from the field name, use the explicit
2012/// `field: expr` form:
2013///
2014/// ```
2015/// # #[derive(toasty::Model)]
2016/// # struct User {
2017/// #     #[key]
2018/// #     #[auto]
2019/// #     id: i64,
2020/// #     name: String,
2021/// # }
2022/// let user_name = "Alice";
2023/// let _ = toasty::create!(User { name: user_name });
2024/// ```
2025///
2026/// ## Nested struct (BelongsTo / HasOne)
2027///
2028/// Use `{ ... }` **without** a type prefix to create a related record inline.
2029/// The macro expands the nested fields into a create builder and passes it
2030/// to the field's setter method.
2031///
2032/// ```
2033/// # #[derive(toasty::Model)]
2034/// # struct User {
2035/// #     #[key]
2036/// #     #[auto]
2037/// #     id: i64,
2038/// #     name: String,
2039/// # }
2040/// # #[derive(toasty::Model)]
2041/// # struct Todo {
2042/// #     #[key]
2043/// #     #[auto]
2044/// #     id: i64,
2045/// #     title: String,
2046/// #     #[index]
2047/// #     user_id: i64,
2048/// #     #[belongs_to(key = user_id, references = id)]
2049/// #     user: toasty::Deferred<User>,
2050/// # }
2051/// let _ = toasty::create!(Todo {
2052///     title: "buy milk",
2053///     user: { name: "Alice" }
2054/// });
2055/// // Expands to:
2056/// // Todo::create()
2057/// //     .title("buy milk")
2058/// //     .user(Todo::fields().user().create().name("Alice"))
2059/// ```
2060///
2061/// The related record is created first and the foreign key is set
2062/// automatically.
2063///
2064/// ## Nested list (HasMany)
2065///
2066/// Use `[{ ... }, { ... }]` to create multiple related records. The macro
2067/// expands each entry into a create builder and passes them as an array to
2068/// the plural field setter.
2069///
2070/// ```
2071/// # #[derive(toasty::Model)]
2072/// # struct User {
2073/// #     #[key]
2074/// #     #[auto]
2075/// #     id: i64,
2076/// #     name: String,
2077/// #     #[has_many]
2078/// #     todos: toasty::Deferred<Vec<Todo>>,
2079/// # }
2080/// # #[derive(toasty::Model)]
2081/// # struct Todo {
2082/// #     #[key]
2083/// #     #[auto]
2084/// #     id: i64,
2085/// #     title: String,
2086/// #     #[index]
2087/// #     user_id: i64,
2088/// #     #[belongs_to(key = user_id, references = id)]
2089/// #     user: toasty::Deferred<User>,
2090/// # }
2091/// let _ = toasty::create!(User {
2092///     name: "Alice",
2093///     todos: [{ title: "first" }, { title: "second" }]
2094/// });
2095/// // Expands to:
2096/// // User::create()
2097/// //     .name("Alice")
2098/// //     .todos([
2099/// //         User::fields().todos().create().title("first"),
2100/// //         User::fields().todos().create().title("second"),
2101/// //     ])
2102/// ```
2103///
2104/// Items in a nested list can also be plain expressions (e.g., an existing
2105/// builder value).
2106///
2107/// ## Deep nesting
2108///
2109/// Nesting composes to arbitrary depth:
2110///
2111/// ```
2112/// # #[derive(toasty::Model)]
2113/// # struct User {
2114/// #     #[key]
2115/// #     #[auto]
2116/// #     id: i64,
2117/// #     name: String,
2118/// #     #[has_many]
2119/// #     todos: toasty::Deferred<Vec<Todo>>,
2120/// # }
2121/// # #[derive(toasty::Model)]
2122/// # struct Todo {
2123/// #     #[key]
2124/// #     #[auto]
2125/// #     id: i64,
2126/// #     title: String,
2127/// #     #[index]
2128/// #     user_id: i64,
2129/// #     #[belongs_to(key = user_id, references = id)]
2130/// #     user: toasty::Deferred<User>,
2131/// #     #[has_many]
2132/// #     tags: toasty::Deferred<Vec<Tag>>,
2133/// # }
2134/// # #[derive(toasty::Model)]
2135/// # struct Tag {
2136/// #     #[key]
2137/// #     #[auto]
2138/// #     id: i64,
2139/// #     name: String,
2140/// #     #[index]
2141/// #     todo_id: i64,
2142/// #     #[belongs_to(key = todo_id, references = id)]
2143/// #     todo: toasty::Deferred<Todo>,
2144/// # }
2145/// let _ = toasty::create!(User {
2146///     name: "Alice",
2147///     todos: [{
2148///         title: "task",
2149///         tags: [{ name: "urgent" }, { name: "work" }]
2150///     }]
2151/// });
2152/// ```
2153///
2154/// This creates a `User`, then a `Todo` linked to that user, then two `Tag`
2155/// records linked to that todo.
2156///
2157/// # Fields that can be omitted
2158///
2159/// | Field type | Behavior when omitted |
2160/// |---|---|
2161/// | `#[auto]` | Value generated by the database or Toasty |
2162/// | `Option<T>` | Defaults to `None` (`NULL`) |
2163/// | `#[default(expr)]` | Uses the default expression |
2164/// | `#[update(expr)]` | Uses the expression as the initial value |
2165/// | `#[has_many] Deferred<Vec<T>>` or `#[has_many] Vec<T>` | No related records created |
2166/// | `#[has_one] Deferred<Option<T>>` or `#[has_one] Option<T>` | No related record created |
2167/// | `#[belongs_to] Deferred<Option<T>>` or `#[belongs_to] Option<T>` | Foreign key set to `NULL` |
2168///
2169/// Required fields (`String`, `i64`, non-optional `BelongsTo`, etc.) that are
2170/// missing do not cause a compile-time error. The insert fails at runtime with
2171/// a database constraint violation.
2172///
2173/// # Compile errors
2174///
2175/// **Type prefix on nested struct:**
2176///
2177/// ```compile_fail
2178/// # #[derive(toasty::Model)]
2179/// # struct User {
2180/// #     #[key]
2181/// #     #[auto]
2182/// #     id: i64,
2183/// #     name: String,
2184/// # }
2185/// # #[derive(toasty::Model)]
2186/// # struct Todo {
2187/// #     #[key]
2188/// #     #[auto]
2189/// #     id: i64,
2190/// #     #[index]
2191/// #     user_id: i64,
2192/// #     #[belongs_to(key = user_id, references = id)]
2193/// #     user: toasty::Deferred<User>,
2194/// # }
2195/// // Error: remove the type prefix `User` — use `{ ... }` without a type name
2196/// toasty::create!(Todo { user: User { name: "Alice" } })
2197/// ```
2198///
2199/// Correct:
2200///
2201/// ```
2202/// # #[derive(toasty::Model)]
2203/// # struct User {
2204/// #     #[key]
2205/// #     #[auto]
2206/// #     id: i64,
2207/// #     name: String,
2208/// # }
2209/// # #[derive(toasty::Model)]
2210/// # struct Todo {
2211/// #     #[key]
2212/// #     #[auto]
2213/// #     id: i64,
2214/// #     #[index]
2215/// #     user_id: i64,
2216/// #     #[belongs_to(key = user_id, references = id)]
2217/// #     user: toasty::Deferred<User>,
2218/// # }
2219/// let _ = toasty::create!(Todo { user: { name: "Alice" } });
2220/// ```
2221///
2222/// Nested struct values infer their type from the field.
2223///
2224/// **Nested lists:**
2225///
2226/// ```compile_fail
2227/// # #[derive(toasty::Model)]
2228/// # struct User {
2229/// #     #[key]
2230/// #     #[auto]
2231/// #     id: i64,
2232/// #     field: String,
2233/// # }
2234/// // Error: nested lists are not supported in create!
2235/// toasty::create!(User { field: [[{ }]] })
2236/// ```
2237///
2238/// **Missing braces or batch bracket:**
2239///
2240/// ```compile_fail
2241/// # #[derive(toasty::Model)]
2242/// # struct User {
2243/// #     #[key]
2244/// #     #[auto]
2245/// #     id: i64,
2246/// # }
2247/// // Error: expected `{` for single creation or `::[` for batch creation after type path
2248/// toasty::create!(User)
2249/// ```
2250///
2251/// # Return type
2252///
2253/// | Form | Returns |
2254/// |---|---|
2255/// | `Type { ... }` | `TypeCreate` (single builder) |
2256/// | `in expr { ... }` | Builder for the relation's model |
2257/// | `Type::[ ... ]` | `Batch` — executes to `Vec<Type>` |
2258/// | `( ... )` | `Batch` — executes to tuple of results |
2259///
2260/// Single and scoped forms return a builder — call `.exec(&mut db).await?`.
2261/// Batch and tuple forms return a `Batch` — also call `.exec(&mut db).await?`.
2262#[proc_macro]
2263pub fn create(input: TokenStream) -> TokenStream {
2264    match create::generate(input.into()) {
2265        Ok(output) => output.into(),
2266        Err(e) => e.to_compile_error().into(),
2267    }
2268}
2269
2270/// Expands struct-literal syntax into update-builder method chains. Returns
2271/// the same builder `target.update()` would return — call
2272/// `.exec(&mut db).await?` to execute the update.
2273///
2274/// # Syntax
2275///
2276/// ```ignore
2277/// toasty::update!(target { field: value, ... })
2278/// ```
2279///
2280/// `target` is any expression that has an `.update()` method — a model
2281/// instance, a query builder, or a scoped relation accessor.
2282///
2283/// ```no_run
2284/// # #[derive(toasty::Model)]
2285/// # struct User {
2286/// #     #[key]
2287/// #     #[auto]
2288/// #     id: i64,
2289/// #     name: String,
2290/// # }
2291/// # async fn example(mut db: toasty::Db, mut user: User, id: i64) -> toasty::Result<()> {
2292/// // Instance target
2293/// toasty::update!(user { name: "Alice Smith" })
2294///     .exec(&mut db).await?;
2295///
2296/// // Query target
2297/// toasty::update!(User::filter_by_id(id) { name: "Bob" })
2298///     .exec(&mut db).await?;
2299/// # Ok(())
2300/// # }
2301/// ```
2302///
2303/// Instance targets do not consume the binding — the macro expands to
2304/// `user.update()`, which auto-borrows `&mut user` the same way the
2305/// chain form does. `user` stays owned after the macro returns.
2306///
2307/// Value expressions are evaluated before the target is borrowed, so
2308/// they may read the target's own fields:
2309///
2310/// ```no_run
2311/// # #[derive(toasty::Model)]
2312/// # struct Todo {
2313/// #     #[key]
2314/// #     #[auto]
2315/// #     id: i64,
2316/// #     done: bool,
2317/// # }
2318/// # async fn example(mut db: toasty::Db, mut todo: Todo) -> toasty::Result<()> {
2319/// toasty::update!(todo { done: !todo.done }).exec(&mut db).await?;
2320/// # Ok(())
2321/// # }
2322/// ```
2323///
2324/// # Field shapes
2325///
2326/// ## Explicit
2327///
2328/// `field: expr` sets the field to `expr`:
2329///
2330/// ```no_run
2331/// # #[derive(toasty::Model)]
2332/// # struct User {
2333/// #     #[key]
2334/// #     #[auto]
2335/// #     id: i64,
2336/// #     name: String,
2337/// #     email: String,
2338/// # }
2339/// # async fn example(mut db: toasty::Db, mut user: User) -> toasty::Result<()> {
2340/// toasty::update!(user {
2341///     name: "Alice Smith",
2342///     email: "alice.smith@example.com",
2343/// }).exec(&mut db).await?;
2344/// # Ok(())
2345/// # }
2346/// ```
2347///
2348/// `expr` is any Rust expression. For collection fields, pass a
2349/// `toasty::stmt::*` combinator (e.g. `stmt::push("x")`,
2350/// `stmt::apply([...])`) for non-set semantics.
2351///
2352/// ## Shorthand
2353///
2354/// `field` alone is equivalent to `field: field`, matching Rust struct
2355/// literal shorthand:
2356///
2357/// ```no_run
2358/// # #[derive(toasty::Model)]
2359/// # struct User {
2360/// #     #[key]
2361/// #     #[auto]
2362/// #     id: i64,
2363/// #     name: String,
2364/// # }
2365/// # async fn example(mut db: toasty::Db, mut user: User) -> toasty::Result<()> {
2366/// let name = "Alice Smith";
2367/// toasty::update!(user { name }).exec(&mut db).await?;
2368/// # Ok(())
2369/// # }
2370/// ```
2371///
2372/// ## Method shorthand
2373///
2374/// `field.combinator(args)` is shorthand for
2375/// `field: toasty::stmt::combinator(args)`. Any function in `toasty::stmt`
2376/// works; missing functions surface as ordinary "no function" errors:
2377///
2378/// ```no_run
2379/// # #[derive(toasty::Model)]
2380/// # struct Article {
2381/// #     #[key]
2382/// #     #[auto]
2383/// #     id: i64,
2384/// #     tags: Vec<String>,
2385/// # }
2386/// # async fn example(mut db: toasty::Db, mut article: Article) -> toasty::Result<()> {
2387/// // tags.push("rust") expands to tags: stmt::push("rust")
2388/// toasty::update!(article { tags.push("rust") })
2389///     .exec(&mut db).await?;
2390/// # Ok(())
2391/// # }
2392/// ```
2393///
2394/// The shorthand is one method call deep. For chained expressions, use
2395/// the explicit `field: expr` form.
2396///
2397/// ## Embedded patch
2398///
2399/// `field: { sub: val, ... }` partially updates an embedded struct
2400/// field, leaving sub-fields not listed unchanged. Expands to
2401/// `stmt::apply([stmt::patch(...), ...])`:
2402///
2403/// ```no_run
2404/// # #[derive(toasty::Embed)]
2405/// # struct Metadata { version: i64, status: String }
2406/// # #[derive(toasty::Model)]
2407/// # struct Document {
2408/// #     #[key]
2409/// #     #[auto]
2410/// #     id: i64,
2411/// #     meta: Metadata,
2412/// # }
2413/// # async fn example(mut db: toasty::Db, mut doc: Document) -> toasty::Result<()> {
2414/// toasty::update!(doc {
2415///     meta: { version: 2, status: "published" },
2416/// }).exec(&mut db).await?;
2417/// # Ok(())
2418/// # }
2419/// ```
2420///
2421/// Sub-fields nest to arbitrary depth. To replace an embedded value
2422/// wholesale, pass the typed value directly: `meta: Metadata { ... }`.
2423///
2424/// ## Has-many insert
2425///
2426/// `field: [{ ... }, ...]` inserts new children of a has-many relation.
2427/// Each `{ ... }` becomes a create builder wrapped in
2428/// `stmt::insert(...)`; the whole list is wrapped in
2429/// `stmt::apply([...])`:
2430///
2431/// ```no_run
2432/// # #[derive(toasty::Model)]
2433/// # struct User {
2434/// #     #[key]
2435/// #     #[auto]
2436/// #     id: i64,
2437/// #     name: String,
2438/// #     #[has_many]
2439/// #     todos: toasty::Deferred<Vec<Todo>>,
2440/// # }
2441/// # #[derive(toasty::Model)]
2442/// # struct Todo {
2443/// #     #[key]
2444/// #     #[auto]
2445/// #     id: i64,
2446/// #     title: String,
2447/// #     #[index]
2448/// #     user_id: i64,
2449/// #     #[belongs_to(key = user_id, references = id)]
2450/// #     user: toasty::Deferred<User>,
2451/// # }
2452/// # async fn example(mut db: toasty::Db, mut user: User) -> toasty::Result<()> {
2453/// toasty::update!(user {
2454///     todos: [{ title: "buy milk" }, { title: "walk dog" }],
2455/// }).exec(&mut db).await?;
2456/// # Ok(())
2457/// # }
2458/// ```
2459///
2460/// Items can also be plain expressions, mixed in with builder
2461/// shorthands — useful for combining inserts and removals:
2462///
2463/// ```no_run
2464/// # #[derive(toasty::Model)]
2465/// # struct User {
2466/// #     #[key]
2467/// #     #[auto]
2468/// #     id: i64,
2469/// #     #[has_many]
2470/// #     todos: toasty::Deferred<Vec<Todo>>,
2471/// # }
2472/// # #[derive(toasty::Model)]
2473/// # struct Todo {
2474/// #     #[key]
2475/// #     #[auto]
2476/// #     id: i64,
2477/// #     title: String,
2478/// #     #[index]
2479/// #     user_id: i64,
2480/// #     #[belongs_to(key = user_id, references = id)]
2481/// #     user: toasty::Deferred<User>,
2482/// # }
2483/// # async fn example(mut db: toasty::Db, mut user: User, old: Todo) -> toasty::Result<()> {
2484/// toasty::update!(user {
2485///     todos: [{ title: "new" }, toasty::stmt::remove(&old)],
2486/// }).exec(&mut db).await?;
2487/// # Ok(())
2488/// # }
2489/// ```
2490///
2491/// # Field validation
2492///
2493/// The macro emits a method call per named field on the update builder.
2494/// A field name the model does not expose for update fails with the
2495/// compiler's standard "no method named …" error at the macro call
2496/// site.
2497#[proc_macro]
2498pub fn update(input: TokenStream) -> TokenStream {
2499    match update::generate(input.into()) {
2500        Ok(output) => output.into(),
2501        Err(e) => e.to_compile_error().into(),
2502    }
2503}