rent
Concepts

CRUD and queries

Builder calls only collect values in memory. save(), all(), only(), count(), and exec() are execution boundaries.

let ada = client
    .create_user()
    .name("Ada")
    .email("ada@example.com")
    .save()
    .await?;

let adults = client
    .user()
    .age_ge(18)
    .order_by_desc(user::fields::CREATED_AT)
    .limit(25)
    .all()
    .await?;

let changed = client
    .update_user()
    .id_eq(ada.id)
    .name("Ada Lovelace")
    .save()
    .await?;

let removed = client.delete_user().id_eq(ada.id).exec().await?;

Filter through relationships without writing a subquery:

let authors = client
    .user()
    .where_posts(|posts| posts.published_eq(true))
    .all()
    .await?;

For large or narrow reads, use keyset cursors, bounded streams, and typed tuple projections:

let identities = client
    .user()
    .after_id(last_id)
    .limit(100)
    .select((user::fields::ID, user::fields::NAME))
    .all()
    .await?;

The setter chain does not send one query per setter. Rent emits one mutation at save(). PostgreSQL and SQLite return the complete entity from that same INSERT ... RETURNING request; MySQL uses the insert identifier and one follow-up read because it lacks equivalent general-purpose returning support.

Generated predicate families include equality, inequality, greater/greater-or-equal, less/less-or-equal, membership (_in and _not_in), and null/not-null, plus _contains, _starts_with, _ends_with, and _contains_insensitive on string fields, depending on the field's type and nullability. Thus normal code is client.document().id_eq(id).version_eq(version). The longer document_predicate::id_eq(id) form remains for expressions that must be stored, reused, or combined dynamically with AND, OR, NOT, JSON operations, or extension operators.