1use std::collections::BTreeMap;
2
3use teaql_core::{
4 DeleteCommand, Entity, EntityDescriptor, Expr, InsertCommand, PropertyDescriptor, Record,
5 SelectQuery, UpdateCommand, Value,
6};
7use teaql_sql::SqlDialect;
8
9use crate::{
10 GraphMutationKind, GraphMutationPlan, GraphNode, GraphOperation, RepositoryError, RuntimeError,
11 sorted_update_fields,
12};
13
14use super::{GraphTransactionBoundary, QueryExecutor, ResolvedRepository, helpers::*};
15
16impl<'a, D, E> ResolvedRepository<'a, D, E>
17where
18 D: SqlDialect,
19 E: QueryExecutor,
20{
21 pub fn save_graph(&self, node: GraphNode) -> Result<GraphNode, RepositoryError<E::Error>> {
22 if node.entity != self.entity {
23 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
24 "resolved repository {} cannot save graph root {}",
25 self.entity, node.entity
26 ))));
27 }
28 let boundary = self
29 .repository
30 .executor
31 .begin_transaction()
32 .map_err(RepositoryError::Executor)?;
33 if matches!(boundary, GraphTransactionBoundary::Unsupported) {
34 return Err(RepositoryError::Runtime(RuntimeError::Graph(
35 "save_graph requires a transactional executor".to_owned(),
36 )));
37 }
38 let result = self
39 .plan_graph(node)
40 .and_then(|plan| self.execute_graph_plan(plan));
41 match result {
42 Ok(saved) => {
43 if matches!(boundary, GraphTransactionBoundary::Started) {
44 self.repository
45 .executor
46 .commit_transaction()
47 .map_err(RepositoryError::Executor)?;
48 }
49 Ok(saved)
50 }
51 Err(err) => {
52 if !matches!(boundary, GraphTransactionBoundary::Unsupported) {
53 self.repository
54 .executor
55 .rollback_transaction()
56 .map_err(RepositoryError::Executor)?;
57 }
58 Err(err)
59 }
60 }
61 }
62
63 pub fn save_entity_graph<T>(&self, entity: T) -> Result<GraphNode, RepositoryError<E::Error>>
64 where
65 T: Entity,
66 {
67 let node = self
68 .graph_node_from_entity(entity)
69 .map_err(RepositoryError::Runtime)?;
70 self.save_graph(node)
71 }
72
73 pub fn plan_graph(
74 &self,
75 node: GraphNode,
76 ) -> Result<GraphMutationPlan, RepositoryError<E::Error>> {
77 if node.entity != self.entity {
78 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
79 "resolved repository {} cannot plan graph root {}",
80 self.entity, node.entity
81 ))));
82 }
83 let mut node = node;
84 let mut plan = GraphMutationPlan::default();
85 self.collect_graph_plan(&mut node, &mut plan)?;
86 plan.planned_root = Some(node);
87 plan.rebuild_batches();
88 Ok(plan)
89 }
90
91 pub fn execute_graph_plan(
92 &self,
93 plan: GraphMutationPlan,
94 ) -> Result<GraphNode, RepositoryError<E::Error>> {
95 let Some(root) = plan.planned_root else {
96 return Err(RepositoryError::Runtime(RuntimeError::Graph(
97 "graph mutation plan has no planned root".to_owned(),
98 )));
99 };
100 self.upsert_graph_node(root)
101 }
102
103 pub fn graph_node_from_entity<T>(&self, entity: T) -> Result<GraphNode, RuntimeError>
104 where
105 T: Entity,
106 {
107 let descriptor = T::entity_descriptor();
108 if descriptor.name != self.entity {
109 return Err(RuntimeError::Graph(format!(
110 "resolved repository {} cannot extract graph root {}",
111 self.entity, descriptor.name
112 )));
113 }
114 self.graph_node_from_record(&descriptor.name, entity.into_record())
115 }
116
117 fn collect_graph_plan(
118 &self,
119 node: &mut GraphNode,
120 plan: &mut GraphMutationPlan,
121 ) -> Result<(), RepositoryError<E::Error>> {
122 match node.operation {
123 GraphOperation::Reference => {
124 plan.push(
125 node.entity.clone(),
126 GraphMutationKind::Reference,
127 node.values.clone(),
128 Vec::new(),
129 );
130 return Ok(());
131 }
132 GraphOperation::Remove => {
133 plan.push(
134 node.entity.clone(),
135 GraphMutationKind::Delete,
136 node.values.clone(),
137 Vec::new(),
138 );
139 return Ok(());
140 }
141 GraphOperation::Upsert => {}
142 }
143
144 let descriptor = self
145 .repository
146 .metadata
147 .context
148 .require_entity(&node.entity)
149 .map_err(RepositoryError::Runtime)?;
150 let id_property = descriptor.id_property().cloned();
151 let id = id_property.as_ref().and_then(|property| {
152 node.values
153 .get(&property.name)
154 .filter(|value| !matches!(value, Value::Null))
155 .cloned()
156 });
157 let is_update = match (id_property.as_ref(), id.as_ref()) {
158 (Some(id_property), Some(id)) => self
159 .fetch_graph_current_row(&node.entity, &id_property.name, id)?
160 .is_some(),
161 _ => false,
162 };
163 if !is_update {
164 if let Some(id_property) = id_property.as_ref() {
165 let needs_id = !node.values.contains_key(&id_property.name)
166 || matches!(node.values.get(&id_property.name), Some(Value::Null));
167 if needs_id {
168 let id = self
169 .repository
170 .metadata
171 .context
172 .next_id(&node.entity)
173 .map_err(RepositoryError::Runtime)?;
174 node.values.insert(id_property.name.clone(), Value::U64(id));
175 }
176 }
177 }
178 let update_fields = if is_update {
179 let mut excluded = Vec::new();
180 if let Some(id_property) = id_property.as_ref() {
181 excluded.push(id_property.name.clone());
182 }
183 if let Some(version_property) = descriptor.version_property() {
184 excluded.push(version_property.name.clone());
185 }
186 sorted_update_fields(&node.values, excluded)
187 } else {
188 Vec::new()
189 };
190 plan.push(
191 node.entity.clone(),
192 if is_update {
193 GraphMutationKind::Update
194 } else {
195 GraphMutationKind::Create
196 },
197 node.values.clone(),
198 update_fields,
199 );
200
201 for (name, children) in &mut node.relations {
202 let relation = descriptor.relation_by_name(name).ok_or_else(|| {
203 RepositoryError::Runtime(RuntimeError::MissingRelation {
204 entity: node.entity.clone(),
205 relation: name.clone(),
206 })
207 })?;
208 let child_repo = self.scoped_repository(relation.target_entity.clone());
209 for child in children {
210 ensure_relation_target(&node.entity, name, &relation.target_entity, child)?;
211 child_repo.collect_graph_plan(child, plan)?;
212 }
213 }
214 Ok(())
215 }
216
217 fn insert_graph_node(
218 &self,
219 mut node: GraphNode,
220 ) -> Result<GraphNode, RepositoryError<E::Error>> {
221 match node.operation {
222 GraphOperation::Upsert => {}
223 GraphOperation::Reference => return self.validate_reference_node(node),
224 GraphOperation::Remove => {
225 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
226 "create graph cannot remove node {}",
227 node.entity
228 ))));
229 }
230 }
231
232 let descriptor = self
233 .repository
234 .metadata
235 .context
236 .require_entity(&node.entity)
237 .map_err(RepositoryError::Runtime)?;
238
239 let mut one_relations = Vec::new();
240 let mut many_relations = Vec::new();
241 for (name, children) in std::mem::take(&mut node.relations) {
242 let relation = descriptor.relation_by_name(&name).ok_or_else(|| {
243 RepositoryError::Runtime(RuntimeError::MissingRelation {
244 entity: node.entity.clone(),
245 relation: name.clone(),
246 })
247 })?;
248 if relation.many {
249 many_relations.push((name, relation.clone(), children));
250 } else {
251 one_relations.push((name, relation.clone(), children));
252 }
253 }
254
255 for (name, relation, children) in one_relations {
256 if children.len() > 1 {
257 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
258 "relation {}.{} expects one child, got {}",
259 node.entity,
260 name,
261 children.len()
262 ))));
263 }
264 let mut saved_children = Vec::new();
265 for child in children {
266 ensure_relation_target(&node.entity, &name, &relation.target_entity, &child)?;
267 let child_repo = self.scoped_repository(child.entity.clone());
268 let saved_child = child_repo.insert_graph_node(child)?;
269 if relation.attach {
270 let foreign_value = saved_child
271 .values
272 .get(&relation.foreign_key)
273 .cloned()
274 .ok_or_else(|| {
275 RepositoryError::Runtime(RuntimeError::Graph(format!(
276 "saved child {} missing foreign key {} for relation {}.{}",
277 relation.target_entity, relation.foreign_key, node.entity, name
278 )))
279 })?;
280 node.values
281 .insert(relation.local_key.clone(), foreign_value);
282 }
283 saved_children.push(saved_child);
284 }
285 node.relations.insert(name, saved_children);
286 }
287
288 let command = self
289 .prepare_insert_command(&InsertCommand {
290 entity: node.entity.clone(),
291 values: node.values.clone(),
292 })
293 .map_err(RepositoryError::Runtime)?;
294 self.execute_prepared_insert(command.clone())?;
295 node.values = command.values;
296
297 for (name, relation, children) in many_relations {
298 let local_value = node
299 .values
300 .get(&relation.local_key)
301 .cloned()
302 .ok_or_else(|| {
303 RepositoryError::Runtime(RuntimeError::Graph(format!(
304 "parent {} missing local key {} for relation {}",
305 node.entity, relation.local_key, name
306 )))
307 })?;
308 let mut saved_children = Vec::new();
309 for mut child in children {
310 ensure_relation_target(&node.entity, &name, &relation.target_entity, &child)?;
311 if relation.attach {
312 child
313 .values
314 .insert(relation.foreign_key.clone(), local_value.clone());
315 }
316 let child_repo = self.scoped_repository(child.entity.clone());
317 saved_children.push(child_repo.insert_graph_node(child)?);
318 }
319 node.relations.insert(name, saved_children);
320 }
321
322 Ok(node)
323 }
324
325 fn upsert_graph_node(
326 &self,
327 mut node: GraphNode,
328 ) -> Result<GraphNode, RepositoryError<E::Error>> {
329 match node.operation {
330 GraphOperation::Upsert => {}
331 GraphOperation::Reference => return self.validate_reference_node(node),
332 GraphOperation::Remove => {
333 self.validate_remove_node(&node)?;
334 self.delete_graph_node(&node)?;
335 return Ok(node);
336 }
337 }
338
339 let descriptor = self
340 .repository
341 .metadata
342 .context
343 .require_entity(&node.entity)
344 .map_err(RepositoryError::Runtime)?;
345 let Some(id_property) = descriptor.id_property() else {
346 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
347 "entity {} has no id property for graph upsert",
348 node.entity
349 ))));
350 };
351 let Some(id) = node
352 .values
353 .get(&id_property.name)
354 .filter(|value| !matches!(value, Value::Null))
355 .cloned()
356 else {
357 return self.insert_graph_node(node);
358 };
359
360 if self
361 .fetch_graph_current_row(&node.entity, &id_property.name, &id)?
362 .is_none()
363 {
364 return self.insert_graph_node(node);
365 }
366
367 let mut one_relations = Vec::new();
368 let mut many_relations = Vec::new();
369 for (name, children) in std::mem::take(&mut node.relations) {
370 let relation = descriptor.relation_by_name(&name).ok_or_else(|| {
371 RepositoryError::Runtime(RuntimeError::MissingRelation {
372 entity: node.entity.clone(),
373 relation: name.clone(),
374 })
375 })?;
376 if relation.many {
377 many_relations.push((name, relation.clone(), children));
378 } else {
379 one_relations.push((name, relation.clone(), children));
380 }
381 }
382
383 for (name, relation, children) in one_relations {
384 if children.len() > 1 {
385 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
386 "relation {}.{} expects one child, got {}",
387 node.entity,
388 name,
389 children.len()
390 ))));
391 }
392 let mut saved_children = Vec::new();
393 for child in children {
394 ensure_relation_target(&node.entity, &name, &relation.target_entity, &child)?;
395 let child_repo = self.scoped_repository(child.entity.clone());
396 let saved_child = child_repo.upsert_graph_node(child)?;
397 if relation.attach {
398 let foreign_value = saved_child
399 .values
400 .get(&relation.foreign_key)
401 .cloned()
402 .ok_or_else(|| {
403 RepositoryError::Runtime(RuntimeError::Graph(format!(
404 "saved child {} missing foreign key {} for relation {}.{}",
405 relation.target_entity, relation.foreign_key, node.entity, name
406 )))
407 })?;
408 node.values
409 .insert(relation.local_key.clone(), foreign_value);
410 }
411 saved_children.push(saved_child);
412 }
413 node.relations.insert(name, saved_children);
414 }
415
416 let update = self.graph_update_command(&node, descriptor, id_property, &id);
417 if !update.values.is_empty() || update.expected_version.is_some() {
418 let prepared_update = self
419 .prepare_update_command(&update)
420 .map_err(RepositoryError::Runtime)?;
421 self.execute_prepared_update(prepared_update.clone())?;
422 for (field, value) in &prepared_update.values {
423 node.values.insert(field.clone(), value.clone());
424 }
425 if let Some(version_property) = descriptor.version_property() {
426 if let Some(expected_version) = prepared_update.expected_version {
427 node.values.insert(
428 version_property.name.clone(),
429 Value::I64(expected_version + 1),
430 );
431 }
432 }
433 }
434
435 for (name, relation, children) in many_relations {
436 let local_value = node
437 .values
438 .get(&relation.local_key)
439 .cloned()
440 .ok_or_else(|| {
441 RepositoryError::Runtime(RuntimeError::Graph(format!(
442 "parent {} missing local key {} for relation {}",
443 node.entity, relation.local_key, name
444 )))
445 })?;
446 let child_repo = self.scoped_repository(relation.target_entity.clone());
447 let existing_children = child_repo.fetch_graph_children(
448 &relation.target_entity,
449 &relation.foreign_key,
450 &local_value,
451 )?;
452 let child_descriptor = self
453 .repository
454 .metadata
455 .context
456 .require_entity(&relation.target_entity)
457 .map_err(RepositoryError::Runtime)?;
458 let child_id_property = child_descriptor.id_property().ok_or_else(|| {
459 RepositoryError::Runtime(RuntimeError::Graph(format!(
460 "entity {} has no id property for graph diff",
461 relation.target_entity
462 )))
463 })?;
464 let mut existing_by_id = BTreeMap::new();
465 for child in existing_children {
466 if let Some(id) = child.get(&child_id_property.name) {
467 existing_by_id.insert(graph_identity_key(id), child);
468 }
469 }
470
471 let mut seen = std::collections::BTreeSet::new();
472 let mut saved_children = Vec::new();
473 for mut child in children {
474 ensure_relation_target(&node.entity, &name, &relation.target_entity, &child)?;
475 if relation.attach && child.operation != GraphOperation::Reference {
476 child
477 .values
478 .insert(relation.foreign_key.clone(), local_value.clone());
479 }
480 if let Some(child_id) = child
481 .values
482 .get(&child_id_property.name)
483 .filter(|value| !matches!(value, Value::Null))
484 {
485 let key = graph_identity_key(child_id);
486 if !seen.insert(key.clone()) {
487 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
488 "duplicate child id {key} in relation {}.{}",
489 node.entity, name
490 ))));
491 }
492 }
493 saved_children.push(child_repo.upsert_graph_node(child)?);
494 }
495
496 if relation.delete_missing {
497 for (id_key, existing) in existing_by_id {
498 if seen.contains(&id_key) {
499 continue;
500 }
501 let Some(existing_id) = existing.get(&child_id_property.name).cloned() else {
502 continue;
503 };
504 let mut delete =
505 DeleteCommand::new(relation.target_entity.clone(), existing_id);
506 if let Some(version) = graph_record_version(&existing, child_descriptor) {
507 delete = delete.expected_version(version);
508 }
509 child_repo.delete(&delete)?;
510 }
511 }
512
513 node.relations.insert(name, saved_children);
514 }
515
516 Ok(node)
517 }
518
519 fn validate_reference_node(
520 &self,
521 node: GraphNode,
522 ) -> Result<GraphNode, RepositoryError<E::Error>> {
523 if !node.relations.is_empty() {
524 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
525 "reference node {} cannot contain child relations",
526 node.entity
527 ))));
528 }
529 let descriptor = self
530 .repository
531 .metadata
532 .context
533 .require_entity(&node.entity)
534 .map_err(RepositoryError::Runtime)?;
535 let id_property = descriptor.id_property().ok_or_else(|| {
536 RepositoryError::Runtime(RuntimeError::Graph(format!(
537 "entity {} has no id property for graph reference",
538 node.entity
539 )))
540 })?;
541 let id = node
542 .values
543 .get(&id_property.name)
544 .filter(|value| !matches!(value, Value::Null))
545 .cloned()
546 .ok_or_else(|| {
547 RepositoryError::Runtime(RuntimeError::Graph(format!(
548 "reference node {} missing id property {}",
549 node.entity, id_property.name
550 )))
551 })?;
552
553 for field in node.values.keys() {
554 if field == &id_property.name {
555 continue;
556 }
557 if descriptor
558 .version_property()
559 .map(|property| field == &property.name)
560 .unwrap_or(false)
561 {
562 continue;
563 }
564 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
565 "reference node {} cannot carry mutable field {}",
566 node.entity, field
567 ))));
568 }
569
570 let current = self
571 .fetch_graph_current_row(&node.entity, &id_property.name, &id)?
572 .ok_or_else(|| {
573 RepositoryError::Runtime(RuntimeError::Graph(format!(
574 "reference node {}({}) does not exist",
575 node.entity,
576 graph_identity_key(&id)
577 )))
578 })?;
579
580 if let Some(version_property) = descriptor.version_property() {
581 if let Some(Value::I64(existing_version)) = current.get(&version_property.name) {
582 if *existing_version < 0 {
583 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
584 "reference node {}({}) is deleted",
585 node.entity,
586 graph_identity_key(&id)
587 ))));
588 }
589 if let Some(Value::I64(expected_version)) = node.values.get(&version_property.name)
590 {
591 if expected_version != existing_version {
592 return Err(RepositoryError::Runtime(
593 RuntimeError::OptimisticLockConflict {
594 entity: node.entity,
595 id: graph_identity_key(&id),
596 },
597 ));
598 }
599 }
600 }
601 }
602
603 Ok(GraphNode {
604 entity: node.entity,
605 values: current,
606 relations: BTreeMap::new(),
607 operation: GraphOperation::Reference,
608 })
609 }
610
611 fn validate_remove_node(&self, node: &GraphNode) -> Result<(), RepositoryError<E::Error>> {
612 if !node.relations.is_empty() {
613 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
614 "remove node {} cannot contain child relations",
615 node.entity
616 ))));
617 }
618 let descriptor = self
619 .repository
620 .metadata
621 .context
622 .require_entity(&node.entity)
623 .map_err(RepositoryError::Runtime)?;
624 let id_property = descriptor.id_property().ok_or_else(|| {
625 RepositoryError::Runtime(RuntimeError::Graph(format!(
626 "entity {} has no id property for graph remove",
627 node.entity
628 )))
629 })?;
630 let id = node
631 .values
632 .get(&id_property.name)
633 .filter(|value| !matches!(value, Value::Null))
634 .cloned()
635 .ok_or_else(|| {
636 RepositoryError::Runtime(RuntimeError::Graph(format!(
637 "remove node {} missing id property {}",
638 node.entity, id_property.name
639 )))
640 })?;
641 let current = self
642 .fetch_graph_current_row(&node.entity, &id_property.name, &id)?
643 .ok_or_else(|| {
644 RepositoryError::Runtime(RuntimeError::Graph(format!(
645 "remove node {}({}) does not exist",
646 node.entity,
647 graph_identity_key(&id)
648 )))
649 })?;
650 if let Some(version_property) = descriptor.version_property() {
651 if let Some(Value::I64(existing_version)) = current.get(&version_property.name) {
652 if *existing_version < 0 {
653 return Err(RepositoryError::Runtime(RuntimeError::Graph(format!(
654 "remove node {}({}) is already deleted",
655 node.entity,
656 graph_identity_key(&id)
657 ))));
658 }
659 }
660 }
661 Ok(())
662 }
663
664 fn graph_node_from_record(
665 &self,
666 entity: &str,
667 record: Record,
668 ) -> Result<GraphNode, RuntimeError> {
669 let descriptor = self.repository.metadata.context.require_entity(entity)?;
670 let mut node = GraphNode::new(entity);
671
672 for (field, value) in record {
673 let Some(relation) = descriptor.relation_by_name(&field) else {
674 node.values.insert(field, value);
675 continue;
676 };
677
678 match value {
679 Value::Null => {
680 node.relations.entry(field).or_default();
681 }
682 Value::Object(record) => {
683 let child = self.graph_node_from_record(&relation.target_entity, record)?;
684 node.relations.entry(field).or_default().push(child);
685 }
686 Value::List(values) => {
687 let children = node.relations.entry(field.clone()).or_default();
688 for value in values {
689 let Value::Object(record) = value else {
690 return Err(RuntimeError::Graph(format!(
691 "relation {}.{} expects object children, got {:?}",
692 entity, field, value
693 )));
694 };
695 children
696 .push(self.graph_node_from_record(&relation.target_entity, record)?);
697 }
698 }
699 other => {
700 return Err(RuntimeError::Graph(format!(
701 "relation {}.{} expects object/list/null, got {:?}",
702 entity, field, other
703 )));
704 }
705 }
706 }
707
708 Ok(node)
709 }
710
711 fn graph_update_command(
712 &self,
713 node: &GraphNode,
714 descriptor: &EntityDescriptor,
715 id_property: &PropertyDescriptor,
716 id: &Value,
717 ) -> UpdateCommand {
718 let mut command = UpdateCommand::new(node.entity.clone(), id.clone());
719 if let Some(version_property) = descriptor.version_property() {
720 if let Some(Value::I64(version)) = node.values.get(&version_property.name) {
721 command = command.expected_version(*version);
722 }
723 }
724 for property in descriptor.properties.iter().filter(|property| {
725 !property.is_id && !property.is_version && node.values.contains_key(&property.name)
726 }) {
727 if property.name == id_property.name {
728 continue;
729 }
730 if let Some(value) = node.values.get(&property.name) {
731 command.values.insert(property.name.clone(), value.clone());
732 }
733 }
734 command
735 }
736
737 fn delete_graph_node(&self, node: &GraphNode) -> Result<u64, RepositoryError<E::Error>> {
738 let descriptor = self
739 .repository
740 .metadata
741 .context
742 .require_entity(&node.entity)
743 .map_err(RepositoryError::Runtime)?;
744 let id_property = descriptor.id_property().ok_or_else(|| {
745 RepositoryError::Runtime(RuntimeError::Graph(format!(
746 "entity {} has no id property for graph remove",
747 node.entity
748 )))
749 })?;
750 let id = node.values.get(&id_property.name).cloned().ok_or_else(|| {
751 RepositoryError::Runtime(RuntimeError::Graph(format!(
752 "remove node {} missing id property {}",
753 node.entity, id_property.name
754 )))
755 })?;
756 let mut delete = DeleteCommand::new(node.entity.clone(), id);
757 if let Some(version_property) = descriptor.version_property() {
758 if let Some(Value::I64(version)) = node.values.get(&version_property.name) {
759 delete = delete.expected_version(*version);
760 }
761 }
762 self.delete(&delete)
763 }
764
765 fn fetch_graph_current_row(
766 &self,
767 entity: &str,
768 id_property: &str,
769 id: &Value,
770 ) -> Result<Option<Record>, RepositoryError<E::Error>> {
771 let mut rows = self
772 .scoped_repository(entity.to_owned())
773 .fetch_all(&SelectQuery::new(entity).filter(Expr::eq(id_property, id.clone())))?;
774 Ok(rows.pop())
775 }
776
777 fn fetch_graph_children(
778 &self,
779 entity: &str,
780 foreign_key: &str,
781 parent_value: &Value,
782 ) -> Result<Vec<Record>, RepositoryError<E::Error>> {
783 self.scoped_repository(entity.to_owned()).fetch_all(
784 &SelectQuery::new(entity).filter(Expr::eq(foreign_key, parent_value.clone())),
785 )
786 }
787}