create!() { /* proc-macro */ }Expand description
Expands struct-literal syntax into create builder method chains. Returns one
or more create builders — call .exec(&mut db).await? to insert the
record(s).
§Syntax forms
§Field syntax
Fields inside { ... } can use either explicit or shorthand syntax:
- Explicit:
field: expr— sets the field to the given expression. - Shorthand:
field— equivalent tofield: field, using a variable with the same name as the field.
These can be mixed freely, just like Rust struct literals:
let name = "Alice".to_string();
toasty::create!(User { name, email: "alice@example.com" })§Single creation
toasty::create!(Type { field: value, ... })Expands to Type::create().field(value)... and returns the model’s create
builder (e.g., UserCreate).
let user = toasty::create!(User {
name: "Alice",
email: "alice@example.com"
})
.exec(&mut db)
.await?;§Scoped creation
toasty::create!(in expr { field: value, ... })Expands to expr.create().field(value).... Creates a record through a
relation accessor. The foreign key is set automatically.
let todo = toasty::create!(in user.todos() { title: "buy milk" })
.exec(&mut db)
.await?;
// todo.user_id == user.id§Typed batch
toasty::create!(Type::[ { fields }, { fields }, ... ])Expands to toasty::batch([builder1, builder2, ...]) and returns
Vec<Type> when executed:
let users = toasty::create!(User::[
{ name: "Alice" },
{ name: "Bob" },
])
.exec(&mut db)
.await?;
// users: Vec<User>§Tuple
toasty::create!((
Type1 { fields },
Type2 { fields },
...
))Expands to toasty::batch((builder1, builder2, ...)) and returns a
tuple matching the input types:
let (user, post) = toasty::create!((
User { name: "Alice" },
Post { title: "Hello" },
))
.exec(&mut db)
.await?;
// (User, Post)§Mixed tuple
Typed batches and single creates can be mixed inside a tuple:
let (users, post) = toasty::create!((
User::[ { name: "Alice" }, { name: "Bob" } ],
Post { title: "Hello" },
))
.exec(&mut db)
.await?;
// (Vec<User>, Post)§Field values
§Expressions
Any Rust expression is valid as a field value — literals, variables, and
function calls all work. When a variable has the same name as the field,
you can use the shorthand syntax (just name instead of name: name):
let name = "Alice";
let _ = toasty::create!(User { name, email: format!("{}@example.com", name) });When the variable name differs from the field name, use the explicit
field: expr form:
let user_name = "Alice";
let _ = toasty::create!(User { name: user_name });§Nested struct (BelongsTo / HasOne)
Use { ... } without a type prefix to create a related record inline.
The macro expands the nested fields into a create builder and passes it
to the field’s setter method.
let _ = toasty::create!(Todo {
title: "buy milk",
user: { name: "Alice" }
});
// Expands to:
// Todo::create()
// .title("buy milk")
// .user(Todo::fields().user().create().name("Alice"))The related record is created first and the foreign key is set automatically.
§Nested list (HasMany)
Use [{ ... }, { ... }] to create multiple related records. The macro
expands each entry into a create builder and passes them as an array to
the plural field setter.
let _ = toasty::create!(User {
name: "Alice",
todos: [{ title: "first" }, { title: "second" }]
});
// Expands to:
// User::create()
// .name("Alice")
// .todos([
// User::fields().todos().create().title("first"),
// User::fields().todos().create().title("second"),
// ])Items in a nested list can also be plain expressions (e.g., an existing builder value).
§Deep nesting
Nesting composes to arbitrary depth:
let _ = toasty::create!(User {
name: "Alice",
todos: [{
title: "task",
tags: [{ name: "urgent" }, { name: "work" }]
}]
});This creates a User, then a Todo linked to that user, then two Tag
records linked to that todo.
§Fields that can be omitted
| Field type | Behavior when omitted |
|---|---|
#[auto] | Value generated by the database or Toasty |
Option<T> | Defaults to None (NULL) |
#[default(expr)] | Uses the default expression |
#[update(expr)] | Uses the expression as the initial value |
HasMany<T> | No related records created |
HasOne<Option<T>> | No related record created |
BelongsTo<Option<T>> | Foreign key set to NULL |
Required fields (String, i64, non-optional BelongsTo, etc.) that are
missing do not cause a compile-time error. The insert fails at runtime with
a database constraint violation.
§Compile errors
Type prefix on nested struct:
// Error: remove the type prefix `User` — use `{ ... }` without a type name
toasty::create!(Todo { user: User { name: "Alice" } })Correct:
let _ = toasty::create!(Todo { user: { name: "Alice" } });Nested struct values infer their type from the field.
Nested lists:
// Error: nested lists are not supported in create!
toasty::create!(User { field: [[{ }]] })Missing braces or batch bracket:
// Error: expected `{` for single creation or `::[` for batch creation after type path
toasty::create!(User)§Return type
| Form | Returns |
|---|---|
Type { ... } | TypeCreate (single builder) |
in expr { ... } | Builder for the relation’s model |
Type::[ ... ] | Batch — executes to Vec<Type> |
( ... ) | Batch — executes to tuple of results |
Single and scoped forms return a builder — call .exec(&mut db).await?.
Batch and tuple forms return a Batch — also call .exec(&mut db).await?.