Skip to content

Commit b5d7745

Browse files
committed
perf: skip null check for parent and root fields
The null checks prevent arangodb from applying the reduce-extraction-to-projection optimization.
1 parent 4a6419d commit b5d7745

File tree

10 files changed

+87
-84
lines changed

10 files changed

+87
-84
lines changed

spec/regression/root-fields/tests/root-and-parent-with-collect/aql/q.aql

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,19 @@ RETURN {
1616
IN v_root1.`children`[*].`children`[*][**]
1717
RETURN {
1818
"parent": { __cruddl_runtime_error_code: @var1, __cruddl_runtime_error: @var2 },
19-
"root": (IS_NULL(v_root1) ? null : {
19+
"root": {
2020
"name": v_root1.`name`
21-
})
21+
}
2222
}
2323
),
2424
"extensionGrandchildren": (
2525
FOR v_extensionGrandchild1
2626
IN v_root1.`children`[*].`extension`.`children`[*][**]
2727
RETURN {
2828
"parent": { __cruddl_runtime_error_code: @var3, __cruddl_runtime_error: @var4 },
29-
"root": (IS_NULL(v_root1) ? null : {
29+
"root": {
3030
"name": v_root1.`name`
31-
})
31+
}
3232
}
3333
)
3434
}
@@ -44,13 +44,12 @@ RETURN {
4444
)
4545
)[**]
4646
SORT (v_grandchild2.`obj`.`name`)
47-
LET v_root2 = v_grandchild2.`root`
4847
RETURN {
4948
"name": v_grandchild2.`obj`.`name`,
5049
"parent": { __cruddl_runtime_error_code: @var7, __cruddl_runtime_error: @var8 },
51-
"root": (IS_NULL(v_root2) ? null : {
52-
"name": v_root2.`name`
53-
})
50+
"root": {
51+
"name": v_grandchild2.`root`.`name`
52+
}
5453
}
5554
),
5655
"rootExtensionGrandchildren": (
@@ -64,13 +63,12 @@ RETURN {
6463
)
6564
)[**]
6665
SORT (v_extensionGrandchild2.`obj`.`name`)
67-
LET v_root3 = v_extensionGrandchild2.`root`
6866
RETURN {
6967
"name": v_extensionGrandchild2.`obj`.`name`,
7068
"parent": { __cruddl_runtime_error_code: @var11, __cruddl_runtime_error: @var12 },
71-
"root": (IS_NULL(v_root3) ? null : {
72-
"name": v_root3.`name`
73-
})
69+
"root": {
70+
"name": v_extensionGrandchild2.`root`.`name`
71+
}
7472
}
7573
)
7674
}

spec/regression/root-fields/tests/root-and-parent-with-intra-root-entity-collect/aql/test.aql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ RETURN {
1111
RETURN {
1212
"name": v_grandchild1.`name`,
1313
"parent": { __cruddl_runtime_error_code: @var1, __cruddl_runtime_error: @var2 },
14-
"root": (IS_NULL(v_root1) ? null : {
14+
"root": {
1515
"name": v_root1.`name`
16-
})
16+
}
1717
}
1818
),
1919
"extensionGrandchildren": (
@@ -22,9 +22,9 @@ RETURN {
2222
RETURN {
2323
"name": v_extensionGrandchild1.`name`,
2424
"parent": { __cruddl_runtime_error_code: @var3, __cruddl_runtime_error: @var4 },
25-
"root": (IS_NULL(v_root1) ? null : {
25+
"root": {
2626
"name": v_root1.`name`
27-
})
27+
}
2828
}
2929
)
3030
}

