use std::marker::PhantomData;
use super::effects::{EffectExpression, EffectFieldValue, EffectKey, EffectRelationship};
use super::projection_obligations::{CommandInputDefault, InputDefaultGenerator};
use crate::read_model::RelationalReadModel;
#[doc(hidden)]
pub struct EffectWireChecked;
#[doc(hidden)]
pub struct EffectWireLiteral;
#[doc(hidden)]
pub struct EffectWireString;
#[doc(hidden)]
pub struct EffectWireBoolean;
#[doc(hidden)]
pub struct EffectWireBigInt;
#[doc(hidden)]
pub struct EffectWireFloat;
#[doc(hidden)]
pub struct EffectWireJson;
#[doc(hidden)]
pub struct EffectWireBytea;
#[doc(hidden)]
pub struct EffectWireTimestamp;
#[doc(hidden)]
pub struct EffectWireList;
#[doc(hidden)]
pub struct EffectWireObject;
#[doc(hidden)]
pub struct EffectWireUnsupported;
#[doc(hidden)]
pub trait EffectWireCompatible<Target> {}
macro_rules! exact_effect_wire_compatibility {
($($wire:ty),+ $(,)?) => {
$(impl EffectWireCompatible<$wire> for $wire {})+
};
}
exact_effect_wire_compatibility!(
EffectWireString,
EffectWireBoolean,
EffectWireBigInt,
EffectWireFloat,
EffectWireJson,
EffectWireBytea,
EffectWireTimestamp,
EffectWireList,
EffectWireObject,
EffectWireUnsupported,
);
impl EffectWireCompatible<EffectWireJson> for EffectWireList {}
impl EffectWireCompatible<EffectWireJson> for EffectWireObject {}
impl<Target> EffectWireCompatible<Target> for EffectWireLiteral {}
#[doc(hidden)]
pub struct TypedEffectExpression<T, Wire = EffectWireChecked> {
expression: EffectExpression,
_value: PhantomData<fn() -> (T, Wire)>,
}
impl<T, Wire> TypedEffectExpression<T, Wire> {
#[doc(hidden)]
pub(crate) fn __into_ir(self) -> EffectExpression {
self.expression
}
fn erase_wire(self) -> TypedEffectExpression<T> {
TypedEffectExpression {
expression: self.expression,
_value: PhantomData,
}
}
}
#[doc(hidden)]
pub struct EffectRequired;
#[doc(hidden)]
pub struct EffectNullable;
#[doc(hidden)]
pub struct EffectInputObjectKind;
#[doc(hidden)]
pub struct EffectInputTerminalKind;
#[doc(hidden)]
pub trait EffectInputPathKind {}
impl EffectInputPathKind for EffectInputObjectKind {}
impl EffectInputPathKind for EffectInputTerminalKind {}
#[doc(hidden)]
pub trait EffectInputDescendableKind: EffectInputPathKind {}
impl EffectInputDescendableKind for EffectInputObjectKind {}
#[doc(hidden)]
pub trait EffectPathNullability {
type Applied<T>;
}
impl EffectPathNullability for EffectRequired {
type Applied<T> = T;
}
impl EffectPathNullability for EffectNullable {
type Applied<T> = Option<T>;
}
#[doc(hidden)]
pub trait CombineEffectNullability<Other: EffectPathNullability> {
type Output: EffectPathNullability;
}
impl CombineEffectNullability<EffectRequired> for EffectRequired {
type Output = EffectRequired;
}
impl CombineEffectNullability<EffectNullable> for EffectRequired {
type Output = EffectNullable;
}
impl CombineEffectNullability<EffectRequired> for EffectNullable {
type Output = EffectNullable;
}
impl CombineEffectNullability<EffectNullable> for EffectNullable {
type Output = EffectNullable;
}
#[doc(hidden)]
pub trait EffectInputFieldMarker {
type Input: 'static;
type Value;
type NonNullValue;
type Nullability: EffectPathNullability;
type PathKind: EffectInputPathKind;
type Wire;
type Nested: 'static;
fn path() -> Vec<&'static str>;
}
#[doc(hidden)]
pub struct EffectInputPath<Outer, Inner>(PhantomData<fn(Outer) -> Inner>);
impl<Outer, Inner> EffectInputFieldMarker for EffectInputPath<Outer, Inner>
where
Outer: EffectInputFieldMarker,
Inner: EffectInputFieldMarker<Input = Outer::Nested>,
Outer::PathKind: EffectInputDescendableKind,
Outer::Nullability: CombineEffectNullability<Inner::Nullability>,
{
type Input = Outer::Input;
type Value = <<Outer::Nullability as CombineEffectNullability<
Inner::Nullability,
>>::Output as EffectPathNullability>::Applied<Inner::NonNullValue>;
type NonNullValue = Inner::NonNullValue;
type Nullability = <Outer::Nullability as CombineEffectNullability<Inner::Nullability>>::Output;
type PathKind = Inner::PathKind;
type Wire = Inner::Wire;
type Nested = Inner::Nested;
fn path() -> Vec<&'static str> {
let mut path = Outer::path();
path.extend(Inner::path());
path
}
}
#[doc(hidden)]
pub trait EffectModelFieldMarker {
type Model: RelationalReadModel;
type Value;
type Wire;
const FIELD: &'static str;
}
#[doc(hidden)]
pub trait EffectRelationshipMarker {
type Source: RelationalReadModel;
type Target: RelationalReadModel;
const FIELD: &'static str;
}
#[doc(hidden)]
#[allow(dead_code)]
pub struct TypedEffectKey<M> {
key: EffectKey,
_model: PhantomData<fn() -> M>,
}
#[doc(hidden)]
pub struct CompiledEffectKeyField<M>(EffectFieldValue, PhantomData<fn() -> M>);
#[doc(hidden)]
pub fn __effect_key_field<F>(
value: TypedEffectExpression<F::Value>,
) -> CompiledEffectKeyField<F::Model>
where
F: EffectModelFieldMarker,
{
CompiledEffectKeyField(
EffectFieldValue {
field: F::FIELD.to_string(),
value: value.__into_ir(),
},
PhantomData,
)
}
#[doc(hidden)]
pub fn __effect_key_assignment<F, Wire>(
value: TypedEffectExpression<F::Value, Wire>,
) -> TypedEffectExpression<F::Value>
where
F: EffectModelFieldMarker,
Wire: EffectWireCompatible<F::Wire>,
{
value.erase_wire()
}
#[doc(hidden)]
pub fn __effect_key<M: RelationalReadModel>(
fields: Vec<CompiledEffectKeyField<M>>,
) -> TypedEffectKey<M> {
TypedEffectKey {
key: EffectKey {
fields: fields.into_iter().map(|field| field.0).collect(),
},
_model: PhantomData,
}
}
#[doc(hidden)]
#[allow(dead_code)]
pub struct TypedEffectRelationship<S, T> {
relationship: EffectRelationship,
_models: PhantomData<fn(S) -> T>,
}
impl<S, T> TypedEffectRelationship<S, T> {}
#[doc(hidden)]
pub fn __effect_relationship<R>() -> TypedEffectRelationship<R::Source, R::Target>
where
R: EffectRelationshipMarker,
{
TypedEffectRelationship {
relationship: EffectRelationship {
source_model: R::Source::schema().model_name.clone(),
field: R::FIELD.to_string(),
target_model: R::Target::schema().model_name.clone(),
},
_models: PhantomData,
}
}
#[doc(hidden)]
pub struct CompiledInputDefault<I>(CommandInputDefault, PhantomData<fn(I)>);
pub struct CompiledInputDefaults<I>(pub(crate) Vec<CommandInputDefault>, PhantomData<fn(I)>);
#[doc(hidden)]
pub fn __input_default_uuid_v7<I, F>() -> CompiledInputDefault<I>
where
I: 'static,
F: EffectInputFieldMarker<Input = I, Value = String>,
{
CompiledInputDefault(
CommandInputDefault {
path: F::path().into_iter().map(str::to_string).collect(),
generator: InputDefaultGenerator::UuidV7,
},
PhantomData,
)
}
#[doc(hidden)]
pub fn __input_default_ulid<I, F>() -> CompiledInputDefault<I>
where
I: 'static,
F: EffectInputFieldMarker<Input = I, Value = String>,
{
CompiledInputDefault(
CommandInputDefault {
path: F::path().into_iter().map(str::to_string).collect(),
generator: InputDefaultGenerator::Ulid,
},
PhantomData,
)
}
#[doc(hidden)]
pub fn __command_input_defaults<I>(
defaults: impl IntoIterator<Item = CompiledInputDefault<I>>,
) -> CompiledInputDefaults<I> {
CompiledInputDefaults(
defaults.into_iter().map(|default| default.0).collect(),
PhantomData,
)
}