use rorm_declaration::imr;
use crate::conditions::{Binary, BinaryOperator, Column, Value};
use crate::crud::selector::Selector;
use crate::fields::proxy;
use crate::fields::utils::column_name::ColumnName;
use crate::internal::field::{Field, SingleColumnField};
use crate::internal::hmr::{AsImr, Source};
use crate::internal::relation_path::Path;
use crate::internal::ConstRef;
pub trait Patch: Sized + 'static {
type Model: Model;
type ValueSpaceImpl: Selector<Result = Self, Model = Self::Model> + Default;
fn columns() -> Vec<ColumnName> {
let mut columns = Vec::new();
Self::push_columns(&mut columns);
columns
}
fn push_columns(columns: &mut Vec<ColumnName>);
fn values(self) -> Vec<Value<'static>> {
let mut values = Vec::new();
self.push_values(&mut values);
values
}
fn push_values(self, values: &mut Vec<Value>);
fn references(&self) -> Vec<Value<'_>> {
let mut values = Vec::new();
self.push_references(&mut values);
values
}
fn push_references<'a>(&'a self, values: &mut Vec<Value<'a>>);
}
pub type PatchAsCondition<'a, P> =
Binary<Column<(<<P as Patch>::Model as Model>::Primary, <P as Patch>::Model)>, Value<'a>>;
pub trait Model: Patch<Model = Self> {
type Primary: Field<Model = Self> + SingleColumnField;
type Fields<P: Path>: ConstRef;
const TABLE: &'static str;
const SOURCE: Source;
fn push_fields_imr(fields: &mut Vec<imr::Field>);
fn get_imr() -> imr::Model {
let mut fields = Vec::new();
Self::push_fields_imr(&mut fields);
imr::Model {
name: Self::TABLE.to_string(),
fields,
source_defined_at: Some(Self::SOURCE.as_imr()),
}
}
}
pub trait FieldByIndex<const INDEX: usize>: Model {
type Field: Field<Model = Self>;
}
pub trait GetField<F: Field>: Patch {
fn get_field(self) -> F::Type;
fn borrow_field(&self) -> &F::Type;
fn borrow_field_mut(&mut self) -> &mut F::Type;
}
pub trait UpdateField<F: Field<Model = Self>>: Model {
fn update_field<'m, T>(
&'m mut self,
update: impl FnOnce(&'m <<Self as Model>::Primary as Field>::Type, &'m mut F::Type) -> T,
) -> T;
}
pub trait Identifiable: Patch {
fn get_primary_key(&self) -> &<<Self::Model as Model>::Primary as Field>::Type;
fn as_condition(&self) -> PatchAsCondition<'_, Self> {
Binary {
operator: BinaryOperator::Equals,
fst_arg: Column(proxy::new()),
snd_arg: <Self::Model as Model>::Primary::type_as_value(self.get_primary_key()),
}
}
}
impl<M: Model, P: Patch<Model = M> + GetField<M::Primary>> Identifiable for P {
fn get_primary_key(&self) -> &<M::Primary as Field>::Type {
<Self as GetField<M::Primary>>::borrow_field(self)
}
}
#[macro_export]
macro_rules! register_model {
($Model:ty) => {
const _: () = {
<$Model>::__rorm_internal__check();
#[$crate::linkme::distributed_slice($crate::MODELS)]
#[linkme(crate = $crate::linkme)]
static __get_imr: fn() -> $crate::imr::Model =
<$Model as $crate::model::Model>::get_imr;
};
};
}