Skip to content

Commit

Permalink
add callback invocation inside the on create statement (still WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
MacondoExpress committed Aug 4, 2022
1 parent cb18739 commit e98aa20
Show file tree
Hide file tree
Showing 7 changed files with 64 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@
* limitations under the License.
*/

import type { RelationField, Context } from "../types";
import type { Node, Relationship } from "../classes";
import type { RelationField, Context, PrimitiveField } from "../types";
import type { Node, Relationship, } from "../classes";
import type { CallbackBucket } from "../classes/CallbackBucket";
import createAuthAndParams from "./create-auth-and-params";
import { AUTH_FORBIDDEN_ERROR } from "../constants";
import { asArray, omitFields } from "../utils/utils";
import * as CypherBuilder from "./cypher-builder/CypherBuilder";
import { convertToCypherParams } from "./cypher-builder/utils";
import { addCallbackAndSetParamCypher } from "./utils/callback-utils";


type CreateOrConnectInput = {
where?: {
Expand All @@ -43,6 +46,7 @@ export function createConnectOrCreateAndParams({
refNode,
context,
withVars,
callbackBucket
}: {
input: CreateOrConnectInput[] | CreateOrConnectInput;
varName: string;
Expand All @@ -51,6 +55,7 @@ export function createConnectOrCreateAndParams({
refNode: Node;
context: Context;
withVars: string[];
callbackBucket: CallbackBucket
}): CypherBuilder.CypherResult {
const withVarsVariables = withVars.map((name) => new CypherBuilder.NamedVariable(name));

Expand All @@ -63,6 +68,7 @@ export function createConnectOrCreateAndParams({
relationField,
refNode,
context,
callbackBucket
});
return result;
});
Expand All @@ -89,20 +95,24 @@ function createConnectOrCreatePartialStatement({
relationField,
refNode,
context,
callbackBucket
}: {
input: CreateOrConnectInput;
baseName: string;
parentVar: string;
relationField: RelationField;
refNode: Node;
context: Context;
callbackBucket: CallbackBucket;
}): CypherBuilder.Clause {
const mergeQuery = mergeStatement({
input,
refNode,
context,
relationField,
parentNode: new CypherBuilder.NamedNode(parentVar),
baseName,
callbackBucket
});

const authQuery = createAuthStatement({
Expand All @@ -123,12 +133,16 @@ function mergeStatement({
context,
relationField,
parentNode,
baseName,
callbackBucket
}: {
input: CreateOrConnectInput;
refNode: Node;
context: Context;
relationField: RelationField;
parentNode: CypherBuilder.Node;
baseName: string
callbackBucket: CallbackBucket;
}): CypherBuilder.Clause {
const whereNodeParameters = getCypherParameters(input.where?.node, refNode);
const onCreateNodeParameters = getCypherParameters(input.onCreate?.node, refNode);
Expand All @@ -139,6 +153,12 @@ function mergeStatement({
});

const unsetAutogeneratedParams = omitFields(autogeneratedParams, Object.keys(whereNodeParameters));
const callbackFields = getCallbackFields(refNode);

const callbackParams = callbackFields.map((callbackField): [CypherBuilder.PropertyRef, CypherBuilder.RawCypher] | [] => {
const varName = new CypherBuilder.NamedVariable(baseName);
return addCallbackAndSetParamCypher(callbackField, varName, parentNode, callbackBucket, "CREATE");
}).filter(tuple => tuple.length !== 0) as [CypherBuilder.PropertyRef, CypherBuilder.RawCypher][];

const rawNodeParams = {
...unsetAutogeneratedParams,
Expand All @@ -151,7 +171,7 @@ function mergeStatement({
}
);

const merge = new CypherBuilder.Merge(node, whereNodeParameters).onCreate(...onCreateParams);
const merge = new CypherBuilder.Merge(node, whereNodeParameters).onCreate(...onCreateParams, ...callbackParams);

const relationshipFields = context.relationships.find((x) => x.properties === relationField.properties);
const autogeneratedRelationshipParams = relationshipFields ? getAutogeneratedParams(relationshipFields) : {};
Expand Down Expand Up @@ -207,6 +227,12 @@ function createAuthStatement({
});
}

function getCallbackFields(node: Node | Relationship): PrimitiveField[] {
const callbackFields = node.primitiveFields
.filter((f) => f.callback);
return callbackFields;
}

// Helper for compatibility reasons
function getAutogeneratedParams(node: Node | Relationship): Record<string, CypherBuilder.Param<any>> {
const autogeneratedFields = node.primitiveFields
Expand Down
1 change: 1 addition & 0 deletions packages/graphql/src/translate/create-create-and-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ function createCreateAndParams({
refNode,
context,
withVars,
callbackBucket
});
res.creates.push(cypher);
res.params = { ...res.params, ...params };
Expand Down
1 change: 1 addition & 0 deletions packages/graphql/src/translate/create-update-and-params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,7 @@ export default function createUpdateAndParams({
refNode,
context,
withVars,
callbackBucket
});
subquery.push(cypher);
res.params = { ...res.params, ...params };
Expand Down
2 changes: 1 addition & 1 deletion packages/graphql/src/translate/translate-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export default async function translateCreate({
let resolvedCallbacks = {};

({ cypher, params: resolvedCallbacks } = await callbackBucket.resolveCallbacksAndFilterCypher({ cypher }));

const createQuery = new CypherBuilder.RawCypher(() => {
return [
cypher,
Expand Down
1 change: 1 addition & 0 deletions packages/graphql/src/translate/translate-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,7 @@ export default async function translateUpdate({
refNode,
context,
withVars,
callbackBucket
});
connectStrs.push(cypher);
cypherParams = { ...cypherParams, ...params };
Expand Down
30 changes: 30 additions & 0 deletions packages/graphql/src/translate/utils/callback-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import type { CallbackBucket } from "../../classes/CallbackBucket";
import type { PrimitiveField } from "../../types";
import * as CypherBuilder from "../cypher-builder/CypherBuilder";

export const addCallbackAndSetParam = (
field: PrimitiveField,
Expand All @@ -42,3 +43,32 @@ export const addCallbackAndSetParam = (

strs.push(`SET ${varName}.${field.dbPropertyName} = $resolvedCallbacks.${paramName}`);
};

export const addCallbackAndSetParamCypher = (
field: PrimitiveField,
variable: CypherBuilder.Variable,
parent: any,
callbackBucket: CallbackBucket,
operation: "CREATE" | "UPDATE"
): [CypherBuilder.PropertyRef, CypherBuilder.RawCypher] | [] => {
if (!field.callback || !field.callback.operations.includes(operation)) {
return [];
}

const propRef = variable.property(field.dbPropertyName as string);

const rawCypherStatement = new CypherBuilder.RawCypher((env: CypherBuilder.Environment) => {
const variableCypher = variable.getCypher(env);
const paramName = `${variableCypher}_${field.fieldName}_${field.callback?.name}`;

callbackBucket.addCallback({
functionName: field.callback?.name as string,
paramName,
parent,
});

return [`$resolvedCallbacks.${paramName}`, {}];
});

return [propRef, rawCypherStatement];
};
2 changes: 1 addition & 1 deletion packages/graphql/tests/integration/issues/1756.int.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ describe("https://github.com/neo4j/graphql/issues/1756", () => {
});
});

describe("https://github.com/neo4j/graphql/issues/1756, nested bug", () => {
describe("https://github.com/neo4j/graphql/issues/1756, on create callback bug", () => {
const productType = generateUniqueType("Product");
const genreType = generateUniqueType("Genre");

Expand Down

0 comments on commit e98aa20

Please sign in to comment.