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(crate) name: &'static str,
16 /// Runtime type shape (no schema-layer graph nodes).
17 pub(crate) kind: FieldKind,
18}
19
20impl FieldModel {
21 /// Build one runtime field descriptor.
22 #[must_use]
23 pub const fn new(name: &'static str, kind: FieldKind) -> Self {
24 Self { name, kind }
25 }
26
27 /// Return the stable field name.
28 #[must_use]
29 pub const fn name(&self) -> &'static str {
30 self.name
31 }
32
33 /// Return the runtime type-kind descriptor.
34 #[must_use]
35 pub const fn kind(&self) -> FieldKind {
36 self.kind
37 }
38}
39
40///
41/// RelationStrength
42///
43/// Explicit relation intent for save-time referential integrity.
44///
45
46#[derive(Clone, Copy, Debug, Eq, PartialEq)]
47pub enum RelationStrength {
48 Strong,
49 Weak,
50}
51
52///
53/// FieldKind
54///
55/// Minimal runtime type surface needed by planning, validation, and execution.
56///
57/// This is aligned with `Value` variants and intentionally lossy: it encodes
58/// only the shape required for predicate compatibility and index planning.
59///
60
61#[derive(Clone, Copy, Debug)]
62pub enum FieldKind {
63 // Scalar primitives
64 Account,
65 Blob,
66 Bool,
67 Date,
68 Decimal {
69 /// Required schema-declared fractional scale for decimal fields.
70 scale: u32,
71 },
72 Duration,
73 Enum {
74 /// Fully-qualified enum type path used for strict filter normalization.
75 path: &'static str,
76 },
77 Float32,
78 Float64,
79 Int,
80 Int128,
81 IntBig,
82 Principal,
83 Subaccount,
84 Text,
85 Timestamp,
86 Uint,
87 Uint128,
88 UintBig,
89 Ulid,
90 Unit,
91
92 /// Typed relation; `key_kind` reflects the referenced key type.
93 /// `strength` encodes strong vs. weak relation intent.
94 Relation {
95 /// Fully-qualified Rust type path for diagnostics.
96 target_path: &'static str,
97 /// Stable external name used in storage keys.
98 target_entity_name: &'static str,
99 /// Data store path where the target entity is persisted.
100 target_store_path: &'static str,
101 key_kind: &'static Self,
102 strength: RelationStrength,
103 },
104
105 // Collections
106 List(&'static Self),
107 Set(&'static Self),
108 /// Deterministic, unordered key/value collection.
109 ///
110 /// Map fields are persistable and patchable, but not queryable or indexable.
111 Map {
112 key: &'static Self,
113 value: &'static Self,
114 },
115
116 /// Structured (non-atomic) value.
117 /// Queryability here controls whether predicates may target this field,
118 /// not whether it may be stored or updated.
119 Structured {
120 queryable: bool,
121 },
122}
123
124impl FieldKind {
125 #[must_use]
126 pub const fn value_kind(&self) -> FieldValueKind {
127 match self {
128 Self::Account
129 | Self::Blob
130 | Self::Bool
131 | Self::Date
132 | Self::Duration
133 | Self::Enum { .. }
134 | Self::Float32
135 | Self::Float64
136 | Self::Int
137 | Self::Int128
138 | Self::IntBig
139 | Self::Principal
140 | Self::Subaccount
141 | Self::Text
142 | Self::Timestamp
143 | Self::Uint
144 | Self::Uint128
145 | Self::UintBig
146 | Self::Ulid
147 | Self::Unit
148 | Self::Decimal { .. }
149 | Self::Relation { .. } => FieldValueKind::Atomic,
150 Self::List(_) | Self::Set(_) => FieldValueKind::Structured { queryable: true },
151 Self::Map { .. } => FieldValueKind::Structured { queryable: false },
152 Self::Structured { queryable } => FieldValueKind::Structured {
153 queryable: *queryable,
154 },
155 }
156 }
157
158 /// Returns `true` if this field shape is permitted in
159 /// persisted or query-visible schemas under the current
160 /// determinism policy.
161 ///
162 /// This shape-level check is structural only; query-time policy
163 /// enforcement (for example, map predicate fencing) is applied at
164 /// query construction and validation boundaries.
165 #[must_use]
166 pub const fn is_deterministic_collection_shape(&self) -> bool {
167 match self {
168 Self::Relation { key_kind, .. } => key_kind.is_deterministic_collection_shape(),
169
170 Self::List(inner) | Self::Set(inner) => inner.is_deterministic_collection_shape(),
171
172 Self::Map { key, value } => {
173 key.is_deterministic_collection_shape() && value.is_deterministic_collection_shape()
174 }
175
176 _ => true,
177 }
178 }
179}