Skip to content

Commit 9a426d2

Browse files
committed
perf(query-compiler): return if condition rows directly
Signed-off-by: Alexey Orlenko's AI Agent <robot@aqrln.net>
1 parent fd3c93d commit 9a426d2

4 files changed

Lines changed: 38 additions & 45 deletions

File tree

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

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,13 @@ impl From<Flow> for Node {
6868

6969
pub enum Flow {
7070
/// Expresses a conditional control flow in the graph.
71-
/// Possible outgoing edges are `then` and `else`, each at most once, with `then` required to be present.
72-
If { rule: DataRule, data: Option<Placeholder> },
71+
/// Possible outgoing edges are `then` and `else`, each at most once.
72+
/// `then` is required unless `then_returns_condition` is set, in which case the condition input is also the then-branch result.
73+
If {
74+
rule: DataRule,
75+
data: Option<Placeholder>,
76+
then_returns_condition: bool,
77+
},
7378

7479
/// Returns a fixed set of results at runtime.
7580
Return(Option<Placeholder>),
@@ -80,13 +85,23 @@ impl Flow {
8085
Self::If {
8186
rule: DataRule::RowCountNeq(0),
8287
data: None,
88+
then_returns_condition: false,
89+
}
90+
}
91+
92+
pub fn if_non_empty_returning_condition() -> Self {
93+
Self::If {
94+
rule: DataRule::RowCountNeq(0),
95+
data: None,
96+
then_returns_condition: true,
8397
}
8498
}
8599

86100
pub fn if_false() -> Self {
87101
Self::If {
88102
rule: DataRule::Never,
89103
data: None,
104+
then_returns_condition: false,
90105
}
91106
}
92107
}

query-compiler/core/src/query_graph_builder/write/nested/connect_or_create_nested.rs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,7 @@ fn handle_many_to_many(
116116
));
117117

118118
let create_node = create::create_record_node(graph, query_schema, child_model.clone(), create_map)?;
119-
let if_node = graph.create_node(Flow::if_non_empty());
120-
let return_existing = graph.create_node(Flow::Return(None));
121-
let return_create = graph.create_node(Flow::Return(None));
119+
let if_node = graph.create_node(Flow::if_non_empty_returning_condition());
122120

123121
graph.create_edge(&parent_node, &read_node, QueryGraphDependency::ExecutionOrder)?;
124122
graph.create_edge(
@@ -131,26 +129,7 @@ fn handle_many_to_many(
131129
),
132130
)?;
133131

134-
graph.create_edge(&if_node, &return_existing, QueryGraphDependency::Then)?;
135132
graph.create_edge(&if_node, &create_node, QueryGraphDependency::Else)?;
136-
graph.create_edge(
137-
&read_node,
138-
&return_existing,
139-
QueryGraphDependency::ProjectedDataDependency(
140-
child_model_identifier.clone(),
141-
RowSink::ProjectedPlaceholder(&ReturnInput),
142-
None,
143-
),
144-
)?;
145-
graph.create_edge(
146-
&create_node,
147-
&return_create,
148-
QueryGraphDependency::ProjectedDataDependency(
149-
child_model_identifier,
150-
RowSink::ProjectedPlaceholder(&ReturnInput),
151-
None,
152-
),
153-
)?;
154133

155134
connect::connect_records_node(graph, &parent_node, &if_node, parent_relation_field, 1)?;
156135
}
@@ -411,9 +390,8 @@ fn one_to_many_inlined_parent(
411390
graph.mark_nodes(&parent_node, &read_node);
412391
graph.create_edge(&parent_node, &read_node, QueryGraphDependency::ExecutionOrder)?;
413392

414-
let if_node = graph.create_node(Flow::if_non_empty());
393+
let if_node = graph.create_node(Flow::if_non_empty_returning_condition());
415394
let create_node = create::create_record_node(graph, query_schema, child_model.clone(), create_map)?;
416-
let return_existing = graph.create_node(Flow::Return(None));
417395

418396
graph.create_edge(
419397
&read_node,
@@ -425,7 +403,6 @@ fn one_to_many_inlined_parent(
425403
),
426404
)?;
427405

428-
graph.create_edge(&if_node, &return_existing, QueryGraphDependency::Then)?;
429406
graph.create_edge(&if_node, &create_node, QueryGraphDependency::Else)?;
430407

431408
graph.create_edge(
@@ -438,16 +415,6 @@ fn one_to_many_inlined_parent(
438415
),
439416
)?;
440417

441-
graph.create_edge(
442-
&read_node,
443-
&return_existing,
444-
QueryGraphDependency::ProjectedDataDependency(
445-
child_link.clone(),
446-
RowSink::ProjectedPlaceholder(&ReturnInput),
447-
None,
448-
),
449-
)?;
450-
451418
Ok(())
452419
}
453420

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

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,8 +253,16 @@ impl<'a, 'b> NodeTranslator<'a, 'b> {
253253
}
254254
}
255255

