Skip to main content

icydb_core/model/
field.rs

1use crate::traits::FieldValueKind;
2
3///
4/// EntityFieldModel
5///
6/// Runtime field metadata surfaced by macro-generated `EntityModel` values.
7///
8/// This is the smallest unit consumed by predicate validation, planning,
9/// and executor-side plan checks.
10///
11
12#[derive(Debug)]
13pub struct EntityFieldModel {
14    /// Field name as used in predicates and indexing.
15    pub name: &'static str,
16    /// Runtime type shape (no schema-layer graph nodes).
17    pub kind: EntityFieldKind,
18}
19
20///
21/// RelationStrength
22///
23/// Explicit relation intent for save-time referential integrity.
24///
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub enum RelationStrength {
28    Strong,
29    Weak,
30}
31
32///
33/// EntityFieldKind
34///
35/// Minimal runtime type surface needed by planning, validation, and execution.
36///
37/// This is aligned with `Value` variants and intentionally lossy: it encodes
38/// only the shape required for predicate compatibility and index planning.
39///
40
41#[derive(Debug)]
42pub enum EntityFieldKind {
43    // Scalar primitives
44    Account,
45    Blob,
46    Bool,
47    Date,
48    Decimal,
49    Duration,
50    Enum,
51    E8s,
52    E18s,
53    Float32,
54    Float64,
55    Int,
56    Int128,
57    IntBig,
58    Principal,
59    Subaccount,
60    Text,
61    Timestamp,
62    Uint,
63    Uint128,
64    UintBig,
65    Ulid,
66    Unit,
67
68    /// Typed entity reference; `key_kind` reflects the referenced key type.
69    /// `strength` encodes strong vs. weak relation intent.
70    Ref {
71        /// Fully-qualified Rust type path for diagnostics.
72        target_path: &'static str,
73        /// Stable external name used in storage keys.
74        target_entity_name: &'static str,
75        /// Data store path where the target entity is persisted.
76        target_store_path: &'static str,
77        key_kind: &'static Self,
78        strength: RelationStrength,
79    },
80
81    // Collections
82    List(&'static Self),
83    Set(&'static Self),
84    Map {
85        key: &'static Self,
86        value: &'static Self,
87    },
88
89    /// Structured (non-atomic) value.
90    /// Queryability here controls whether predicates may target this field,
91    /// not whether it may be stored or updated.
92    Structured {
93        queryable: bool,
94    },
95}
96
97impl EntityFieldKind {
98    #[must_use]
99    pub const fn value_kind(&self) -> FieldValueKind {
100        match self {
101            Self::Account
102            | Self::Blob
103            | Self::Bool
104            | Self::Date
105            | Self::Decimal
106            | Self::Duration
107            | Self::Enum
108            | Self::E8s
109            | Self::E18s
110            | Self::Float32
111            | Self::Float64
112            | Self::Int
113            | Self::Int128
114            | Self::IntBig
115            | Self::Principal
116            | Self::Subaccount
117            | Self::Text
118            | Self::Timestamp
119            | Self::Uint
120            | Self::Uint128
121            | Self::UintBig
122            | Self::Ulid
123            | Self::Unit
124            | Self::Ref { .. } => FieldValueKind::Atomic,
125            Self::List(_) | Self::Set(_) => FieldValueKind::Structured { queryable: true },
126            Self::Map { .. } => FieldValueKind::Structured { queryable: false },
127            Self::Structured { queryable } => FieldValueKind::Structured {
128                queryable: *queryable,
129            },
130        }
131    }
132
133    /// Returns `true` if this field shape is permitted in
134    /// persisted or query-visible schemas under the current
135    /// determinism policy.
136    ///
137    /// This shape-level check is structural only; query-time policy
138    /// enforcement (for example, map predicate fencing) is applied at
139    /// query construction and validation boundaries.
140    #[must_use]
141    pub const fn is_deterministic_collection_shape(&self) -> bool {
142        match self {
143            Self::Ref { key_kind, .. } => key_kind.is_deterministic_collection_shape(),
144
145            Self::List(inner) | Self::Set(inner) => inner.is_deterministic_collection_shape(),
146
147            Self::Map { key, value } => {
148                key.is_deterministic_collection_shape() && value.is_deterministic_collection_shape()
149            }
150
151            _ => true,
152        }
153    }
154}