Skip to content

Commit 32fbd32

Browse files
committed
fix: fix AQL error when trying to update child entities when there currently were no child entities
When the dict-based child entity impelemntation was used, and an non-empty update... for child entity was given, and this child entity list for the updated root entity was currently empty, and AQL error was generated. The problem was that we used a range generator that should have generated an empty range, but the AQL ranges are never empty, they just are inverted if the end position is lower than the start position. This resulted in an invalid ZIP call, which yielded NULL.
1 parent 936c9a6 commit 32fbd32

7 files changed

+186
-1
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"childEntityUpdatesViaDictStrategyThreshold": 1,
3+
"authRoles": ["allusers"]
4+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
# in the .context.json, childEntityUpdatesViaDictStrategyThreshold is set to 1
2+
# so we will always use the dict strategy to update child entities
3+
4+
# this test makes sure that updating child entities works (even though it does nothing)
5+
# when the child entity list in the database is empty
6+
# this regression test exists because of two bugs we had in the initial dict-based implementation
7+
# - an AQL error when there were updates but the collection was empty
8+
# - updates that did not correspond to actual were persisted as new items (just without id etc.)
9+
10+
mutation clearItems {
11+
updateDelivery(
12+
input: { id: "@{ids/Delivery/1}", removeItems: ["id_init_0000", "id_init_0001"] }
13+
) {
14+
items {
15+
id
16+
itemNumber
17+
}
18+
}
19+
}
20+
21+
# to verify it is cleared in the db
22+
query afterClear {
23+
Delivery(id: "@{ids/Delivery/1}") {
24+
items {
25+
id
26+
itemNumber
27+
}
28+
}
29+
}
30+
31+
mutation updateMultiple {
32+
updateDelivery(
33+
input: {
34+
id: "@{ids/Delivery/1}"
35+
updateItems: [
36+
{ id: "id_test_0003", itemNumber: "updated03" }
37+
{ id: "id_test_0005", itemNumber: "updated05" }
38+
{ id: "id_test_0009", itemNumber: "updated09" }
39+
{ id: "id_test_0007", itemNumber: "updated07" }
40+
{ id: "id_test_0008", itemNumber: "updated08" }
41+
]
42+
}
43+
) {
44+
items {
45+
id
46+
itemNumber
47+
}
48+
}
49+
}
50+
51+
# just sanity check - should do nothign
52+
query afterUpdateMultiple {
53+
Delivery(id: "@{ids/Delivery/1}") {
54+
items {
55+
id
56+
itemNumber
57+
}
58+
}
59+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"clearItems": {
3+
"data": {
4+
"updateDelivery": {
5+
"items": []
6+
}
7+
}
8+
},
9+
"afterClear": {
10+
"data": {
11+
"Delivery": {
12+
"items": []
13+
}
14+
}
15+
},
16+
"updateMultiple": {
17+
"data": {
18+
"updateDelivery": {
19+
"items": []
20+
}
21+
}
22+
},
23+
"afterUpdateMultiple": {
24+
"data": {
25+
"Delivery": {
26+
"items": []
27+
}
28+
}
29+
}
30+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"childEntityUpdatesViaDictStrategyThreshold": 100,
3+
"authRoles": ["allusers"]
4+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# this test makes sure that updating child entities works (even though it does nothing)
2+
# when the child entity list in the database is empty
3+
# this regression test exists because of two bugs we had in the initial dict-based implementation
4+
# - an AQL error when there were updates but the collection was empty
5+
# - updates that did not correspond to actual were persisted as new items (just without id etc.)
6+
7+
mutation clearItems {
8+
updateDelivery(
9+
input: { id: "@{ids/Delivery/1}", removeItems: ["id_init_0000", "id_init_0001"] }
10+
) {
11+
items {
12+
id
13+
itemNumber
14+
}
15+
}
16+
}
17+
18+
# to verify it is cleared in the db
19+
query afterClear {
20+
Delivery(id: "@{ids/Delivery/1}") {
21+
items {
22+
id
23+
itemNumber
24+
}
25+
}
26+
}
27+
28+
mutation updateMultiple {
29+
updateDelivery(
30+
input: {
31+
id: "@{ids/Delivery/1}"
32+
updateItems: [
33+
{ id: "id_test_0003", itemNumber: "updated03" }
34+
{ id: "id_test_0005", itemNumber: "updated05" }
35+
{ id: "id_test_0009", itemNumber: "updated09" }
36+
{ id: "id_test_0007", itemNumber: "updated07" }
37+
{ id: "id_test_0008", itemNumber: "updated08" }
38+
]
39+
}
40+
) {
41+
items {
42+
id
43+
itemNumber
44+
}
45+
}
46+
}
47+
48+
# just sanity check - should do nothign
49+
query afterUpdateMultiple {
50+
Delivery(id: "@{ids/Delivery/1}") {
51+
items {
52+
id
53+
itemNumber
54+
}
55+
}
56+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"clearItems": {
3+
"data": {
4+
"updateDelivery": {
5+
"items": []
6+
}
7+
}
8+
},
9+
"afterClear": {
10+
"data": {
11+
"Delivery": {
12+
"items": []
13+
}
14+
}
15+
},
16+
"updateMultiple": {
17+
"data": {
18+
"updateDelivery": {
19+
"items": []
20+
}
21+
}
22+
},
23+
"afterUpdateMultiple": {
24+
"data": {
25+
"Delivery": {
26+
"items": []
27+
}
28+
}
29+
}
30+
}

src/database/arangodb/aql-generator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,9 @@ register(UpdateChildEntitiesQueryNode, (node, context) => {
829829
// temporary property to store the index of the child entity in the list
830830
aql`LET ${itemsWithIndexVar} = ${aqlExt.parenthesizeList(
831831
aql`FOR ${indexVar}`,
832-
aql`IN 0..(LENGTH(${itemsVar}) - 1)`,
832+
// 0..-1 would evaluate to [0, -1], so the ZIP would complain because the right side
833+
// has more entries (2) than the left (0). RANGE() behaves the same
834+
aql`IN LENGTH(${itemsVar}) > 0 ? 0..(LENGTH(${itemsVar}) - 1) : []`,
833835
aql`RETURN MERGE(NTH(${itemsVar}, ${indexVar}), { __index: ${indexVar} })`,
834836
)}`,
835837

0 commit comments

Comments
 (0)