256+
let then_returns_condition = match self.graph.node_content(&self.node) {
257+
Some(Node::Flow(Flow::If {
258+
then_returns_condition, ..
259+
})) => *then_returns_condition,
260+
_ => false,
261+
};
262+
256263
let then_expr = match then_node {
257-
Some(node) => self.process_child_with_dependencies(node)?,
264+
Some(node) => Some(self.process_child_with_dependencies(node)?),
265+
None if then_returns_condition => None,
258266
None => {
259267
return Err(TranslateError::GraphBuildError(
260268
QueryGraphBuilderError::QueryGraphError(QueryGraphError::InvariantViolation(
@@ -274,10 +282,13 @@ impl<'a, 'b> NodeTranslator<'a, 'b> {
274282
let node = self.graph.pluck_node(&self.node);
275283
let node = self.transform_node(node)?;
276284

277-
let Node::Flow(Flow::If { rule, data }) = node else {
285+
let Node::Flow(Flow::If { rule, data, .. }) = node else {
278286
panic!("current node must be Flow::If");
279287
};
280288
let placeholder = projected_placeholder(data, "If")?;
289+
let then_expr = then_expr.unwrap_or_else(|| Expression::Get {
290+
name: placeholder.name.clone(),
291+
});
281292

282293
let expr = Expression::If {
283294
value: Expression::Get { name: placeholder.name }.into(),

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,14 +43,14 @@ transaction
4343
"public"."Post"."id"»
4444
params [const(String("Quantum Topological Embeddings of Mycorrhizal Networks: A Fractal Analysis of Phyllotaxic Algorithms in Non-Euclidean Plant Informatic")),
4545
var(2$id as Int)])
46-
in let 5 = unique (query «SELECT "public"."Category"."id" FROM
46+
in let 4 = unique (query «SELECT "public"."Category"."id" FROM
4747
"public"."Category" WHERE
4848
("public"."Category"."id" = $1 AND 1=1)
4949
LIMIT $2 OFFSET $3»
5050
params [const(BigInt(10)), const(BigInt(1)),
5151
const(BigInt(0))])
52-
in let 7 = if (rowCountNeq 0 (get 5))
53-
then get 5
52+
in let 6 = if (rowCountNeq 0 (get 4))
53+
then get 4
5454
else unique (query «INSERT INTO "public"."Category"
5555
("id","name") VALUES ($1,$2) RETURNING
5656
"public"."Category"."id"»
@@ -60,15 +60,15 @@ transaction
6060
[ rowCountNeq 0
6161
] orRaise "MISSING_RELATED_RECORD");
6262
0$id = mapField id (get 0);
63-
7 = validate (get 7)
63+
6 = validate (get 6)
6464
[ rowCountEq 1
6565
] orRaise "INCOMPLETE_CONNECT_INPUT";
66-
7$id = mapField id (get 7)
66+
6$id = mapField id (get 6)
6767
in execute «INSERT INTO "public"."_CategoryToPost"
6868
("B","A") VALUES [($1),*],* ON CONFLICT DO
6969
NOTHING»
7070
params [product(var(0$id as Int[]),
71-
var(7$id as Int[]))];
71+
var(6$id as Int[]))];
7272
let 0 = unique (validate (get 0)
7373
[ rowCountNeq 0
7474
] orRaise "MISSING_RECORD");

0 commit comments

Comments
 (0)