Skip to content

Commit 585f54a

Browse files
authored
Merge pull request #6775 from neo4j/update-populated-by-new-translation-layer
Update populated by new translation layer
2 parents 80b10e3 + 90265de commit 585f54a

File tree

5 files changed

+43
-28
lines changed

5 files changed

+43
-28
lines changed

packages/graphql/src/translate/queryAST/ast/input-fields/ParamInputField.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ export class ParamInputField extends InputField {
6161
queryASTContext: QueryASTContext<Cypher.Node>,
6262
_inputVariable?: Cypher.Variable
6363
): Cypher.SetParam[] {
64+
// This check is needed for populatedBy callbacks
65+
const param = this.getParam();
66+
if (param instanceof Cypher.Param) {
67+
if (param.value === undefined) {
68+
return [];
69+
}
70+
}
6471
const leftExpr = this.getLeftExpression(queryASTContext);
6572
const rightExpr = this.getRightExpression(queryASTContext);
6673

packages/graphql/src/translate/queryAST/factory/Operations/UpdateFactory.ts

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,6 @@ export class UpdateFactory {
148148
// });
149149

150150
this.addEntityAuthorization({ entity: target, context, operation: update });
151-
152151
asArray(input).forEach((inputItem) => {
153152
const targetInput = this.getInputNode(inputItem, isNested);
154153
raiseAttributeAmbiguityForUpdate(Object.keys(targetInput), target);
@@ -170,12 +169,11 @@ export class UpdateFactory {
170169
}
171170
if (attribute) {
172171
if (operator) {
173-
const paramInputField = this.getInputFieldDeprecated(
174-
"node",
175-
operator,
176-
attribute,
177-
targetInput[key]
178-
);
172+
const value = targetInput[key];
173+
if (attribute.typeHelper.isRequired() && value === null && operator === "SET") {
174+
throw new Error(`Cannot set non-nullable field ${target.name}.${attribute.name} to null`);
175+
}
176+
const paramInputField = this.getInputFieldDeprecated("node", operator, attribute, value);
179177
update.addField(paramInputField);
180178

181179
this.addAttributeAuthorization({
@@ -193,12 +191,13 @@ export class UpdateFactory {
193191
);
194192
}
195193
for (const op of Object.keys(targetInput[fieldName])) {
196-
const paramInputField = this.getInputField(
197-
"node",
198-
op,
199-
attribute,
200-
targetInput[fieldName][op]
201-
);
194+
const value = targetInput[fieldName][op];
195+
if (attribute.typeHelper.isRequired() && value === null && op === "set") {
196+
throw new Error(
197+
`Cannot set non-nullable field ${target.name}.${attribute.name} to null`
198+
);
199+
}
200+
const paramInputField = this.getInputField("node", op, attribute, value);
202201
update.addField(paramInputField);
203202

204203
this.addAttributeAuthorization({
@@ -429,16 +428,22 @@ export class UpdateFactory {
429428
}
430429
}
431430
}
431+
if (Object.keys(targetInputEdge).length > 0) {
432+
this.addPopulatedByFieldToUpdate({
433+
entity: target,
434+
update,
435+
input: targetInputEdge,
436+
callbackBucket,
437+
relationship,
438+
});
439+
}
432440
}
433-
});
434-
435-
// TODO: handle operations
436-
this.addPopulatedByFieldToUpdate({
437-
entity: target,
438-
update,
439-
input,
440-
callbackBucket,
441-
relationship,
441+
this.addPopulatedByFieldToUpdate({
442+
entity: target,
443+
update,
444+
input: targetInput,
445+
callbackBucket,
446+
});
442447
});
443448
}
444449

@@ -501,7 +506,7 @@ export class UpdateFactory {
501506
callbackBucket.addCallback({
502507
functionName: callbackFunctionName,
503508
param: relCallbackParam,
504-
parent: input.edge,
509+
parent: input,
505510
type: attribute.type,
506511
});
507512
});

packages/graphql/src/translate/queryAST/utils/callback-bucket.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,13 @@ export class CallbackBucket {
7979
const callbackFunction = callbacksList[cb.functionName];
8080
if (callbackFunction) {
8181
const paramValue = await callbackFunction(cb.parent, {}, this.context);
82-
cb.param.value = this.parseCallbackResult(paramValue, cb.type);
82+
if (paramValue === undefined) {
83+
cb.param.value = undefined;
84+
} else if (paramValue === null) {
85+
cb.param.value = null;
86+
} else {
87+
cb.param.value = this.parseCallbackResult(paramValue, cb.type);
88+
}
8389
}
8490
})
8591
);

packages/graphql/tests/integration/directives/populatedBy/populatedBy-node-properties.int.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1811,7 +1811,7 @@ describe("@populatedBy directive - Node properties", () => {
18111811
[testMovie.plural]: [
18121812
{
18131813
id: movieId,
1814-
callback: `${date.toISOString().split("T")[1]?.split("Z")[0]}Z`,
1814+
callback: `${date.toISOString().split("T")[1]?.split("Z")[0]}000000Z`,
18151815
},
18161816
],
18171817
},

packages/graphql/tests/integration/directives/populatedBy/populatedBy-relationship-properties.int.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2441,7 +2441,6 @@ describe("@populatedBy directive - Relationship properties", () => {
24412441
type: "Time",
24422442
callback: () => Promise.resolve(`${date.toISOString().split("T")[1]}`),
24432443
expectedValue: `${date.toISOString().split("T")[1]?.split("Z")[0]}000000Z`,
2444-
expectedValueTemp: `${date.toISOString().split("T")[1]?.split("Z")[0]}Z`, // TODO: this is a due to a bug with custom input objects, only used for Update until this is moved to QueryAST
24452444
},
24462445
{
24472446
description: "@populatedBy - LocalDateTime",
@@ -3208,7 +3207,6 @@ describe("@populatedBy directive - Relationship properties", () => {
32083207
const testMovie = testHelper.createUniqueType("Movie");
32093208
const testGenre = testHelper.createUniqueType("Genre");
32103209
const callback = (parent) => `${parent.title_SET}-slug`;
3211-
32123210
const typeDefs = /* GraphQL */ `
32133211
type ${testMovie.name} @node {
32143212
id: ID
@@ -3286,7 +3284,6 @@ describe("@populatedBy directive - Relationship properties", () => {
32863284
`);
32873285

32883286
const result = await testHelper.executeGraphQL(mutation);
3289-
32903287
expect(result.errors).toBeUndefined();
32913288
expect(result.data as any).toMatchObject({
32923289
[testMovie.operations.update]: {

0 commit comments

Comments
 (0)