pub mod aggregate;
mod db_typ;
pub mod from_expr;
pub mod into_expr;
#[cfg(feature = "jiff-02")]
mod jiff_operations;
mod operations;
pub mod optional;
use std::{
cell::{Cell, OnceCell},
fmt::Debug,
marker::PhantomData,
ops::Deref,
rc::Rc,
};
use crate::{
IntoExpr, Table,
db::TableRow,
lower,
mutable::Mutable,
private::IntoJoinable,
scoped_transaction::{MutTemp, TransactionScope},
};
pub use db_typ::{DbTyp, StorableTyp};
pub trait NumTyp: OrdTyp + Clone + Copy {
const ZERO: &str;
}
impl NumTyp for i64 {
const ZERO: &str = "0";
}
impl NumTyp for f64 {
const ZERO: &str = "0.0";
}
pub trait OrdTyp: EqTyp {}
impl OrdTyp for String {}
impl OrdTyp for Vec<u8> {}
impl OrdTyp for i64 {}
impl OrdTyp for f64 {}
impl OrdTyp for bool {}
#[cfg(feature = "jiff-02")]
impl OrdTyp for jiff::Timestamp {}
#[cfg(feature = "jiff-02")]
impl OrdTyp for jiff::civil::Date {}
pub trait BuffTyp: DbTyp {}
impl BuffTyp for String {}
impl BuffTyp for Vec<u8> {}
#[diagnostic::on_unimplemented(
message = "Columns with type `{Self}` can not be checked for equality",
note = "`EqTyp` is also implemented for all table types"
)]
pub trait EqTyp: DbTyp {}
impl EqTyp for String {}
impl EqTyp for Vec<u8> {}
impl EqTyp for i64 {}
impl EqTyp for f64 {}
impl EqTyp for bool {}
#[cfg(feature = "jiff-02")]
impl EqTyp for jiff::Timestamp {}
#[cfg(feature = "jiff-02")]
impl EqTyp for jiff::civil::Date {}
#[diagnostic::do_not_recommend]
impl<T: Table> EqTyp for TableRow<T> {}
pub trait OptTable: DbTyp {
type Schema;
type Mutable<'t>;
fn into_mutable<'t>(
txn: &'t mut TransactionScope<Self::Schema>,
val: Self,
) -> Self::Mutable<'t>;
}
impl<T: Table> OptTable for TableRow<T> {
type Schema = T::Schema;
type Mutable<'t> = Mutable<'t, T>;
fn into_mutable<'t>(
txn: &'t mut TransactionScope<Self::Schema>,
inp: Self,
) -> Self::Mutable<'t> {
txn.tmp = Cell::new(vec![MutTemp::new(inp)]);
Mutable::new(&mut *Cell::get_mut(&mut txn.tmp)[0])
}
}
impl<T: Table> OptTable for Option<TableRow<T>> {
type Schema = T::Schema;
type Mutable<'t> = Option<Mutable<'t, T>>;
fn into_mutable<'t>(
txn: &'t mut TransactionScope<Self::Schema>,
val: Self,
) -> Self::Mutable<'t> {
val.map(|x| TableRow::<T>::into_mutable(txn, x))
}
}
pub struct Expr<'column, S, T: DbTyp> {
pub(crate) _local: PhantomData<*const ()>,
pub(crate) inner: Rc<lower::Expr>,
pub(crate) _p: PhantomData<&'column ()>,
pub(crate) _p2: PhantomData<S>,
pub(crate) ext: OnceCell<Box<T::Ext<'static>>>,
pub(crate) not_null_key: bool,
}
#[cfg_attr(false, mutants::skip)]
impl<S, T: DbTyp> Debug for Expr<'_, S, T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Expr of type {}", std::any::type_name::<T>())
}
}
impl<'column, S, T: DbTyp> Expr<'column, S, T> {
#[doc(hidden)]
pub fn _migrate<OldS>(prev: impl IntoExpr<'column, OldS>) -> Self {
let prev = prev.into_expr().inner;
Self::new(prev)
}
}
pub fn adhoc_expr<S, T: DbTyp>(f: lower::Expr) -> Expr<'static, S, T> {
Expr::adhoc(f)
}
pub fn new_column<'x, S, C: DbTyp, T: Table>(
table: impl IntoExpr<'x, S, Typ = TableRow<T>>,
name: &'static str,
) -> Expr<'x, S, C> {
let table = table.into_expr();
Expr::new_inner(
table.inner.col(T::NAME, name, T::ID, table.not_null_key),
table.not_null_key && !C::NULLABLE,
)
}
pub fn unique_from_joinable<'inner, T: Table>(
j: impl IntoJoinable<'inner, T::Schema, Typ = TableRow<T>>,
) -> Expr<'inner, T::Schema, Option<TableRow<T>>> {
let joinable = j.into_joinable();
let unique = Rc::new(lower::Unique {
table: joinable.table.name,
conds: joinable.conds,
guaranteed: false,
});
Expr::adhoc(lower::Expr::RowIndex(lower::RowLike::Unique(unique), T::ID))
}
impl<S, T: DbTyp> Expr<'_, S, T> {
pub(crate) fn adhoc(e: lower::Expr) -> Self {
Self::new(Rc::new(e))
}
pub(crate) fn new(val: Rc<lower::Expr>) -> Self {
Self::new_inner(val, false)
}
pub(crate) fn new_inner(val: Rc<lower::Expr>, not_null_key: bool) -> Self {
Self {
_local: PhantomData,
inner: val,
_p: PhantomData,
_p2: PhantomData,
ext: OnceCell::new(),
not_null_key,
}
}
}
impl<S, T: DbTyp> Clone for Expr<'_, S, T> {
fn clone(&self) -> Self {
Self {
_local: PhantomData,
inner: self.inner.clone(),
_p: self._p,
_p2: self._p2,
ext: OnceCell::new(),
not_null_key: self.not_null_key,
}
}
}
impl<'t, T: Table> Deref for Expr<'t, T::Schema, TableRow<T>> {
type Target = T::Ext2<'t>;
fn deref(&self) -> &Self::Target {
T::covariant_ext(self.ext.get_or_init(|| {
let expr = Expr {
_local: PhantomData,
inner: self.inner.clone(),
_p: PhantomData::<&'static ()>,
_p2: PhantomData,
ext: OnceCell::new(),
not_null_key: self.not_null_key,
};
Box::new(T::build_ext2(&expr))
}))
}
}