use rorm_db::sql::value::NullType;
use rorm_declaration::imr;
use crate::conditions::Value;
use crate::fields::proxy::FieldProxy;
use crate::fields::proxy::FieldProxyImpl;
use crate::internal::hmr::annotations::Annotations;
use crate::internal::hmr::{AsImr, Source};
use crate::internal::relation_path::{Path, PathField};
use crate::model::Model;
pub mod cascading_foreign_model;
pub mod decoder;
pub mod fake_field;
pub mod foreign_model;
pub mod multi_column;
use crate::fields::traits::{Array, FieldColumns, FieldType};
use crate::fields::utils::column_name::ColumnName;
use crate::fields::utils::const_fn::{ConstFn, Contains};
use crate::internal::const_concat::ConstString;
use crate::internal::ConstRef;
pub trait Field: 'static + Copy {
type Type: FieldType;
type Model: Model;
const INDEX: usize;
const NAME: ColumnName;
const EXPLICIT_ANNOTATIONS: Annotations;
const EFFECTIVE_ANNOTATIONS: FieldColumns<Self::Type, Annotations> =
<<<Self::Type as FieldType>::GetAnnotations as ConstFn<_, _>>::Body<(
contains::ExplicitAnnotations<Self>,
)> as Contains<_>>::ITEM;
const EFFECTIVE_NAMES: FieldColumns<Self::Type, ColumnName> =
<<<Self::Type as FieldType>::GetNames as ConstFn<_, _>>::Body<(contains::Name<Self>,)> as Contains<_>>::ITEM;
const SOURCE: Source;
fn new() -> Self;
}
pub fn push_imr<F: Field>(imr: &mut Vec<imr::Field>) {
let names = F::EFFECTIVE_NAMES;
let db_types = F::Type::NULL;
let annotations = F::EFFECTIVE_ANNOTATIONS;
let source_defined_at = F::SOURCE.as_imr();
for ((name, annotations), null_type) in names
.into_iter()
.zip(annotations.into_iter())
.zip(db_types.into_iter())
{
imr.push(imr::Field {
name: name.as_str().to_string(),
db_type: match null_type {
NullType::String => imr::DbType::VarChar,
NullType::Choice => imr::DbType::Choices,
NullType::I64 => imr::DbType::Int64,
NullType::I32 => imr::DbType::Int32,
NullType::I16 => imr::DbType::Int16,
NullType::Bool => imr::DbType::Boolean,
NullType::F64 => imr::DbType::Double,
NullType::F32 => imr::DbType::Float,
NullType::Binary => imr::DbType::Binary,
NullType::ChronoNaiveTime => imr::DbType::Time,
NullType::ChronoNaiveDate => imr::DbType::Date,
NullType::ChronoNaiveDateTime => imr::DbType::DateTime,
NullType::ChronoDateTime => imr::DbType::DateTime,
NullType::TimeDate => imr::DbType::Date,
NullType::TimeTime => imr::DbType::Time,
NullType::TimeOffsetDateTime => imr::DbType::DateTime,
NullType::TimePrimitiveDateTime => imr::DbType::DateTime,
NullType::Uuid => imr::DbType::Uuid,
NullType::UuidHyphenated => imr::DbType::Uuid,
NullType::UuidSimple => imr::DbType::Uuid,
NullType::JsonValue => imr::DbType::Binary,
#[cfg(feature = "postgres-only")]
NullType::MacAddress => imr::DbType::MacAddress,
#[cfg(feature = "postgres-only")]
NullType::IpNetwork => imr::DbType::IpNetwork,
#[cfg(feature = "postgres-only")]
NullType::BitVec => imr::DbType::BitVec,
},
annotations: annotations.as_imr(),
source_defined_at: Some(source_defined_at.clone()),
});
}
}
#[allow(clippy::result_large_err, reason = "There is no heap in const")]
pub const fn check<F: Field>() -> Result<(), ConstString<1024>> {
<<<F::Type as FieldType>::Check as ConstFn<_, _>>::Body<(
contains::ExplicitAnnotations<F>,
contains::EffectiveAnnotations<F>,
)> as Contains<_>>::ITEM
}
pub trait SingleColumnField: Field<Type: FieldType<Columns = Array<1>>> {
const EFFECTIVE_ANNOTATION: Annotations = {
let [annos] = Self::EFFECTIVE_ANNOTATIONS;
annos
};
fn type_as_value(field: &Self::Type) -> Value<'_> {
let [value] = field.as_values();
value
}
fn type_into_value(field: Self::Type) -> Value<'static> {
let [value] = field.into_values();
value
}
}
impl<F> SingleColumnField for F where F: Field<Type: FieldType<Columns = Array<1>>> {}
pub trait ContainerField<T: FieldType, P: Path>: Field<Type = T> {
type Target: ConstRef;
}
impl<I, T, F, P> std::ops::Deref for FieldProxy<I>
where
T: FieldType,
F: Field<Type = T> + ContainerField<T, P>,
P: Path,
I: FieldProxyImpl<Field = F, Path = P>,
{
type Target = F::Target;
fn deref(&self) -> &'static Self::Target {
ConstRef::REF
}
}
impl<T, F, P> ContainerField<T, P> for F
where
T: FieldType,
F: Field<Type = T> + PathField<T>,
P: Path<Current = <F::ParentField as Field>::Model>,
{
type Target = <<F::ChildField as Field>::Model as Model>::Fields<P::Step<F>>;
}
mod contains {
use std::marker::PhantomData;
use crate::fields::traits::FieldColumns;
use crate::fields::utils::column_name::ColumnName;
use crate::fields::utils::const_fn::Contains;
use crate::internal::field::Field;
use crate::internal::hmr::annotations::Annotations;
pub struct ExplicitAnnotations<F: Field>(PhantomData<F>);
impl<F: Field> Contains<Annotations> for ExplicitAnnotations<F> {
const ITEM: Annotations = F::EXPLICIT_ANNOTATIONS;
}
pub struct EffectiveAnnotations<F: Field>(PhantomData<F>);
impl<F: Field> Contains<FieldColumns<F::Type, Annotations>> for EffectiveAnnotations<F> {
const ITEM: FieldColumns<F::Type, Annotations> = F::EFFECTIVE_ANNOTATIONS;
}
pub struct Name<F: Field>(PhantomData<F>);
impl<F: Field> Contains<ColumnName> for Name<F> {
const ITEM: ColumnName = F::NAME;
}
}