For AI agents: the complete documentation index is available at https://a3s-lab.github.io/ORM/en/llms.txt, the full documentation bundle is available at https://a3s-lab.github.io/ORM/en/llms-full.txt, and this page is available as Markdown at https://a3s-lab.github.io/ORM/en/queries/mutations.md.
  • English
  • v0.3.1
  • INSERT, UPDATE, and DELETE

    Write queries preserve column ownership and value-family constraints. An INSERT or UPDATE without assignments fails during compilation.

    Single-row and multi-row INSERT

    use a3s_orm::{insert_into, InsertRow};
    
    let single = insert_into::<Person>()
        .value(Person::id(), 1)
        .value(Person::name(), "Ada")
        .value(Person::age(), 36)
        .returning((Person::id(), Person::name()));
    
    let rows = [
        InsertRow::<Person>::new()
            .value(Person::id(), 2)
            .value(Person::name(), "Grace")
            .value(Person::age(), 40),
        InsertRow::<Person>::new()
            .value(Person::id(), 3)
            .value(Person::name(), "Linus")
            .value(Person::age(), 28),
    ];
    
    let batch = insert_into::<Person>().rows(rows);

    Multi-row compilation verifies identical columns and ordering before adding values to the shared parameter sequence.

    Conflict handling

    let upsert = insert_into::<Person>()
        .value(Person::id(), 1)
        .value(Person::name(), "Ada")
        .value(Person::age(), 37)
        .on_conflict(Person::id())
        .do_update_from_excluded(Person::name())
        .do_update_from_excluded(Person::age())
        .returning(Person::id());

    A conflict target can be one column or a tuple of up to four columns. do_nothing, bound-value updates, and excluded references remain structured. The MySQL dialect rejects this syntax.

    UPDATE

    use a3s_orm::update_table;
    
    let update = update_table::<Person>()
        .set(Person::name(), "Ada Lovelace")
        .filter(Person::id().eq(1))
        .returning((Person::id(), Person::name()));

    UPDATE does not require a filter automatically. A full-table update must be explicit, and applications should add policy checks at their boundary.

    Expression assignments and UPDATE FROM

    use a3s_orm::{orm_table, select_from, update_table, OrderDirection};
    
    orm_table! { struct Candidate => "candidate" { id: i64 => "id" } }
    
    let candidates = select_from::<Person>()
        .select(Person::id())
        .order_by(Person::id(), OrderDirection::Asc)
        .limit(5)
        .for_update()
        .skip_locked()
        .as_cte::<Candidate>();
    
    let claim = update_table::<Person>()
        .with(candidates)
        .set_expression(Person::age(), Person::age() + 1)
        .from::<Candidate>()
        .filter(Person::id().eq_column(Candidate::id()))
        .returning((Person::id(), Person::age()));

    set_expression requires an output type matching the destination column. The CTE, assignment, filter, and RETURNING share one parameter accumulator.

    DELETE

    use a3s_orm::delete_from;
    
    let removed = delete_from::<Person>()
        .filter(Person::id().eq(3))
        .returning(Person::id());

    DELETE also permits an omitted filter. Production interfaces should model full-table deletion as a separate controlled operation.