spec/regression/root-fields/tests/root-and-parent/aql/test.aql

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,36 +15,36 @@ RETURN {
1515
IN (IS_LIST(v_child1.`children`) ? v_child1.`children` : [])
1616
RETURN {
1717
"name": v_grandchild1.`name`,
18-
"parent": (IS_NULL(v_child1) ? null : {
18+
"parent": {
1919
"name": v_child1.`name`,
20-
"parent": (IS_NULL(v_root1) ? null : {
20+
"parent": {
2121
"name": v_root1.`name`
22-
}),
22+
},
2323
"children": (
2424
FOR v_grandchild2
2525
IN (IS_LIST(v_child1.`children`) ? v_child1.`children` : [])
2626
RETURN {
2727
"name": v_grandchild2.`name`,
28-
"parent": (IS_NULL(v_child1) ? null : {
28+
"parent": {
2929
"name": v_child1.`name`,
30-
"parent": (IS_NULL(v_root1) ? null : {
30+
"parent": {
3131
"name": v_root1.`name`
32-
})
33-
})
32+
}
33+
}
3434
}
3535
)
36-
}),
37-
"root": (IS_NULL(v_root1) ? null : {
36+
},
37+
"root": {
3838
"name": v_root1.`name`
39-
})
39+
}
4040
}
4141
),
42-
"parent": (IS_NULL(v_root1) ? null : {
42+
"parent": {
4343
"name": v_root1.`name`
44-
}),
45-
"root": (IS_NULL(v_root1) ? null : {
44+
},
45+
"root": {
4646
"name": v_root1.`name`
47-
})
47+
}
4848
}
4949
)
5050
}

