Skip to main content

icydb_core/model/
field.rs

1use crate::traits::FieldValueKind;
2
3///
4/// FieldModel
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 FieldModel {
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: FieldKind,
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/// FieldKind
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(Clone, Copy, Debug)]
42pub enum FieldKind {
43    // Scalar primitives
44    Account,
45    Blob,
46    Bool,
47    Date,
48    Decimal,
49    Duration,
50    Enum {
51        /// Fully-qualified enum type path used for strict filter normalization.
52        path: &'static str,
53    },
54    E8s,
55    E18s,
56    Float32,
57    Float64,
58    Int,
59    Int128,
60    IntBig,
61    Principal,
62    Subaccount,
63    Text,
64    Timestamp,
65    Uint,
66    Uint128,
67    UintBig,
68    Ulid,
69    Unit,
70
71    /// Typed relation; `key_kind` reflects the referenced key type.
72    /// `strength` encodes strong vs. weak relation intent.
73    Relation {
74        /// Fully-qualified Rust type path for diagnostics.
75        target_path: &'static str,
76        /// Stable external name used in storage keys.
77        target_entity_name: &'static str,
78        /// Data store path where the target entity is persisted.
79        target_store_path: &'static str,
80        key_kind: &'static Self,
81        strength: RelationStrength,
82    },
83
84    // Collections
85    List(&'static Self),
86    Set(&'static Self),
87    /// Deterministic, unordered key/value collection.
88    ///
89    /// Map fields are persistable and patchable, but not queryable or indexable.
90    Map {
91        key: &'static Self,
92        value: &'static Self,
93    },
94
95    /// Structured (non-atomic) value.
96    /// Queryability here controls whether predicates may target this field,
97    /// not whether it may be stored or updated.
98    Structured {
99        queryable: bool,
100    },
101}
102
103impl FieldKind {
104    #[must_use]
105    pub const fn value_kind(&self) -> FieldValueKind {
106        match self {
107            Self::Account
108            | Self::Blob
109            | Self::Bool
110            | Self::Date
111            | Self::Decimal
112            | Self::Duration
113            | Self::Enum { .. }
114            | Self::E8s
115            | Self::E18s
116            | Self::Float32
117            | Self::Float64
118            | Self::Int
119            | Self::Int128
120            | Self::IntBig
121            | Self::Principal
122            | Self::Subaccount
123            | Self::Text
124            | Self::Timestamp
125            | Self::Uint
126            | Self::Uint128
127            | Self::UintBig
128            | Self::Ulid
129            | Self::Unit
130            | Self::Relation { .. } => FieldValueKind::Atomic,
131            Self::List(_) | Self::Set(_) => FieldValueKind::Structured { queryable: true },
132            Self::Map { .. } => FieldValueKind::Structured { queryable: false },
133            Self::Structured { queryable } => FieldValueKind::Structured {
134                queryable: *queryable,
135            },
136        }
137    }
138
139    /// Returns `true` if this field shape is permitted in
140    /// persisted or query-visible schemas under the current
141    /// determinism policy.
142    ///
143    /// This shape-level check is structural only; query-time policy
144    /// enforcement (for example, map predicate fencing) is applied at
145    /// query construction and validation boundaries.
146    #[must_use]
147    pub const fn is_deterministic_collection_shape(&self) -> bool {
148        match self {
149            Self::Relation { key_kind, .. } => key_kind.is_deterministic_collection_shape(),
150
151            Self::List(inner) | Self::Set(inner) => inner.is_deterministic_collection_shape(),
152
153            Self::Map { key, value } => {
154                key.is_deterministic_collection_shape() && value.is_deterministic_collection_shape()
155            }
156
157            _ => true,
158        }
159    }
160}