1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
use crate::{
query_ast::*,
query_graph::{Node, NodeRef, QueryGraph, QueryGraphDependency},
QueryGraphBuilderError, QueryGraphBuilderResult,
};
use query_structure::RelationFieldRef;
/// Only for many to many relations.
///
/// Creates a connect node in the graph and creates edges to `parent_node` and `child_node`.
/// By default, the connect node assumes that both the parent and the child node results
/// are convertible to IDs, as the edges perform a transformation on the connect node to
/// inject the required IDs after the parents executed.
///
/// The resulting graph (dashed indicates that those nodes and edges are not created in this function):
///
/// ```text
/// ┌ ─ ─ ─ ─ ─ ─ ─ ─ ┐
/// ┌── Parent ─ ─ ─ ─ ─
/// │ └ ─ ─ ─ ─ ─ ─ ─ ─ ┘ │
/// │ │
/// │ │
/// │ │
/// │ ▼ ▼
/// │ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ ─ ─ ─ ─ ─
/// │ Child Result │
/// │ └ ─ ─ ─ ─ ─ ─ ─ ─ ┘ └ ─ ─ ─ ─ ─ ─
/// │ │
/// │ │
/// │ │
/// │ ▼
/// │ ┌─────────────────┐
/// └─▶│ Connect │
/// └─────────────────┘
/// ```
pub(crate) fn connect_records_node(
graph: &mut QueryGraph,
parent_node: &NodeRef,
child_node: &NodeRef,
parent_relation_field: &RelationFieldRef,
expected_connects: usize,
) -> QueryGraphBuilderResult<NodeRef> {
assert!(parent_relation_field.relation().is_many_to_many());
let parent_model_id = parent_relation_field.model().primary_identifier();
let child_model_id = parent_relation_field.related_model().primary_identifier();
let connect = WriteQuery::ConnectRecords(ConnectRecords {
parent_id: None,
child_ids: vec![],
relation_field: parent_relation_field.clone(),
});
let connect_node = graph.create_node(Query::Write(connect));
// Edge from parent to connect.
graph.create_edge(
parent_node,
&connect_node,
QueryGraphDependency::ProjectedDataDependency(
parent_model_id,
Box::new(|mut connect_node, mut parent_ids| {
let len = parent_ids.len();
if len == 0 {
return Err(QueryGraphBuilderError::AssertionError(
"Required exactly one parent ID to be present for connect query, found 0.".to_string(),
));
}
if let Node::Query(Query::Write(WriteQuery::ConnectRecords(ref mut c))) = connect_node {
let parent_id = parent_ids.pop().unwrap();
c.parent_id = Some(parent_id);
}
Ok(connect_node)
}),
),
)?;
// Edge from child to connect.
graph.create_edge(
child_node,
&connect_node,
QueryGraphDependency::ProjectedDataDependency(
child_model_id,
Box::new(move |mut connect_node, child_ids| {
let len = child_ids.len();
if len != expected_connects {
return Err(QueryGraphBuilderError::RecordNotFound(format!(
"Expected {expected_connects} records to be connected, found only {len}.",
)));
}
if let Node::Query(Query::Write(WriteQuery::ConnectRecords(ref mut c))) = connect_node {
c.child_ids = child_ids;
}
Ok(connect_node)
}),
),
)?;
Ok(connect_node)
}