spec/regression/root-fields/tests/root-with-collect/aql/filter.aql

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ RETURN {
1717
FILTER (RIGHT(v_grandchild1.`name`, LENGTH(@var1)) == @var2)
1818
RETURN {
1919
"name": v_grandchild1.`name`,
20-
"root": (IS_NULL(v_root1) ? null : {
20+
"root": {
2121
"name": v_root1.`name`
22-
})
22+
}
2323
}
2424
),
2525
@var3: {
@@ -40,9 +40,9 @@ RETURN {
4040
IN v_root1.`children`[*].`extension`.`children`[*][**]
4141
FILTER (RIGHT(v_extensionGrandchild1.`name`, LENGTH(@var6)) == @var7)
4242
RETURN {
43-
"root": (IS_NULL(v_root1) ? null : {
43+
"root": {
4444
"name": v_root1.`name`
45-
})
45+
}
4646
}
4747
),
4848
@var8: {
@@ -72,12 +72,11 @@ RETURN {
7272
)[**]
7373
FILTER (RIGHT(v_grandchild3.`obj`.`name`, LENGTH(@var13)) == @var14)
7474
SORT (v_grandchild3.`obj`.`name`)
75-
LET v_root2 = v_grandchild3.`root`
7675
RETURN {
7776
"name": v_grandchild3.`obj`.`name`,
78-
"root": (IS_NULL(v_root2) ? null : {
79-
"name": v_root2.`name`
80-
})
77+
"root": {
78+
"name": v_grandchild3.`root`.`name`
79+
}
8180
}
8281
),
8382
@var15: {
@@ -109,12 +108,11 @@ RETURN {
109108
)[**]
110109
FILTER (RIGHT(v_extensionGrandchild3.`obj`.`name`, LENGTH(@var22)) == @var23)
111110
SORT (v_extensionGrandchild3.`obj`.`name`)
112-
LET v_root3 = v_extensionGrandchild3.`root`
113111
RETURN {
114112
"name": v_extensionGrandchild3.`obj`.`name`,
115-
"root": (IS_NULL(v_root3) ? null : {
116-
"name": v_root3.`name`
117-
})
113+
"root": {
114+
"name": v_extensionGrandchild3.`root`.`name`
115+
}
118116
}
119117
),
120118
@var24: {

spec/regression/root-fields/tests/root-with-collect/aql/order.aql

Lines changed: 20 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ RETURN {
1717
SORT (v_grandchild1.`name`)
1818
RETURN {
1919
"name": v_grandchild1.`name`,
20-
"root": (IS_NULL(v_root1) ? null : {
20+
"root": {
2121
"name": v_root1.`name`
22-
})
22+
}
2323
}
2424
),
2525
"grandchildrenReverse": (
@@ -28,9 +28,9 @@ RETURN {
2828
SORT (v_grandchild2.`name`) DESC
2929
RETURN {
3030
"name": v_grandchild2.`name`,
31-
"root": (IS_NULL(v_root1) ? null : {
31+
"root": {
3232
"name": v_root1.`name`
33-
})
33+
}
3434
}
3535
),
3636
"extensionGrandchildren": (
@@ -39,9 +39,9 @@ RETURN {
3939
SORT (v_extensionGrandchild1.`name`)
4040
RETURN {
4141
"name": v_extensionGrandchild1.`name`,
42-
"root": (IS_NULL(v_root1) ? null : {
42+
"root": {
4343
"name": v_root1.`name`
44-
})
44+
}
4545
}
4646
),
4747
"extensionGrandchildrenReverse": (
@@ -50,9 +50,9 @@ RETURN {
5050
SORT (v_extensionGrandchild2.`name`) DESC
5151
RETURN {
5252
"name": v_extensionGrandchild2.`name`,
53-
"root": (IS_NULL(v_root1) ? null : {
53+
"root": {
5454
"name": v_root1.`name`
55-
})
55+
}
5656
}
5757
)
5858
}
@@ -68,12 +68,11 @@ RETURN {
6868
)
6969
)[**]
7070
SORT (v_grandchild3.`obj`.`name`)
71-
LET v_root2 = v_grandchild3.`root`
7271
RETURN {
7372
"name": v_grandchild3.`obj`.`name`,
74-
"root": (IS_NULL(v_root2) ? null : {
75-
"name": v_root2.`name`
76-
})
73+
"root": {
74+
"name": v_grandchild3.`root`.`name`
75+
}
7776
}
7877
),
7978
"rootGrandchildrenReverse": (
@@ -87,12 +86,11 @@ RETURN {
8786
)
8887
)[**]
8988
SORT (v_grandchild4.`obj`.`name`) DESC
90-
LET v_root3 = v_grandchild4.`root`
9189
RETURN {
9290
"name": v_grandchild4.`obj`.`name`,
93-
"root": (IS_NULL(v_root3) ? null : {
94-
"name": v_root3.`name`
95-
})
91+
"root": {
92+
"name": v_grandchild4.`root`.`name`
93+
}
9694
}
9795
),
9896
"rootExtensionGrandchildren": (
@@ -106,12 +104,11 @@ RETURN {
106104
)
107105
)[**]
108106
SORT (v_extensionGrandchild3.`obj`.`name`)
109-
LET v_root4 = v_extensionGrandchild3.`root`
110107
RETURN {
111108
"name": v_extensionGrandchild3.`obj`.`name`,
112-
"root": (IS_NULL(v_root4) ? null : {
113-
"name": v_root4.`name`
114-
})
109+
"root": {
110+
"name": v_extensionGrandchild3.`root`.`name`
111+
}
115112
}
116113
),
117114
"rootExtensionGrandchildrenReverse": (
@@ -125,12 +122,11 @@ RETURN {
125122
)
126123
)[**]
127124
SORT (v_extensionGrandchild4.`obj`.`name`) DESC
128-
LET v_root5 = v_extensionGrandchild4.`root`
129125
RETURN {
130126
"name": v_extensionGrandchild4.`obj`.`name`,
131-
"root": (IS_NULL(v_root5) ? null : {
132-
"name": v_root5.`name`
133-
})
127+
"root": {
128+
"name": v_extensionGrandchild4.`root`.`name`
129+
}
134130
}
135131
)
136132
}

