toasty 0.8.0

An async ORM for Rust supporting SQL and NoSQL databases
Documentation
//! Internal types referenced by code generated by `#[derive(Model)]` and the
//! `create!` / `update!` / `query!` macros. Not part of the public API; the
//! contents may change between releases.

#![doc(hidden)]

pub mod auto;
pub mod index;
pub mod newtype;
pub mod shared_column;
pub mod storage;
pub mod version;
pub mod via;

pub use crate::schema::inventory;
pub use crate::{
    Db, Error, Executor, Result, Statement,
    schema::{
        Auto, Deferred, DiscoverItem, Embed, Field, Load, Model, QueryMany, QueryOne,
        QueryOptionOne, RelationManyField, RelationOneField, Scope, ViaMany, ViaManyField, ViaPath,
        ViaTarget, generate_unique_id,
    },
    stmt::CreateMany,
    stmt::{self, Assign, IntoExpr, IntoInsert, IntoStatement, List, Path},
    update_target::UpdateTarget,
};
#[cfg(feature = "serde")]
pub use serde_json;
pub use std::{clone::Clone, convert::Into, default::Default, option::Option};

pub use self::version::Version;
pub use toasty_core as core;

/// The expression-level type that a create/update setter accepts for a field
/// of type `F`. This is just [`Field::ExprTarget`], but naming it keeps the
/// long `<F as Field>::ExprTarget` projection out of generated setter
/// signatures (and out of the compiler errors they produce).
pub type FieldExprTarget<F> = <F as Field>::ExprTarget;

/// Infer the [`Scope`] type from a scope expression and return its fields
/// path.
///
/// The `create!` macro uses this in the scoped form (`in expr { ... }`) to
/// obtain the field struct for nested builders. Because the macro has no
/// type information, it cannot call `S::new_path_root()` directly — this function
/// lets Rust infer `S` from the scope argument.
pub fn scope_fields<S: Scope>(_scope: &S) -> S::Path<S::Item> {
    S::new_path_root()
}

/// Create a record inside a scoped create target.
pub fn create_in_scope<S: Scope>(scope: S) -> S::Create {
    S::create_in_scope(scope)
}

/// Convert a value into an untyped [`core::stmt::Expr`] via the typed
/// [`IntoExpr<T>`] trait.
///
/// Generated code (`#[derive(Model)]`, `#[derive(Embed)]`) splices this in
/// instead of inlining the `let expr: Expr<T> = value.into_expr(); expr.into()`
/// pattern at every field site. The explicit `T` type parameter
/// disambiguates which `IntoExpr` impl to use.
pub fn into_untyped_expr<T, V: IntoExpr<T>>(value: V) -> core::stmt::Expr {
    let expr: stmt::Expr<T> = value.into_expr();
    expr.into()
}

/// Insert `item` into the relation that produced this list query.
///
/// Generated code emits `Query<List<M>>::insert` as a one-line forward to
/// this helper. The query must be scoped to a single-step relation
/// traversal; multi-step traversals and unscoped queries return an
/// `unsupported_feature` error.
pub async fn relation_insert<M, E>(
    mut query: stmt::Query<List<M>>,
    executor: &mut dyn Executor,
    item: E,
) -> Result<()>
where
    M: Model,
    E: IntoExpr<M>,
{
    match query.take_via_assoc() {
        Some(untyped) if untyped.path.projection.as_slice().len() == 1 => {
            let assoc = stmt::Association::<List<M>>::from_untyped(untyped);
            executor.exec(assoc.insert(item)).await
        }
        Some(_) => Err(Error::unsupported_feature(
            "insert is not supported on multi-step relation traversals",
        )),
        None => Err(Error::unsupported_feature(
            "insert requires a relation-scoped query",
        )),
    }
}

/// Remove `item` from the relation that produced this list query.
///
/// Counterpart to [`relation_insert`]; the same scoping rules apply.
pub async fn relation_remove<M, E>(
    mut query: stmt::Query<List<M>>,
    executor: &mut dyn Executor,
    item: E,
) -> Result<()>
where
    M: Model,
    E: IntoExpr<M>,
{
    match query.take_via_assoc() {
        Some(untyped) if untyped.path.projection.as_slice().len() == 1 => {
            let assoc = stmt::Association::<List<M>>::from_untyped(untyped);
            executor.exec(assoc.remove(item)).await
        }
        Some(_) => Err(Error::unsupported_feature(
            "remove is not supported on multi-step relation traversals",
        )),
        None => Err(Error::unsupported_feature(
            "remove requires a relation-scoped query",
        )),
    }
}

/// Continue a `has_many` traversal from `query` along `path`.
///
/// If `query` was already scoped from a relation traversal, append
/// `field_offset` to that traversal's path so the result remains a single
/// chained association. Otherwise build a fresh `Association::many` rooted
/// at `query`. Used by generated `.field()` chain methods on the per-model
/// `Query<List<Source>>` for `has_many` relations.
pub fn chain_or_build_many<Source, Target>(
    mut query: stmt::Query<List<Source>>,
    field_offset: usize,
    path: stmt::Path<Source, List<Target>>,
) -> stmt::Association<List<Target>>
where
    Source: Model,
    Target: Model,
{
    match query.take_via_assoc() {
        Some(untyped) => stmt::Association::<List<Source>>::from_untyped(untyped)
            .chain_field::<Target>(field_offset),
        None => stmt::Association::many(query, path),
    }
}

/// Continue a `belongs_to` / `has_one` traversal from `query` along `path`.
///
/// Mirrors [`chain_or_build_many`] for singular relation steps: when no
/// existing traversal is present the fresh association is built via
/// [`stmt::Association::many_via_one`].
pub fn chain_or_build_many_via_one<Source, Target>(
    mut query: stmt::Query<List<Source>>,
    field_offset: usize,
    path: stmt::Path<Source, Target>,
) -> stmt::Association<List<Target>>
where
    Source: Model,
    Target: Model,
{
    match query.take_via_assoc() {
        Some(untyped) => stmt::Association::<List<Source>>::from_untyped(untyped)
            .chain_field::<Target>(field_offset),
        None => stmt::Association::many_via_one(query, path),
    }
}