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}