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    error::InternalError,
12    model::EntityModel,
13    traits::{AuthoredFieldProjection, CanisterKind, FieldProjection, StoreKind, TypeKind},
14    types::{EntityTag, Id},
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/// Materialized authored create payload produced by one generated create input.
59///
60/// Carries both the fully typed entity after-image and authored field slots so
61/// save preflight can distinguish omission from authorship.
62pub struct EntityCreateMaterialization<E> {
63    entity: E,
64    authored_slots: Vec<usize>,
65}
66
67impl<E> EntityCreateMaterialization<E> {
68    /// Build one materialized typed create payload.
69    #[must_use]
70    pub const fn new(entity: E, authored_slots: Vec<usize>) -> Self {
71        Self {
72            entity,
73            authored_slots,
74        }
75    }
76
77    /// Consume and return the typed entity after-image.
78    #[must_use]
79    pub fn into_entity(self) -> E {
80        self.entity
81    }
82
83    /// Borrow the authored field slots carried by this insert payload.
84    #[must_use]
85    pub const fn authored_slots(&self) -> &[usize] {
86        self.authored_slots.as_slice()
87    }
88}
89
90/// Create-authored typed input for one entity.
91///
92/// This is intentionally distinct from the readable entity shape so generated
93/// and managed fields remain structurally un-authorable on typed creates.
94pub trait EntityCreateInput: Sized {
95    /// Entity materialized by this input.
96    type Entity: EntityValue;
97
98    /// Materialize one typed create payload plus authored-slot provenance.
99    fn materialize_create(self)
100    -> Result<EntityCreateMaterialization<Self::Entity>, InternalError>;
101}
102
103/// Entity-owned association with its generated create-input shape.
104pub trait EntityCreateType: EntityValue {
105    /// Generated authored create-input type.
106    type Create: EntityCreateInput<Entity = Self>;
107}
108
109mod singleton {
110    pub trait Key {}
111
112    impl Key for () {}
113    impl Key for crate::types::Unit {}
114
115    pub trait Sealed {}
116
117    impl<E> Sealed for E
118    where
119        E: super::EntityValue,
120        E::Key: Key,
121    {
122    }
123}
124
125/// Marker for entities whose unit key proves one logical row.
126pub trait SingletonEntity: EntityValue + singleton::Sealed {}
127
128impl<E> SingletonEntity for E where E: EntityValue + singleton::Sealed {}