Skip to content

Commit 1ad4ad8

Browse files
authored
refactor: remove and replace old ProjectedDataDependency (#5604)
[ORM-1137](https://linear.app/prisma-company/issue/ORM-1160/get-rid-of-all-remaining-projecteddatadependency) Removes all remaining usages of the old `ProjectedDataDependency` and renames `ProjectedDataSinkDependency` to `ProjectedDataDependency`.
1 parent 10e768c commit 1ad4ad8

25 files changed

Lines changed: 282 additions & 419 deletions

query-compiler/query-compiler/src/translate.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -284,22 +284,17 @@ impl<'a, 'b> NodeTranslator<'a, 'b> {
284284
fn transform_node(&mut self, mut node: Node) -> TranslateResult<Node> {
285285
for edge in self.parent_edges {
286286
match self.graph.take_edge(edge) {
287-
Some(QueryGraphDependency::ProjectedDataDependency(selection, f, _)) => {
288-
let fields = self.process_edge_selections(edge, &node, selection);
289-
node = f(node, vec![SelectionResult::new(fields)])?;
290-
}
291-
292-
Some(QueryGraphDependency::ProjectedDataSinkDependency(selection, sink, _)) => {
287+
Some(QueryGraphDependency::ProjectedDataDependency(selection, sink, _)) => {
293288
let fields = self.process_edge_selections(edge, &node, selection);
294289

295290
match sink {
296291
RowSink::All(field) | RowSink::ExactlyOne(field) | RowSink::AtMostOne(field) => {
297292
*field.node_input_field(&mut node) = vec![SelectionResult::new(fields)];
298293
}
299294
RowSink::Single(field) => {
300-
*field.node_input_field(&mut node) = SelectionResult::new(fields);
295+
*field.node_input_field(&mut node) = Some(SelectionResult::new(fields));
301296
}
302-
RowSink::ExactlyOneFilter(field) => {
297+
RowSink::AllFilter(field) | RowSink::ExactlyOneFilter(field) => {
303298
*field.node_input_field(&mut node) = SelectionResult::new(fields).filter();
304299
}
305300
RowSink::ExactlyOneWriteArgs(selection, field) => {
@@ -435,17 +430,14 @@ impl<'a, 'b> NodeTranslator<'a, 'b> {
435430
.into_iter()
436431
.flat_map(|edge| {
437432
let edge_content = self.graph.edge_content(&edge);
438-
let Some(
439-
QueryGraphDependency::ProjectedDataDependency(selection, _, expectation)
440-
| QueryGraphDependency::ProjectedDataSinkDependency(selection, _, expectation),
441-
) = edge_content
433+
let Some(QueryGraphDependency::ProjectedDataDependency(selection, _, expectation)) = edge_content
442434
else {
443435
return Either::Left(std::iter::empty());
444436
};
445437

446438
let requires_unique = matches!(
447439
edge_content,
448-
Some(QueryGraphDependency::ProjectedDataSinkDependency(_, sink, _))
440+
Some(QueryGraphDependency::ProjectedDataDependency(_, sink, _))
449441
if sink.is_unique()
450442
);
451443

query-compiler/query-compiler/tests/snapshots/queries__queries@create-m2m.json.snap

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ transaction
3737
VALUES ($1) RETURNING
3838
"public"."Category"."id"»
3939
params [const(String("cooking"))])
40-
in let 1$id = mapField id (get 1);
40+
in let 1 = unique (validate (get 1)
41+
[ rowCountNeq 0
42+
] orRaise "MISSING_RELATED_RECORD");
43+
1$id = mapField id (get 1);
4144
2 = validate (get 2)
4245
[ rowCountEq 1
4346
] orRaise "INCOMPLETE_CONNECT_INPUT";

query-compiler/query-compiler/tests/snapshots/queries__queries@create-nested-connectOrCreate-mixed.json.snap

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,10 @@ transaction
5050
params [const(BigInt(10)), const(BigInt(1)),
5151
const(BigInt(0))])
5252
in if (rowCountNeq 0 (get 6))
53-
then let 0$id = mapField id (get 0);
53+
then let 0 = unique (validate (get 0)
54+
[ rowCountNeq 0
55+
] orRaise "MISSING_RELATED_RECORD");
56+
0$id = mapField id (get 0);
5457
6 = validate (get 6)
5558
[ rowCountEq 1
5659
] orRaise "INCOMPLETE_CONNECT_INPUT";
@@ -66,7 +69,10 @@ transaction
6669
"public"."Category"."id"»
6770
params [const(BigInt(10)),
6871
const(String("Mushrooms"))])
69-
in let 0$id = mapField id (get 0);
72+
in let 0 = unique (validate (get 0)
73+
[ rowCountNeq 0
74+
] orRaise "MISSING_RELATED_RECORD");
75+
0$id = mapField id (get 0);
7076
7 = validate (get 7)
7177
[ rowCountEq 1
7278
] orRaise "INCOMPLETE_CONNECT_INPUT";

query-compiler/query-compiler/tests/snapshots/queries__queries@create-nested-connectOrCreate-one2m.json.snap

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,10 @@ transaction
4444
params [const(BigInt(10)), const(BigInt(1)),
4545
const(BigInt(0))])
4646
in if (rowCountNeq 0 (get 2))
47-
then let 0$id = mapField id (get 0);
47+
then let 0 = unique (validate (get 0)
48+
[ rowCountNeq 0
49+
] orRaise "MISSING_RELATED_RECORD");
50+
0$id = mapField id (get 0);
4851
2 = validate (get 2)
4952
[ rowCountEq 1
5053
] orRaise "INCOMPLETE_CONNECT_INPUT";
@@ -57,7 +60,10 @@ transaction
5760
RETURNING "public"."Category"."id"»
5861
params [const(BigInt(10)),
5962
const(String("JavaScript"))])
60-
in let 0$id = mapField id (get 0);
63+
in let 0 = unique (validate (get 0)
64+
[ rowCountNeq 0
65+
] orRaise "MISSING_RELATED_RECORD");
66+
0$id = mapField id (get 0);
6167
3 = validate (get 3)
6268
[ rowCountEq 1
6369
] orRaise "INCOMPLETE_CONNECT_INPUT";

query-compiler/query-compiler/tests/snapshots/queries__queries@update-m2m-disconnect.json.snap

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,9 @@ transaction
2222
"public"."Category"."id" WHERE ("public"."Category"."id"
2323
= $1 AND 1=1 AND "t0"."B" IN [$2]) OFFSET $3»
2424
params [const(BigInt(1)), var(0$id as Int), const(BigInt(0))]
25-
in let 0 = validate (get 0)
25+
in let 0 = unique (validate (get 0)
2626
[ rowCountNeq 0
27-
] orRaise "MISSING_RELATED_RECORD";
27+
] orRaise "MISSING_RELATED_RECORD");
2828
0$id = mapField id (get 0);
2929
1$id = mapField id (get 1)
3030
in execute «DELETE FROM "public"."_CategoryToPost" WHERE

query-engine/core/src/interpreter/expressionista.rs

Lines changed: 7 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -366,16 +366,7 @@ impl Expressionista {
366366
}?;
367367

368368
let res = match dependency {
369-
QueryGraphDependency::ProjectedDataDependency(selection, f, expectation) => {
370-
expectation
371-
.map(|expect| expect.check(binding))
372-
.transpose()
373-
.map_err(Into::into)
374-
.and(binding.as_selection_results(&selection))
375-
.and_then(|parent_selections| Ok(f(node, parent_selections)?))
376-
}
377-
378-
QueryGraphDependency::ProjectedDataSinkDependency(
369+
QueryGraphDependency::ProjectedDataDependency(
379370
selection,
380371
consumer,
381372
expectation,
@@ -390,7 +381,7 @@ impl Expressionista {
390381
let row = parent_selections.pop().expect(
391382
"parent selection should be present after validation",
392383
);
393-
*field.node_input_field(&mut node) = row;
384+
*field.node_input_field(&mut node) = Some(row);
394385
}
395386
RowSink::All(field) => {
396387
*field.node_input_field(&mut node) = parent_selections
@@ -405,6 +396,10 @@ impl Expressionista {
405396
);
406397
*field.node_input_field(&mut node) = vec![row];
407398
}
399+
RowSink::AllFilter(filter) => {
400+
*filter.node_input_field(&mut node) =
401+
parent_selections.filter();
402+
}
408403
RowSink::ExactlyOneFilter(filter) => {
409404
let row = parent_selections.pop().expect(
410405
"parent selection should be present after validation",
@@ -466,8 +461,7 @@ impl Expressionista {
466461
.into_iter()
467462
.filter_map(|edge| match graph.pluck_edge(&edge) {
468463
x @ (QueryGraphDependency::DataDependency(_, _)
469-
| QueryGraphDependency::ProjectedDataDependency(_, _, _)
470-
| QueryGraphDependency::ProjectedDataSinkDependency(_, _, _)) => {
464+
| QueryGraphDependency::ProjectedDataDependency(_, _, _)) => {
471465
let parent_binding_name = graph.edge_source(&edge).id();
472466
Some((parent_binding_name, x))
473467
}

query-engine/core/src/query_graph/formatters.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -109,20 +109,10 @@ impl Display for QueryGraphDependency {
109109
match self {
110110
Self::ExecutionOrder => write!(f, "ExecutionOrder"),
111111
Self::DataDependency(_, _) => write!(f, "ParentResult"),
112-
Self::ProjectedDataDependency(selection, _, _) => {
112+
Self::ProjectedDataDependency(selection, sink, _) => {
113113
write!(
114114
f,
115-
"ProjectedDataDependency ({:?})",
116-
selection
117-
.selections()
118-
.map(|f| format!("{}.{}", f.container().name(), f.prisma_name()))
119-
.collect::<Vec<_>>()
120-
)
121-
}
122-
Self::ProjectedDataSinkDependency(selection, sink, _) => {
123-
write!(
124-
f,
125-
"ProjectedDataSinkDependency({sink:?}) {:?}",
115+
"ProjectedDataDependency({sink:?}) {:?}",
126116
selection
127117
.selections()
128118
.map(|f| format!("{}.{}", f.container().name(), f.prisma_name()))

query-engine/core/src/query_graph/mod.rs

Lines changed: 23 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ use serde::Serialize;
1111
use smallvec::{SmallVec, smallvec};
1212

1313
use crate::{
14-
FilteredQuery, ManyRecordsQuery, Query, QueryGraphBuilderError, QueryGraphBuilderResult, QueryOptions, ReadQuery,
15-
interpreter::ExpressionResult,
14+
ManyRecordsQuery, Query, QueryGraphBuilderError, QueryGraphBuilderResult, QueryOptions, ReadQuery,
15+
inputs::ManyRecordsQueryFilterInput, interpreter::ExpressionResult,
1616
};
1717
use guard::*;
1818
use itertools::Itertools;
@@ -21,7 +21,7 @@ use petgraph::{
2121
visit::{EdgeRef as PEdgeRef, NodeIndexable},
2222
*,
2323
};
24-
use query_structure::{FieldSelection, Filter, IntoFilter, QueryArguments, SelectionResult, WriteArgs};
24+
use query_structure::{FieldSelection, Filter, QueryArguments, SelectionResult, WriteArgs};
2525

2626
pub type QueryGraphResult<T> = std::result::Result<T, QueryGraphError>;
2727

@@ -135,9 +135,6 @@ impl EdgeRef {
135135
}
136136
}
137137

138-
pub(crate) type ProjectedDataDependencyFn =
139-
Box<dyn FnOnce(Node, Vec<SelectionResult>) -> QueryGraphBuilderResult<Node> + Send + Sync + 'static>;
140-
141138
/// Stored on the edges of the QueryGraph, a QueryGraphDependency contains information on how children are connected to their parents,
142139
/// expressing for example the need for additional information from the parent to be able to execute at runtime.
143140
pub enum QueryGraphDependency {
@@ -156,9 +153,7 @@ pub enum QueryGraphDependency {
156153
/// Important note: As opposed to `DataDependency`, this dependency guarantees that if the closure is called, the source result contains at least the requested selection.
157154
/// To achieve that, the query graph is post-processed in the `finalize` and reloads are injected at points where a selection is not fulfilled.
158155
/// See `insert_reloads` for more information.
159-
ProjectedDataDependency(FieldSelection, ProjectedDataDependencyFn, Option<DataExpectation>), // [Composites] todo rename
160-
161-
ProjectedDataSinkDependency(FieldSelection, RowSink, Option<DataExpectation>),
156+
ProjectedDataDependency(FieldSelection, RowSink, Option<DataExpectation>),
162157

163158
/// Only valid in the context of a `If` control flow node.
164159
Then,
@@ -170,14 +165,16 @@ pub enum QueryGraphDependency {
170165
#[derive(Debug)]
171166
pub enum RowSink {
172167
/// Store a single row to the node input field.
173-
Single(&'static dyn NodeInputField<SelectionResult>),
168+
Single(&'static dyn NodeInputField<Option<SelectionResult>>),
174169
/// Store all rows to the node input field.
175170
All(&'static dyn NodeInputField<Vec<SelectionResult>>),
176171
/// Store at most one row to the node input field.
177172
AtMostOne(&'static dyn NodeInputField<Vec<SelectionResult>>),
178173
/// Store an array of exactly one row to the node input field.
179174
ExactlyOne(&'static dyn NodeInputField<Vec<SelectionResult>>),
180-
/// Store exactly one filter to the node input field.
175+
/// Store a filter representing all rows to the node input field.
176+
AllFilter(&'static dyn NodeInputField<Filter>),
177+
/// Store a filter representing exactly one row to the node input field.
181178
ExactlyOneFilter(&'static dyn NodeInputField<Filter>),
182179
/// Inject write arguments based on selection retrieved from exactly one row.
183180
ExactlyOneWriteArgs(FieldSelection, &'static dyn NodeInputField<[WriteArgs]>),
@@ -841,12 +838,14 @@ impl QueryGraph {
841838
let out_edges = self.outgoing_edges(&return_node);
842839
let dependencies: Vec<FieldSelection> = out_edges
843840
.into_iter()
844-
.filter_map(|edge| match self.edge_content(&edge).unwrap() {
845-
QueryGraphDependency::ProjectedDataDependency(requested_selection, _, _)
846-
| QueryGraphDependency::ProjectedDataSinkDependency(requested_selection, _, _) => {
841+
.filter_map(|edge| {
842+
if let QueryGraphDependency::ProjectedDataDependency(requested_selection, _, _) =
843+
self.edge_content(&edge).unwrap()
844+
{
847845
Some(requested_selection.clone())
846+
} else {
847+
None
848848
}
849-
_ => None,
850849
})
851850
.collect();
852851
let dependencies = FieldSelection::union(dependencies);
@@ -857,10 +856,7 @@ impl QueryGraph {
857856
let incoming_dep_edge = in_edges.into_iter().find(|edge| {
858857
matches!(
859858
self.edge_content(edge),
860-
Some(
861-
QueryGraphDependency::ProjectedDataDependency(_, _, _)
862-
| QueryGraphDependency::ProjectedDataSinkDependency(_, _, _)
863-
)
859+
Some(QueryGraphDependency::ProjectedDataDependency(_, _, _))
864860
)
865861
});
866862

@@ -871,28 +867,13 @@ impl QueryGraph {
871867
.remove_edge(incoming_edge)
872868
.expect("Expected edges between marked nodes to be non-empty.");
873869

874-
match content {
875-
QueryGraphDependency::ProjectedDataDependency(existing, transformer, expectation) => {
876-
let merged_dependencies = dependencies.merge(existing);
877-
self.create_edge(
878-
&source,
879-
&target,
880-
QueryGraphDependency::ProjectedDataDependency(
881-
merged_dependencies,
882-
transformer,
883-
expectation,
884-
),
885-
)?;
886-
}
887-
QueryGraphDependency::ProjectedDataSinkDependency(existing, sink, expectation) => {
888-
let merged_dependencies = dependencies.merge(existing);
889-
self.create_edge(
890-
&source,
891-
&target,
892-
QueryGraphDependency::ProjectedDataSinkDependency(merged_dependencies, sink, expectation),
893-
)?;
894-
}
895-
_ => (),
870+
if let QueryGraphDependency::ProjectedDataDependency(existing, sink, expectation) = content {
871+
let merged_dependencies = dependencies.merge(existing);
872+
self.create_edge(
873+
&source,
874+
&target,
875+
QueryGraphDependency::ProjectedDataDependency(merged_dependencies, sink, expectation),
876+
)?;
896877
}
897878
}
898879
}
@@ -988,13 +969,7 @@ impl QueryGraph {
988969
&reload_node,
989970
QueryGraphDependency::ProjectedDataDependency(
990971
primary_model_id,
991-
Box::new(|mut reload_node, parent_result| {
992-
if let Node::Query(Query::Read(ReadQuery::ManyRecordsQuery(ref mut mr))) = reload_node {
993-
mr.set_filter(parent_result.filter());
994-
}
995-
996-
Ok(reload_node)
997-
}),
972+
RowSink::AllFilter(&ManyRecordsQueryFilterInput),
998973
None,
999974
),
1000975
)?;
@@ -1103,7 +1078,6 @@ impl QueryGraph {
11031078
.into_iter()
11041079
.filter_map(|edge| match self.edge_content(&edge).unwrap() {
11051080
QueryGraphDependency::ProjectedDataDependency(requested_selection, _, _)
1106-
| QueryGraphDependency::ProjectedDataSinkDependency(requested_selection, _, _)
11071081
if !q.satisfies(requested_selection) =>
11081082
{
11091083
Some(requested_selection.clone())

query-engine/core/src/query_graph_builder/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ pub enum DataOperation {
333333
Upsert,
334334
Delete,
335335
Disconnect,
336+
Connect,
336337
NestedCreate,
337338
NestedUpdate,
338339
NestedUpsert,
@@ -350,6 +351,7 @@ impl fmt::Display for DataOperation {
350351
Self::Upsert => "an upsert",
351352
Self::Delete => "a delete",
352353
Self::Disconnect => "a disconnect",
354+
Self::Connect => "a connect",
353355
Self::NestedCreate => "a nested create",
354356
Self::NestedUpdate => "a nested update",
355357
Self::NestedUpsert => "a nested upsert",

0 commit comments

Comments
 (0)