1use serde::{Deserialize, Serialize};
2use std::{collections::HashMap, error, mem::discriminant, sync::Arc};
3
4use crate::{
5 data::{
6 entity_schema::Complete, now, request::PushCondition, EntityType, FieldType, Timestamp
7 },
8 sadd, sread, sref, sreflist, sstr, ssub, swrite, AdjustBehavior, Entity, EntityId,
9 EntitySchema, Field, FieldSchema, Request, Result, Single, Snowflake, Value,
10};
11
12#[derive(Debug, Clone)]
13pub struct EntityExists(EntityId);
14impl error::Error for EntityExists {}
15impl std::fmt::Display for EntityExists {
16 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17 write!(f, "Entity already exists: {}", self.0)
18 }
19}
20
21#[derive(Debug, Clone)]
22pub struct EntityTypeNotFound(EntityType);
23impl error::Error for EntityTypeNotFound {}
24impl std::fmt::Display for EntityTypeNotFound {
25 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26 write!(f, "Unknown entity type: {}", self.0)
27 }
28}
29
30#[derive(Debug, Clone)]
31pub struct EntityNotFound(EntityId);
32impl error::Error for EntityNotFound {}
33impl std::fmt::Display for EntityNotFound {
34 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
35 write!(f, "Entity not found: {}", self.0)
36 }
37}
38
39#[derive(Debug, Clone)]
40pub struct FieldNotFound(EntityId, FieldType);
41impl error::Error for FieldNotFound {}
42impl std::fmt::Display for FieldNotFound {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 write!(f, "Field not found for entity {}: {}", self.0, self.1)
45 }
46}
47
48#[derive(Debug, Clone)]
49pub struct ValueTypeMismatch(EntityId, FieldType, Value, Value);
50impl error::Error for ValueTypeMismatch {}
51impl std::fmt::Display for ValueTypeMismatch {
52 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53 write!(
54 f,
55 "Value type mismatch for entity {} field {}: expected {:?}, got {:?}",
56 self.0, self.1, self.2, self.3
57 )
58 }
59}
60
61#[derive(Debug, Clone)]
62pub struct UnsupportAdjustBehavior(EntityId, FieldType, AdjustBehavior);
63impl error::Error for UnsupportAdjustBehavior {}
64impl std::fmt::Display for UnsupportAdjustBehavior {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 write!(
67 f,
68 "Unsupported adjust behavior for entity {} field {}: {:?}",
69 self.0, self.1, self.2
70 )
71 }
72}
73
74#[derive(Debug, Clone)]
75pub enum BadIndirectionReason {
76 NegativeIndex(i64),
77 ArrayIndexOutOfBounds(usize, usize),
78 EmptyEntityReference,
79 InvalidEntityId(EntityId),
80 UnexpectedValueType(FieldType, String),
81 ExpectedIndexAfterEntityList(FieldType),
82 FailedToResolveField(FieldType, String),
83}
84
85#[derive(Debug, Clone)]
86pub struct BadIndirection {
87 entity_id: EntityId,
88 field_type: FieldType,
89 reason: BadIndirectionReason,
90}
91
92impl BadIndirection {
93 pub fn new(entity_id: EntityId, field_type: FieldType, reason: BadIndirectionReason) -> Self {
94 BadIndirection {
95 entity_id,
96 field_type,
97 reason,
98 }
99 }
100}
101
102impl error::Error for BadIndirection {}
103
104impl std::fmt::Display for BadIndirection {
105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106 write!(
107 f,
108 "Bad indirection for entity {}, field {}: ",
109 self.entity_id, self.field_type
110 )?;
111 match &self.reason {
112 BadIndirectionReason::NegativeIndex(index) => {
113 write!(f, "negative index: {}", index)
114 }
115 BadIndirectionReason::ArrayIndexOutOfBounds(index, size) => {
116 write!(f, "array index out of bounds: {} >= {}", index, size)
117 }
118 BadIndirectionReason::EmptyEntityReference => {
119 write!(f, "empty entity reference")
120 }
121 BadIndirectionReason::InvalidEntityId(id) => {
122 write!(f, "invalid entity id: {}", id)
123 }
124 BadIndirectionReason::UnexpectedValueType(field, value) => {
125 write!(f, "unexpected value type for field {}: {}", field, value)
126 }
127 BadIndirectionReason::ExpectedIndexAfterEntityList(field) => {
128 write!(f, "expected index after EntityList, got: {}", field)
129 }
130 BadIndirectionReason::FailedToResolveField(field, error) => {
131 write!(f, "failed to resolve field {}: {}", field, error)
132 }
133 }
134 }
135}
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct Context {}
139
140#[derive(Debug, Clone, Serialize, Deserialize)]
142pub struct Snapshot {
143 schemas: HashMap<EntityType, EntitySchema<Single>>,
144 entities: HashMap<EntityType, Vec<EntityId>>,
145 types: Vec<EntityType>,
146 fields: HashMap<EntityId, HashMap<FieldType, Field>>,
147}
148
149#[derive(Debug, Clone)]
151pub struct PageOpts {
152 pub limit: usize,
154 pub cursor: Option<String>,
156}
157
158impl Default for PageOpts {
159 fn default() -> Self {
160 PageOpts {
161 limit: 100,
162 cursor: None,
163 }
164 }
165}
166
167impl PageOpts {
168 pub fn new(limit: usize, cursor: Option<String>) -> Self {
169 PageOpts { limit, cursor }
170 }
171}
172
173#[derive(Debug, Clone)]
175pub struct PageResult<T> {
176 pub items: Vec<T>,
178 pub total: usize,
180 pub next_cursor: Option<String>,
182}
183
184impl<T> PageResult<T> {
185 pub fn new(items: Vec<T>, total: usize, next_cursor: Option<String>) -> Self {
186 PageResult {
187 items,
188 total,
189 next_cursor,
190 }
191 }
192}
193
194pub struct Store {
195 schemas: HashMap<EntityType, EntitySchema<Single>>,
196 entities: HashMap<EntityType, Vec<EntityId>>,
197 types: Vec<EntityType>,
198 fields: HashMap<EntityId, HashMap<FieldType, Field>>,
199 snowflake: Arc<Snowflake>,
200}
201
202impl Store {
203 pub fn new(snowflake: Arc<Snowflake>) -> Self {
204 Store {
205 schemas: HashMap::new(),
206 entities: HashMap::new(),
207 types: Vec::new(),
208 fields: HashMap::new(),
209 snowflake,
210 }
211 }
212
213 pub fn create_entity(
214 &mut self,
215 ctx: &Context,
216 entity_type: &EntityType,
217 parent_id: Option<EntityId>,
218 name: &str,
219 ) -> Result<Entity> {
220 if !self.schemas.contains_key(&entity_type) {
221 return Err(EntityTypeNotFound(entity_type.clone()).into());
222 }
223
224 if let Some(parent) = &parent_id {
225 if !self.entity_exists(ctx, &parent) {
226 return Err(EntityNotFound(parent.clone()).into());
227 }
228 }
229
230 let entity_id = EntityId::new(entity_type.clone(), self.snowflake.generate());
231 if self.fields.contains_key(&entity_id) {
232 return Err(EntityExists(entity_id).into());
233 }
234
235 {
236 let entities = self
237 .entities
238 .entry(entity_type.clone())
239 .or_insert_with(Vec::new);
240 entities.push(entity_id.clone());
241 }
242
243 {
244 self.fields
245 .entry(entity_id.clone())
246 .or_insert_with(HashMap::new);
247 }
248
249 {
250 let mut writes = self
251 .schemas
252 .get(entity_type)
253 .map(|s| &s.fields)
254 .into_iter()
255 .flat_map(|fields| fields.iter())
256 .map(|(field_type, _)| match field_type.as_ref() {
257 "Name" => {
258 swrite!(entity_id.clone(), field_type.clone(), sstr!(name))
259 }
260 "Parent" => match &parent_id {
261 Some(parent) => swrite!(
262 entity_id.clone(),
263 field_type.clone(),
264 sref!(Some(parent.clone()))
265 ),
266 None => swrite!(entity_id.clone(), field_type.clone()),
267 },
268 _ => {
269 swrite!(entity_id.clone(), field_type.clone())
271 }
272 })
273 .collect::<Vec<Request>>();
274
275 if let Some(parent) = &parent_id {
277 writes.push(sadd!(
278 parent.clone(),
279 "Children".into(),
280 sreflist![entity_id.clone()]
281 ));
282 }
283
284 self.perform(ctx, &mut writes)?;
285 }
286
287 Ok(Entity::new(entity_id))
288 }
289
290 pub fn get_entity_schema(
291 &self,
292 _: &Context,
293 entity_type: &EntityType,
294 ) -> Result<EntitySchema<Single>> {
295 self.schemas
296 .get(entity_type)
297 .cloned()
298 .ok_or_else(|| EntityTypeNotFound(entity_type.clone()).into())
299 }
300
301 pub fn get_complete_entity_schema(
302 &self,
303 ctx: &Context,
304 entity_type: &EntityType,
305 ) -> Result<EntitySchema<Complete>> {
306 let mut schema = EntitySchema::<Complete>::from(self.get_entity_schema(ctx, entity_type)?);
307
308 loop {
309 if let Some(inherit_type) = &schema.inherit {
310 if let Some(inherit_schema) = self.schemas.get(inherit_type) {
311 for (field_type, field_schema) in &inherit_schema.fields {
313 schema
314 .fields
315 .entry(field_type.clone())
316 .or_insert_with(|| field_schema.clone());
317 }
318 } else {
319 return Err(EntityTypeNotFound(inherit_type.clone()).into());
320 }
321 } else {
322 break;
323 }
324 }
325
326 Ok(schema)
327 }
328
329 pub fn set_entity_schema(
331 &mut self,
332 ctx: &Context,
333 entity_schema: &EntitySchema<Single>,
334 ) -> Result<()> {
335 let complete_old_schema = self
338 .get_complete_entity_schema(ctx, &entity_schema.entity_type)
339 .unwrap_or_else(|_| EntitySchema::<Complete>::new(entity_schema.entity_type.clone()));
340
341 self.schemas
342 .insert(entity_schema.entity_type.clone(), entity_schema.clone());
343
344 if !self.entities.contains_key(&entity_schema.entity_type) {
345 self.entities
346 .insert(entity_schema.entity_type.clone(), Vec::new());
347 }
348
349 if !self.types.contains(&entity_schema.entity_type) {
350 self.types.push(entity_schema.entity_type.clone());
351 }
352
353 let complete_new_schema =
355 self.get_complete_entity_schema(ctx, &entity_schema.entity_type)?;
356
357 for removed_field in complete_old_schema.diff(&complete_new_schema) {
358 for entity_id in self
360 .entities
361 .get(&entity_schema.entity_type)
362 .unwrap_or(&Vec::new())
363 {
364 if let Some(fields) = self.fields.get_mut(entity_id) {
365 fields.remove(&removed_field.field_type);
366 }
367 }
368 }
369
370 for added_field in complete_new_schema.diff(&complete_old_schema) {
371 for entity_id in self
373 .entities
374 .get(&entity_schema.entity_type)
375 .unwrap_or(&Vec::new())
376 {
377 let fields = self
378 .fields
379 .entry(entity_id.clone())
380 .or_insert_with(HashMap::new);
381 fields.insert(
382 added_field.field_type.clone(),
383 Field {
384 field_type: added_field.field_type.clone(),
385 value: added_field.default_value.clone(),
386 write_time: now(),
387 writer_id: None,
388 },
389 );
390 }
391 }
392
393 Ok(())
394 }
395
396 pub fn get_field_schema(
398 &self,
399 ctx: &Context,
400 entity_type: &EntityType,
401 field_type: &FieldType,
402 ) -> Result<FieldSchema> {
403 self
404 .get_entity_schema(ctx, entity_type)?
405 .fields
406 .get(field_type)
407 .cloned()
408 .ok_or_else(|| {
409 FieldNotFound(EntityId::new(entity_type.clone(), 0), field_type.clone()).into()
410 })
411 }
412
413 pub fn set_field_schema(
415 &mut self,
416 ctx: &Context,
417 entity_type: &EntityType,
418 field_type: &FieldType,
419 field_schema: FieldSchema,
420 ) -> Result<()> {
421 let mut entity_schema = self
422 .get_entity_schema(ctx, entity_type)?;
423
424 entity_schema.fields.insert(field_type.clone(), field_schema);
425
426 self.set_entity_schema(ctx, &entity_schema)
427 }
428
429 pub fn entity_exists(&self, _: &Context, entity_id: &EntityId) -> bool {
430 self.fields.contains_key(entity_id)
431 }
432
433 pub fn field_exists(
434 &self,
435 _: &Context,
436 entity_type: &EntityType,
437 field_type: &FieldType,
438 ) -> bool {
439 self.schemas
440 .get(entity_type)
441 .map(|schema| schema.fields.contains_key(field_type))
442 .unwrap_or(false)
443 }
444
445 pub fn perform(&mut self, ctx: &Context, requests: &mut Vec<Request>) -> Result<()> {
446 for request in requests.iter_mut() {
447 match request {
448 Request::Read {
449 entity_id,
450 field_type,
451 value,
452 write_time,
453 writer_id,
454 } => {
455 let indir: (EntityId, FieldType) =
456 resolve_indirection(ctx, self, entity_id, field_type)?;
457 self.read(ctx, &indir.0, &indir.1, value, write_time, writer_id)?;
458 }
459 Request::Write {
460 entity_id,
461 field_type,
462 value,
463 write_time,
464 writer_id,
465 push_condition,
466 adjust_behavior,
467 } => {
468 let indir = resolve_indirection(ctx, self, entity_id, field_type)?;
469 self.write(
470 ctx,
471 &indir.0,
472 &indir.1,
473 value,
474 write_time,
475 writer_id,
476 push_condition,
477 adjust_behavior,
478 )?;
479 }
480 }
481 }
482 Ok(())
483 }
484
485 fn read(
486 &self,
487 _: &Context,
488 entity_id: &EntityId,
489 field_type: &FieldType,
490 value: &mut Option<Value>,
491 write_time: &mut Option<Timestamp>,
492 writer_id: &mut Option<EntityId>,
493 ) -> Result<()> {
494 let field = self
495 .fields
496 .get(&entity_id)
497 .and_then(|fields| fields.get(field_type));
498
499 if let Some(field) = field {
500 *value = Some(field.value.clone());
501 *write_time = Some(field.write_time.clone());
502 *writer_id = field.writer_id.clone();
503 } else {
504 return Err(FieldNotFound(entity_id.clone(), field_type.clone()).into());
505 }
506
507 Ok(())
508 }
509
510 fn write(
511 &mut self,
512 ctx: &Context,
513 entity_id: &EntityId,
514 field_type: &FieldType,
515 value: &Option<Value>,
516 write_time: &Option<Timestamp>,
517 writer_id: &Option<EntityId>,
518 write_option: &PushCondition,
519 adjust_behavior: &AdjustBehavior,
520 ) -> Result<()> {
521 let entity_schema = self.get_complete_entity_schema(ctx, entity_id.get_type())?;
522 let field_schema = entity_schema.fields.get(field_type)
523 .ok_or_else(|| FieldNotFound(entity_id.clone(), field_type.clone()))?;
524
525 let fields = self
526 .fields
527 .entry(entity_id.clone())
528 .or_insert_with(HashMap::new);
529
530 let field = fields.entry(field_type.clone()).or_insert_with(|| Field {
531 field_type: field_type.clone(),
532 value: field_schema.default_value.clone(),
533 write_time: now(),
534 writer_id: None,
535 });
536
537 let mut new_value = field_schema.default_value.clone();
538 if let Some(value) = value {
541 if discriminant(value) != discriminant(&field_schema.default_value) {
542 return Err(ValueTypeMismatch(
543 entity_id.clone(),
544 field_type.clone(),
545 field_schema.default_value.clone(),
546 value.clone(),
547 )
548 .into());
549 }
550
551 new_value = value.clone();
552 }
553
554 let old_value = &field.value;
555 match adjust_behavior {
556 AdjustBehavior::Add => match old_value {
557 Value::Int(old_int) => {
558 new_value = Value::Int(old_int + new_value.as_int().unwrap_or(0));
559 }
560 Value::Float(old_float) => {
561 new_value = Value::Float(old_float + new_value.as_float().unwrap_or(0.0));
562 }
563 Value::EntityList(old_list) => {
564 new_value = Value::EntityList(
565 old_list
566 .iter()
567 .chain(new_value.as_entity_list().unwrap_or(&Vec::new()).iter())
568 .cloned()
569 .collect(),
570 );
571 }
572 Value::String(old_string) => {
573 new_value = Value::String(format!(
574 "{}{}",
575 old_string,
576 new_value.as_string().cloned().unwrap_or_default()
577 ));
578 }
579 Value::BinaryFile(old_file) => {
580 new_value = Value::BinaryFile(
581 old_file
582 .iter()
583 .chain(
584 new_value
585 .as_binary_file()
586 .map_or(&Vec::new(), |f| &f)
587 .iter(),
588 )
589 .cloned()
590 .collect(),
591 );
592 }
593 _ => {
594 return Err(UnsupportAdjustBehavior(
595 entity_id.clone(),
596 field_type.clone(),
597 adjust_behavior.clone(),
598 )
599 .into());
600 }
601 },
602 AdjustBehavior::Subtract => match old_value {
603 Value::Int(old_int) => {
604 new_value = Value::Int(old_int - new_value.as_int().unwrap_or(0));
605 }
606 Value::Float(old_float) => {
607 new_value = Value::Float(old_float - new_value.as_float().unwrap_or(0.0));
608 }
609 Value::EntityList(old_list) => {
610 let new_list = new_value.as_entity_list().cloned().unwrap_or_default();
611 new_value = Value::EntityList(
612 old_list
613 .into_iter()
614 .filter(|item| !new_list.contains(item))
615 .cloned()
616 .collect(),
617 );
618 }
619 _ => {
620 return Err(UnsupportAdjustBehavior(
621 entity_id.clone(),
622 field_type.clone(),
623 adjust_behavior.clone(),
624 )
625 .into());
626 }
627 },
628 _ => {
629 }
631 }
632
633 match write_option {
634 PushCondition::Always => {
635 field.value = new_value;
636
637 if let Some(write_time) = write_time {
638 field.write_time = *write_time;
639 } else {
640 field.write_time = now();
641 }
642 if let Some(writer_id) = writer_id {
643 field.writer_id = Some(writer_id.clone());
644 } else {
645 field.writer_id = None;
646 }
647 }
648 PushCondition::Changes => {
649 if field.value != new_value {
651 field.value = new_value;
652 if let Some(write_time) = write_time {
653 field.write_time = *write_time;
654 } else {
655 field.write_time = now();
656 }
657 if let Some(writer_id) = writer_id {
658 field.writer_id = Some(writer_id.clone());
659 } else {
660 field.writer_id = None;
661 }
662 }
663 }
664 }
665
666 Ok(())
667 }
668
669 pub fn delete_entity(&mut self, ctx: &Context, entity_id: &EntityId) -> Result<()> {
672 {
674 if !self.fields.contains_key(entity_id) {
675 return Err(EntityNotFound(entity_id.clone()).into());
676 }
677 }
678
679 {
681 let mut reqs = vec![sread!(entity_id.clone(), "Children".into())];
682 self.perform(ctx, &mut reqs)?;
683 if let Request::Read { value, .. } = &reqs[0] {
684 if let Some(Value::EntityList(children)) = value {
685 for child in children {
686 self.delete_entity(ctx, child)?;
687 }
688 } else {
689 return Err(BadIndirection::new(
690 entity_id.clone(),
691 "Children".into(),
692 BadIndirectionReason::UnexpectedValueType(
693 "Children".into(),
694 format!("{:?}", value),
695 ),
696 )
697 .into());
698 }
699 }
700 }
701
702 {
704 self.perform(
705 ctx,
706 &mut vec![ssub!(
707 entity_id.clone(),
708 "Parent->Children".into(),
709 sreflist![entity_id.clone()]
710 )],
711 )?;
712 }
713
714 {
716 self.fields.remove(entity_id);
717 }
718
719 {
721 if let Some(entities) = self.entities.get_mut(entity_id.get_type()) {
722 entities.retain(|id| id != entity_id);
723 }
724 }
725
726 Ok(())
727 }
728
729 pub fn find_entities(
731 &self,
732 _: &Context,
733 entity_type: &EntityType,
734 page_opts: Option<PageOpts>,
735 ) -> Result<PageResult<EntityId>> {
736 let opts = page_opts.unwrap_or_default();
737
738 if !self.entities.contains_key(entity_type) {
740 return Ok(PageResult {
741 items: Vec::new(),
742 total: 0,
743 next_cursor: None,
744 });
745 }
746
747 let all_entities = self.entities.get(entity_type).unwrap();
748 let total = all_entities.len();
749
750 let start_idx = if let Some(cursor) = &opts.cursor {
752 match cursor.parse::<usize>() {
753 Ok(idx) => idx,
754 Err(_) => 0,
755 }
756 } else {
757 0
758 };
759
760 let end_idx = std::cmp::min(start_idx + opts.limit, total);
762 let items: Vec<EntityId> = if start_idx < total {
763 all_entities[start_idx..end_idx].to_vec()
764 } else {
765 Vec::new()
766 };
767
768 let next_cursor = if end_idx < total {
770 Some(end_idx.to_string())
771 } else {
772 None
773 };
774
775 Ok(PageResult {
776 items,
777 total,
778 next_cursor,
779 })
780 }
781
782 pub fn get_entity_types(
784 &self,
785 _: &Context,
786 page_opts: Option<PageOpts>,
787 ) -> Result<PageResult<EntityType>> {
788 let opts = page_opts.unwrap_or_default();
789
790 let all_types: Vec<EntityType> = self.schemas.keys().cloned().collect();
792 let total = all_types.len();
793
794 let start_idx = if let Some(cursor) = &opts.cursor {
796 match cursor.parse::<usize>() {
797 Ok(idx) => idx,
798 Err(_) => 0,
799 }
800 } else {
801 0
802 };
803
804 let end_idx = std::cmp::min(start_idx + opts.limit, total);
806 let items: Vec<EntityType> = if start_idx < total {
807 all_types[start_idx..end_idx].to_vec()
808 } else {
809 Vec::new()
810 };
811
812 let next_cursor = if end_idx < total {
814 Some(end_idx.to_string())
815 } else {
816 None
817 };
818
819 Ok(PageResult {
820 items,
821 total,
822 next_cursor,
823 })
824 }
825
826 pub fn take_snapshot(&self, _: &Context) -> Snapshot {
828 Snapshot {
829 schemas: self.schemas.clone(),
830 entities: self.entities.clone(),
831 types: self.types.clone(),
832 fields: self.fields.clone(),
833 }
834 }
835
836 pub fn restore_snapshot(&mut self, _: &Context, snapshot: Snapshot) {
838 self.schemas = snapshot.schemas;
839 self.entities = snapshot.entities;
840 self.types = snapshot.types;
841 self.fields = snapshot.fields;
842 }
843}
844
845pub fn resolve_indirection(
846 ctx: &Context,
847 store: &mut Store,
848 entity_id: &EntityId,
849 field_type: &FieldType,
850) -> Result<(EntityId, FieldType)> {
851 let fields = field_type.indirect_fields();
852
853 if fields.len() == 1 {
854 return Ok((entity_id.clone(), field_type.clone()));
855 }
856
857 let mut current_entity_id = entity_id.clone();
858
859 for i in 0..fields.len() - 1 {
860 let field = &fields[i];
861
862 if i > 0 && field.0.parse::<i64>().is_ok() {
864 let index = field.0.parse::<i64>().unwrap();
865 if index < 0 {
866 return Err(BadIndirection::new(
867 current_entity_id.clone(),
868 field_type.clone(),
869 BadIndirectionReason::NegativeIndex(index),
870 )
871 .into());
872 }
873
874 let prev_field = &fields[i - 1];
876
877 let mut reqs = vec![sread!(current_entity_id.clone(), prev_field.clone())];
878 store.perform(ctx, &mut reqs)?;
879
880 if let Request::Read { value, .. } = &reqs[0] {
881 if let Some(Value::EntityList(entities)) = value {
882 let index_usize = index as usize;
883 if index_usize >= entities.len() {
884 return Err(BadIndirection::new(
885 current_entity_id.clone(),
886 field_type.clone(),
887 BadIndirectionReason::ArrayIndexOutOfBounds(
888 index_usize,
889 entities.len(),
890 ),
891 )
892 .into());
893 }
894
895 current_entity_id = entities[index_usize].clone();
896 } else {
897 return Err(BadIndirection::new(
898 current_entity_id.clone(),
899 field_type.clone(),
900 BadIndirectionReason::UnexpectedValueType(
901 prev_field.clone(),
902 format!("{:?}", value),
903 ),
904 )
905 .into());
906 }
907 }
908
909 continue;
910 }
911
912 let mut reqs = vec![sread!(current_entity_id.clone(), field.clone())];
914
915 if let Err(e) = store.perform(ctx, &mut reqs) {
916 return Err(BadIndirection::new(
917 current_entity_id.clone(),
918 field_type.clone(),
919 BadIndirectionReason::FailedToResolveField(field.clone(), e.to_string()),
920 )
921 .into());
922 }
923
924 if let Request::Read { value, .. } = &reqs[0] {
925 if let Some(Value::EntityReference(reference)) = value {
926 match reference {
927 Some(ref_id) => {
928 if !store.entity_exists(ctx, ref_id) {
930 return Err(BadIndirection::new(
931 current_entity_id.clone(),
932 field_type.clone(),
933 BadIndirectionReason::InvalidEntityId(ref_id.clone()),
934 )
935 .into());
936 }
937 current_entity_id = ref_id.clone();
938 }
939 None => {
940 return Err(BadIndirection::new(
942 current_entity_id.clone(),
943 field_type.clone(),
944 BadIndirectionReason::EmptyEntityReference,
945 )
946 .into());
947 }
948 }
949
950 continue;
951 }
952
953 if let Some(Value::EntityList(_)) = value {
954 if i + 1 >= fields.len() - 1 || fields[i + 1].0.parse::<i64>().is_err() {
956 return Err(BadIndirection::new(
957 current_entity_id.clone(),
958 field_type.clone(),
959 BadIndirectionReason::ExpectedIndexAfterEntityList(fields[i + 1].clone()),
960 )
961 .into());
962 }
963 continue;
965 }
966
967 return Err(BadIndirection::new(
968 current_entity_id.clone(),
969 field_type.clone(),
970 BadIndirectionReason::UnexpectedValueType(field.clone(), format!("{:?}", value)),
971 )
972 .into());
973 }
974 }
975
976 Ok((current_entity_id, fields.last().unwrap().clone()))
977}