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 relation; `key_kind` reflects the referenced key type.
69    /// `strength` encodes strong vs. weak relation intent.
70    Relation {
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    /// Deterministic, unordered key/value collection.
85    ///
86    /// Map fields are persistable and patchable, but not queryable or indexable.
87    Map {
88        key: &'static Self,
89        value: &'static Self,
90    },
91
92    /// Structured (non-atomic) value.
93    /// Queryability here controls whether predicates may target this field,
94    /// not whether it may be stored or updated.
95    Structured {
96        queryable: bool,
97    },
98}
99
100impl EntityFieldKind {
101    #[must_use]
102    pub const fn value_kind(&self) -> FieldValueKind {
103        match self {
104            Self::Account
105            | Self::Blob
106            | Self::Bool
107            | Self::Date
108            | Self::Decimal
109            | Self::Duration
110            | Self::Enum
111            | Self::E8s
112            | Self::E18s
113            | Self::Float32
114            | Self::Float64
115            | Self::Int
116            | Self::Int128
117            | Self::IntBig
118            | Self::Principal
119            | Self::Subaccount
120            | Self::Text
121            | Self::Timestamp
122            | Self::Uint
123            | Self::Uint128
124            | Self::UintBig
125            | Self::Ulid
126            | Self::Unit
127            | Self::Relation { .. } => FieldValueKind::Atomic,
128            Self::List(_) | Self::Set(_) => FieldValueKind::Structured { queryable: true },
129            Self::Map { .. } => FieldValueKind::Structured { queryable: false },
130            Self::Structured { queryable } => FieldValueKind::Structured {
131                queryable: *queryable,
132            },
133        }
134    }
135
136    /// Returns `true` if this field shape is permitted in
137    /// persisted or query-visible schemas under the current
138    /// determinism policy.
139    ///
140    /// This shape-level check is structural only; query-time policy
141    /// enforcement (for example, map predicate fencing) is applied at
142    /// query construction and validation boundaries.
143    #[must_use]
144    pub const fn is_deterministic_collection_shape(&self) -> bool {
145        match self {
146            Self::Relation { key_kind, .. } => key_kind.is_deterministic_collection_shape(),
147
148            Self::List(inner) | Self::Set(inner) => inner.is_deterministic_collection_shape(),
149
150            Self::Map { key, value } => {
151                key.is_deterministic_collection_shape() && value.is_deterministic_collection_shape()
152            }
153
154            _ => true,
155        }
156    }
157}