spec/regression/root-fields/tests/root-with-collect/aql/q.aql

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,18 @@ RETURN {
1515
FOR v_grandchild1
1616
IN v_root1.`children`[*].`children`[*][**]
1717
RETURN {
18-
"root": (IS_NULL(v_root1) ? null : {
18+
"root": {
1919
"name": v_root1.`name`
20-
})
20+
}
2121
}
2222
),
2323
"extensionGrandchildren": (
2424
FOR v_extensionGrandchild1
2525
IN v_root1.`children`[*].`extension`.`children`[*][**]
2626
RETURN {
27-
"root": (IS_NULL(v_root1) ? null : {
27+
"root": {
2828
"name": v_root1.`name`
29-
})
29+
}
3030
}
3131
)
3232
}
@@ -42,12 +42,11 @@ RETURN {
4242
)
4343
)[**]
4444
SORT (v_grandchild2.`obj`.`name`)
45-
LET v_root2 = v_grandchild2.`root`
4645
RETURN {
4746
"name": v_grandchild2.`obj`.`name`,
48-
"root": (IS_NULL(v_root2) ? null : {
49-
"name": v_root2.`name`
50-
})
47+
"root": {
48+
"name": v_grandchild2.`root`.`name`
49+
}
5150
}
5251
),
5352
"rootExtensionGrandchildren": (
@@ -61,12 +60,11 @@ RETURN {
6160
)
6261
)[**]
6362
SORT (v_extensionGrandchild2.`obj`.`name`)
64-
LET v_root3 = v_extensionGrandchild2.`root`
6563
RETURN {
6664
"name": v_extensionGrandchild2.`obj`.`name`,
67-
"root": (IS_NULL(v_root3) ? null : {
68-
"name": v_root3.`name`
69-
})
65+
"root": {
66+
"name": v_extensionGrandchild2.`root`.`name`
67+
}
7068
}
7169
)
7270
}

spec/regression/traversal-performance/tests/collect/aql/RelationAndFieldTraversalWithParent.aql

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,11 @@ RETURN {
1818
RETURN { obj: v_entity1, root: v_node1 }
1919
)
2020
)[**]
21-
LET v_root1 = v_child1.`root`
2221
RETURN {
2322
"key": v_child1.`obj`.`key`,
24-
"parent": (IS_NULL(v_root1) ? null : {
25-
"key": v_root1.`key`
26-
})
23+
"parent": {
24+
"key": v_child1.`root`.`key`
25+
}
2726
}
2827
)
2928
})

spec/regression/traversal-performance/tests/collect/result.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
"RelationAndFieldTraversalWithParent": {
2020
"errors": [
2121
{
22-
"message": "AQL: query would use more memory than allowed [node #17: TraversalNode] [node #18: CalculationNode] [node #19: FilterNode] [node #43: SubqueryStartNode] [node #22: FilterNode] [node #23: CalculationNode] [node #24: EnumerateListNode] [node #25: CalculationNode] [node #44: SubqueryEndNode] [node #42: SubqueryEndNode] [node #39: SubqueryStartNode] [node #13: FilterNode] [node #30: CalculationNode] [node #31: EnumerateListNode] [node #33: CalculationNode] [node #40: SubqueryEndNode] [node #36: CalculationNode] [node #37: ReturnNode] (while executing)",
22+
"message": "AQL: query would use more memory than allowed [node #17: TraversalNode] [node #18: CalculationNode] [node #19: FilterNode] [node #42: SubqueryStartNode] [node #22: FilterNode] [node #23: CalculationNode] [node #24: EnumerateListNode] [node #25: CalculationNode] [node #43: SubqueryEndNode] [node #41: SubqueryEndNode] [node #38: SubqueryStartNode] [node #13: FilterNode] [node #30: CalculationNode] [node #31: EnumerateListNode] [node #32: CalculationNode] [node #39: SubqueryEndNode] [node #35: CalculationNode] [node #36: ReturnNode] (while executing)",
2323
"locations": [
2424
{
2525
"line": 10,

src/schema-generation/output-type-generator.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,10 @@ export class OutputTypeGenerator {
227227
// a check that they return null if the source node is null.
228228
// if we skip both, entity extensions will be passed as null, but they will only ever be used to look up
229229
// fields in them, and a FieldQueryNode returns null if the source is null.
230-
skipNullCheck: field.type.isEntityExtensionType,
230+
// parent fields and root fields can never be null (either they exist, or querying them throws an error)
231+
// it's important to skip the null check because ArangoDB would otherwise no longer use the reduce-extraction-to-projection optimiztion
232+
skipNullCheck:
233+
field.type.isEntityExtensionType || field.isParentField || field.isRootField,
231234
isPure: true,
232235
resolve: (sourceNode, args, info) => this.resolveField(field, sourceNode, info),
233236
};

0 commit comments

Comments
 (0)