Skip to main content

icydb_core/model/
entity.rs

1//! Module: model::entity
2//! Responsibility: module-local ownership and contracts for model::entity.
3//! Does not own: cross-module orchestration outside this module.
4//! Boundary: exposes this module API while keeping implementation details internal.
5
6//! Runtime-only entity schema surface generated by macros.
7//!
8//! This model intentionally includes only:
9//! - entity metadata (path + stable external name)
10//! - ordered fields
11//! - primary key field
12//! - index definitions
13//!
14//! It intentionally excludes:
15//! - validators/sanitizers/defaults
16//! - relations or full schema graphs
17//! - JSON schema ingestion or global registries
18//!
19//! Stability: this is the authoritative runtime contract for planning and
20//! execution. Additive changes are expected; breaking changes require a
21//! coordinated version bump across the engine.
22//!
23//! Field names are entity-scoped. Callers that combine entities must
24//! namespace by entity at the call site.
25
26use crate::model::{field::FieldModel, index::IndexModel};
27
28///
29/// EntityModel
30///
31/// Macro-generated runtime schema snapshot for a single entity.
32/// The planner and predicate validator consume this model directly.
33///
34
35#[derive(Debug)]
36pub struct EntityModel {
37    /// Fully-qualified Rust type path (for diagnostics).
38    pub(crate) path: &'static str,
39
40    /// Stable external name used in keys and routing.
41    pub(crate) entity_name: &'static str,
42
43    /// Primary key field (points at an entry in `fields`).
44    pub(crate) primary_key: &'static FieldModel,
45
46    /// Stable primary-key slot within `fields`.
47    pub(crate) primary_key_slot: usize,
48
49    /// Ordered field list (authoritative for runtime planning).
50    pub(crate) fields: &'static [FieldModel],
51
52    /// Index definitions (field order is significant).
53    pub(crate) indexes: &'static [&'static IndexModel],
54}
55
56impl EntityModel {
57    /// Construct one generated runtime entity descriptor.
58    ///
59    /// This constructor exists for derive/codegen output. Runtime query and
60    /// executor code treat `EntityModel` values as already validated build-time
61    /// artifacts and do not perform defensive model-shape validation per call.
62    #[must_use]
63    #[doc(hidden)]
64    pub const fn generated(
65        path: &'static str,
66        entity_name: &'static str,
67        primary_key: &'static FieldModel,
68        primary_key_slot: usize,
69        fields: &'static [FieldModel],
70        indexes: &'static [&'static IndexModel],
71    ) -> Self {
72        Self {
73            path,
74            entity_name,
75            primary_key,
76            primary_key_slot,
77            fields,
78            indexes,
79        }
80    }
81
82    /// Return the fully-qualified Rust path for this entity.
83    #[must_use]
84    pub const fn path(&self) -> &'static str {
85        self.path
86    }
87
88    /// Return the stable external entity name.
89    #[must_use]
90    pub const fn name(&self) -> &'static str {
91        self.entity_name
92    }
93
94    /// Return the primary-key field descriptor.
95    #[must_use]
96    pub const fn primary_key(&self) -> &'static FieldModel {
97        self.primary_key
98    }
99
100    /// Return the stable primary-key slot within the ordered field table.
101    #[must_use]
102    pub const fn primary_key_slot(&self) -> usize {
103        self.primary_key_slot
104    }
105
106    /// Return the ordered runtime field descriptors.
107    #[must_use]
108    pub const fn fields(&self) -> &'static [FieldModel] {
109        self.fields
110    }
111
112    /// Return the runtime index descriptors.
113    #[must_use]
114    pub const fn indexes(&self) -> &'static [&'static IndexModel] {
115        self.indexes
116    }
117}
118
119/// Resolve one schema field name into its stable slot index.
120#[must_use]
121pub(crate) fn resolve_field_slot(model: &EntityModel, field_name: &str) -> Option<usize> {
122    model
123        .fields
124        .iter()
125        .position(|field| field.name == field_name)
126}
127
128/// Resolve the primary-key field into its stable slot index.
129#[must_use]
130pub(crate) const fn resolve_primary_key_slot(model: &EntityModel) -> usize {
131    model.primary_key_slot()
132}