Skip to main content

icydb_core/
entity.rs

1//! Module: entity
2//!
3//! Responsibility: typed entity declaration, placement, value, creation, and
4//! singleton contracts.
5//! Does not own: accepted schema authority, persisted-row codecs, key byte
6//! formats, or generated model reconciliation.
7//! Boundary: generated/model proposals and typed values -> database runtime.
8
9use crate::{
10    db::EntityKey,
11    model::EntityModel,
12    traits::{AuthoredFieldProjection, CanisterKind, FieldProjection, StoreKind, TypeKind},
13    types::{EntityTag, Id},
14    value::InputValue,
15};
16
17/// Generated declaration facts for an entity type.
18///
19/// `NAME` seeds self-referential generated relation metadata. `MODEL` is a
20/// proposal consumed during reconciliation; accepted schema snapshots remain
21/// the runtime authority for storage, planning, and execution.
22pub trait EntityDeclaration: EntityKey {
23    /// Stable schema-visible entity name.
24    const NAME: &'static str;
25
26    /// Generated model proposal for reconciliation and model-only tooling.
27    const MODEL: &'static EntityModel;
28}
29
30/// Runtime placement of an entity in one store and canister.
31pub trait EntityPlacement {
32    /// Store that owns the entity's rows.
33    type Store: StoreKind<Canister = Self::Canister>;
34
35    /// Canister that owns the declared store.
36    type Canister: CanisterKind;
37}
38
39/// Declaration- and placement-bound entity model.
40///
41/// This contract is sufficient for proposal-based, model-only planning and
42/// does not imply that `Self` is a materializable entity value. Stored runtime
43/// entities prove that additional capability through `PersistedRow`.
44pub trait EntityKind: EntityDeclaration + EntityPlacement + TypeKind {
45    /// Stable compact entity identity used by runtime routing.
46    const ENTITY_TAG: EntityTag;
47}
48
49/// A concrete entity value that can present a typed identity at boundaries.
50///
51/// Implementors store primitive key material internally. `id()` constructs a
52/// typed `Id<Self>` view on demand; that identifier is not proof of authority.
53pub trait EntityValue: EntityKey + AuthoredFieldProjection + FieldProjection + Sized {
54    /// Return this value's typed entity identity.
55    fn id(&self) -> Id<Self>;
56}
57
58/// One authored field carried by a generated typed create input.
59///
60/// The stable slot identifies the generated field proposal; the accepted row
61/// contract validates that identity before admitting the unresolved value.
62pub struct EntityCreateFieldInput {
63    slot: usize,
64    value: InputValue,
65}
66
67impl EntityCreateFieldInput {
68    /// Build one authored create-field input from a generated stable slot.
69    #[must_use]
70    pub const fn new(slot: usize, value: InputValue) -> Self {
71        Self { slot, value }
72    }
73
74    /// Return the generated stable field slot.
75    #[must_use]
76    pub const fn slot(&self) -> usize {
77        self.slot
78    }
79
80    /// Consume and return the unresolved authored value.
81    #[must_use]
82    pub fn into_value(self) -> InputValue {
83        self.value
84    }
85}
86
87/// Create-authored typed input for one entity.
88///
89/// This is intentionally distinct from the readable entity shape so generated
90/// and managed fields remain structurally un-authorable on typed creates.
91pub trait EntityCreateInput: Sized {
92    /// Entity materialized by this input.
93    type Entity: EntityValue;
94
95    /// Lower this DTO to exact authored field inputs without resolving omissions.
96    fn into_authored_fields(self) -> Vec<EntityCreateFieldInput>;
97}
98
99/// Entity-owned association with its generated create-input shape.
100pub trait EntityCreateType: EntityValue {
101    /// Generated authored create-input type.
102    type Create: EntityCreateInput<Entity = Self>;
103}
104
105mod singleton {
106    pub trait Key {}
107
108    impl Key for () {}
109    impl Key for crate::types::Unit {}
110
111    pub trait Sealed {}
112
113    impl<E> Sealed for E
114    where
115        E: super::EntityValue,
116        E::Key: Key,
117    {
118    }
119}
120
121/// Marker for entities whose unit key proves one logical row.
122pub trait SingletonEntity: EntityValue + singleton::Sealed {}
123
124impl<E> SingletonEntity for E where E: EntityValue + singleton::Sealed {}