Skip to main content

teaql_runtime/repository/
graph.rs

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}