icydb_core/model/entity.rs
1//! Runtime-only entity schema surface generated by macros.
2//!
3//! This model intentionally includes only:
4//! - entity metadata (path + stable external name)
5//! - ordered fields
6//! - primary key field
7//! - index definitions
8//!
9//! It intentionally excludes:
10//! - validators/sanitizers/defaults
11//! - relations or full schema graphs
12//! - JSON schema ingestion or global registries
13//!
14//! Stability: this is the authoritative runtime contract for planning and
15//! execution. Additive changes are expected; breaking changes require a
16//! coordinated version bump across the engine.
17//!
18//! Field names are entity-scoped. Callers that combine entities must
19//! namespace by entity at the call site.
20
21use crate::model::{field::FieldModel, index::IndexModel};
22
23///
24/// EntityModel
25///
26/// Macro-generated runtime schema snapshot for a single entity.
27/// The planner and predicate validator consume this model directly.
28///
29
30#[derive(Debug)]
31pub struct EntityModel {
32 /// Fully-qualified Rust type path (for diagnostics).
33 pub(crate) path: &'static str,
34
35 /// Stable external name used in keys and routing.
36 pub(crate) entity_name: &'static str,
37
38 /// Primary key field (points at an entry in `fields`).
39 pub(crate) primary_key: &'static FieldModel,
40
41 /// Ordered field list (authoritative for runtime planning).
42 pub(crate) fields: &'static [FieldModel],
43
44 /// Index definitions (field order is significant).
45 pub(crate) indexes: &'static [&'static IndexModel],
46}
47
48impl EntityModel {
49 /// Build one runtime entity schema descriptor.
50 #[must_use]
51 pub const fn new(
52 path: &'static str,
53 entity_name: &'static str,
54 primary_key: &'static FieldModel,
55 fields: &'static [FieldModel],
56 indexes: &'static [&'static IndexModel],
57 ) -> Self {
58 Self {
59 path,
60 entity_name,
61 primary_key,
62 fields,
63 indexes,
64 }
65 }
66
67 /// Return the fully-qualified Rust path for this entity.
68 #[must_use]
69 pub const fn path(&self) -> &'static str {
70 self.path
71 }
72
73 /// Return the stable external entity name.
74 #[must_use]
75 pub const fn entity_name(&self) -> &'static str {
76 self.entity_name
77 }
78
79 /// Return the primary-key field descriptor.
80 #[must_use]
81 pub const fn primary_key(&self) -> &'static FieldModel {
82 self.primary_key
83 }
84
85 /// Return the ordered runtime field descriptors.
86 #[must_use]
87 pub const fn fields(&self) -> &'static [FieldModel] {
88 self.fields
89 }
90
91 /// Return the runtime index descriptors.
92 #[must_use]
93 pub const fn indexes(&self) -> &'static [&'static IndexModel] {
94 self.indexes
95 }
96}
97
98/// Resolve one schema field name into its stable slot index.
99#[must_use]
100pub(crate) fn resolve_field_slot(model: &EntityModel, field_name: &str) -> Option<usize> {
101 model
102 .fields
103 .iter()
104 .position(|field| field.name == field_name)
105}
106
107/// Resolve the primary-key field into its stable slot index.
108#[must_use]
109pub(crate) fn resolve_primary_key_slot(model: &EntityModel) -> Option<usize> {
110 model
111 .fields
112 .iter()
113 .position(|field| std::ptr::eq(field, model.primary_key))
114}