icydb_core/model/
entity.rs1use crate::model::{field::FieldModel, index::IndexModel};
7
8#[derive(Debug)]
17pub struct PrimaryKeyModel {
18 fields: PrimaryKeyModelFields,
19}
20
21impl PrimaryKeyModel {
22 #[must_use]
24 pub const fn scalar(field: &'static FieldModel) -> Self {
25 Self {
26 fields: PrimaryKeyModelFields::Scalar(field),
27 }
28 }
29
30 #[must_use]
32 pub const fn ordered(fields: &'static [&'static FieldModel]) -> Self {
33 assert!(!fields.is_empty(), "primary key model requires fields");
34 Self {
35 fields: PrimaryKeyModelFields::Ordered(fields),
36 }
37 }
38
39 #[must_use]
41 pub const fn len(&self) -> usize {
42 match self.fields {
43 PrimaryKeyModelFields::Scalar(_) => 1,
44 PrimaryKeyModelFields::Ordered(fields) => fields.len(),
45 }
46 }
47
48 #[must_use]
50 pub const fn is_empty(&self) -> bool {
51 self.len() == 0
52 }
53
54 #[must_use]
56 pub const fn is_scalar(&self) -> bool {
57 self.len() == 1
58 }
59
60 #[must_use]
62 pub const fn scalar_field(&self) -> &'static FieldModel {
63 match self.fields {
64 PrimaryKeyModelFields::Scalar(field) => field,
65 PrimaryKeyModelFields::Ordered(fields) => fields[0],
66 }
67 }
68
69 #[must_use]
71 pub const fn fields(&self) -> PrimaryKeyModelFields {
72 self.fields
73 }
74}
75
76#[derive(Clone, Copy, Debug)]
83pub enum PrimaryKeyModelFields {
84 Scalar(&'static FieldModel),
85 Ordered(&'static [&'static FieldModel]),
86}
87
88impl PrimaryKeyModelFields {
89 #[must_use]
91 pub const fn len(self) -> usize {
92 match self {
93 Self::Scalar(_) => 1,
94 Self::Ordered(fields) => fields.len(),
95 }
96 }
97
98 #[must_use]
100 pub const fn is_empty(self) -> bool {
101 self.len() == 0
102 }
103
104 #[must_use]
106 pub fn get(self, index: usize) -> Option<&'static FieldModel> {
107 match self {
108 Self::Scalar(field) => (index == 0).then_some(field),
109 Self::Ordered(fields) => fields.get(index).copied(),
110 }
111 }
112
113 #[must_use]
115 pub const fn iter(self) -> PrimaryKeyModelFieldIter {
116 PrimaryKeyModelFieldIter {
117 fields: self,
118 index: 0,
119 }
120 }
121}
122
123#[derive(Clone, Debug)]
130pub struct PrimaryKeyModelFieldIter {
131 fields: PrimaryKeyModelFields,
132 index: usize,
133}
134
135impl Iterator for PrimaryKeyModelFieldIter {
136 type Item = &'static FieldModel;
137
138 fn next(&mut self) -> Option<Self::Item> {
139 let item = self.fields.get(self.index)?;
140 self.index += 1;
141 Some(item)
142 }
143}
144
145#[cfg(test)]
146mod primary_key_model_tests {
147 use super::{PrimaryKeyModel, PrimaryKeyModelFields};
148 use crate::model::FieldModel;
149
150 static ID_FIELD: FieldModel = FieldModel::generated("id", crate::model::FieldKind::Nat64);
151 static TENANT_FIELD: FieldModel =
152 FieldModel::generated("tenant_id", crate::model::FieldKind::Nat64);
153 static ORDERED_FIELDS: [&FieldModel; 2] = [&ID_FIELD, &TENANT_FIELD];
154
155 #[test]
156 fn scalar_primary_key_model_exposes_one_field() {
157 let model = PrimaryKeyModel::scalar(&ID_FIELD);
158
159 assert_eq!(model.len(), 1);
160 assert!(model.is_scalar());
161 assert_eq!(model.scalar_field().name(), "id");
162 assert_eq!(
163 model
164 .fields()
165 .iter()
166 .map(FieldModel::name)
167 .collect::<Vec<_>>(),
168 ["id"]
169 );
170 }
171
172 #[test]
173 fn ordered_primary_key_model_preserves_field_order() {
174 let model = PrimaryKeyModel::ordered(&ORDERED_FIELDS);
175
176 assert_eq!(model.len(), 2);
177 assert!(!model.is_scalar());
178 assert_eq!(model.scalar_field().name(), "id");
179 assert_eq!(
180 model
181 .fields()
182 .iter()
183 .map(FieldModel::name)
184 .collect::<Vec<_>>(),
185 ["id", "tenant_id"],
186 );
187 assert!(matches!(model.fields(), PrimaryKeyModelFields::Ordered(_)));
188 }
189}
190
191#[derive(Debug)]
199pub struct EntityModel {
200 pub(crate) path: &'static str,
202
203 pub(crate) entity_name: &'static str,
205
206 pub(crate) primary_key: &'static FieldModel,
208
209 pub(crate) primary_key_slot: usize,
211
212 pub(crate) primary_key_model: PrimaryKeyModel,
214
215 pub(crate) fields: &'static [FieldModel],
217
218 pub(crate) indexes: &'static [&'static IndexModel],
220}
221
222impl EntityModel {
223 #[must_use]
229 #[doc(hidden)]
230 pub const fn generated(
231 path: &'static str,
232 entity_name: &'static str,
233 primary_key: &'static FieldModel,
234 primary_key_slot: usize,
235 fields: &'static [FieldModel],
236 indexes: &'static [&'static IndexModel],
237 ) -> Self {
238 Self {
239 path,
240 entity_name,
241 primary_key,
242 primary_key_slot,
243 primary_key_model: PrimaryKeyModel::scalar(primary_key),
244 fields,
245 indexes,
246 }
247 }
248
249 #[must_use]
252 #[doc(hidden)]
253 pub const fn generated_with_primary_key_model(
254 path: &'static str,
255 entity_name: &'static str,
256 primary_key_model: PrimaryKeyModel,
257 primary_key_slot: usize,
258 fields: &'static [FieldModel],
259 indexes: &'static [&'static IndexModel],
260 ) -> Self {
261 Self {
262 path,
263 entity_name,
264 primary_key: primary_key_model.scalar_field(),
265 primary_key_slot,
266 primary_key_model,
267 fields,
268 indexes,
269 }
270 }
271
272 #[must_use]
274 pub const fn path(&self) -> &'static str {
275 self.path
276 }
277
278 #[must_use]
280 pub const fn name(&self) -> &'static str {
281 self.entity_name
282 }
283
284 #[must_use]
286 pub const fn primary_key(&self) -> &'static FieldModel {
287 self.primary_key
288 }
289
290 #[must_use]
292 pub const fn primary_key_model(&self) -> &PrimaryKeyModel {
293 &self.primary_key_model
294 }
295
296 #[must_use]
298 pub fn primary_key_names(&self) -> Vec<&'static str> {
299 self.primary_key_model()
300 .fields()
301 .iter()
302 .map(crate::model::field::FieldModel::name)
303 .collect()
304 }
305
306 #[must_use]
308 pub const fn primary_key_slot(&self) -> usize {
309 self.primary_key_slot
310 }
311
312 #[must_use]
314 pub const fn fields(&self) -> &'static [FieldModel] {
315 self.fields
316 }
317
318 #[must_use]
320 pub const fn indexes(&self) -> &'static [&'static IndexModel] {
321 self.indexes
322 }
323
324 #[must_use]
326 pub(crate) fn resolve_field_slot(&self, field_name: &str) -> Option<usize> {
327 self.fields
328 .iter()
329 .position(|field| field.name == field_name)
330 }
331}