@neo4j/graphql
Version:
A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations
175 lines • 9.59 kB
JavaScript
;
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const cypher_builder_1 = __importDefault(require("@neo4j/cypher-builder"));
const case_where_1 = require("../utils/case-where");
const get_relationship_type_1 = require("../utils/get-relationship-type");
const check_authentication_1 = require("./authorization/check-authentication");
const create_authorization_before_and_params_1 = require("./authorization/compatibility/create-authorization-before-and-params");
const build_clause_1 = require("./utils/build-clause");
const get_relationship_direction_1 = require("./utils/get-relationship-direction");
const create_connection_where_and_params_1 = __importDefault(require("./where/create-connection-where-and-params"));
function createDeleteAndParams({ deleteInput, varName, node, parentVar, chainStr, withVars, context, parameterPrefix, recursing, }) {
(0, check_authentication_1.checkAuthentication)({ context, node, targetOperations: ["DELETE"] });
function reducer(res, [key, value]) {
(0, check_authentication_1.checkAuthentication)({ context, node, targetOperations: ["DELETE"], field: key });
const relationField = node.relationFields.find((x) => key === x.fieldName);
if (relationField) {
const refNodes = [];
const relationship = context.relationships.find((x) => x.properties === relationField.properties);
if (relationField.union) {
Object.keys(value).forEach((unionTypeName) => {
refNodes.push(context.nodes.find((x) => x.name === unionTypeName));
});
}
else if (relationField.interface) {
relationField.interface.implementations?.forEach((implementationName) => {
refNodes.push(context.nodes.find((x) => x.name === implementationName));
});
}
else {
refNodes.push(context.nodes.find((x) => x.name === relationField.typeMeta.name));
}
const { inStr, outStr } = (0, get_relationship_direction_1.getRelationshipDirection)(relationField);
refNodes.forEach((refNode) => {
(0, check_authentication_1.checkAuthentication)({ context, node: refNode, targetOperations: ["DELETE"] });
const v = relationField.union ? value[refNode.name] : value;
const deletes = relationField.typeMeta.array ? v : [v];
deletes.forEach((d, index) => {
const innerStrs = [];
const variableName = chainStr
? `${varName}${index}`
: `${varName}_${key}${relationField.union || relationField.interface ? `_${refNode.name}` : ""}${index}`;
const relationshipVariable = `${variableName}_relationship`;
const fieldType = (0, get_relationship_type_1.getRelationshipType)(relationField, context.features);
const relTypeStr = `[${relationshipVariable}:${fieldType}]`;
const nodeToDelete = `${variableName}_to_delete`;
const labels = refNode.getLabelString(context);
innerStrs.push("WITH *");
innerStrs.push("CALL(*) {");
innerStrs.push(`OPTIONAL MATCH (${parentVar})${inStr}${relTypeStr}${outStr}(${variableName}${labels})`);
const whereStrs = [];
let aggregationWhere = false;
if (d.where) {
try {
const { cypher: whereCypher, subquery: preComputedSubqueries, params: whereParams, } = (0, create_connection_where_and_params_1.default)({
nodeVariable: variableName,
whereInput: d.where,
node: refNode,
context,
relationshipVariable,
relationship,
parameterPrefix: `${parameterPrefix}${!recursing ? `.${key}` : ""}${relationField.union ? `.${refNode.name}` : ""}${relationField.typeMeta.array ? `[${index}]` : ""}.where`,
});
if (whereCypher) {
whereStrs.push(whereCypher);
res.params = { ...res.params, ...whereParams };
if (preComputedSubqueries) {
innerStrs.push(preComputedSubqueries);
aggregationWhere = true;
}
}
}
catch (_err) {
innerStrs.push(" \n}");
return;
}
}
const authorizationAndParams = (0, create_authorization_before_and_params_1.createAuthorizationBeforeAndParams)({
context,
nodes: [
{
variable: variableName,
node: refNode,
},
],
operations: ["DELETE"],
indexPrefix: "delete",
});
if (authorizationAndParams) {
const { cypher, params, subqueries } = authorizationAndParams;
whereStrs.push(cypher);
res.params = { ...res.params, ...params };
if (subqueries) {
innerStrs.push(subqueries);
innerStrs.push("WITH *");
}
}
if (whereStrs.length) {
const predicate = `${whereStrs.join(" AND ")}`;
if (aggregationWhere) {
const columns = [
new cypher_builder_1.default.NamedVariable(relationshipVariable),
new cypher_builder_1.default.NamedVariable(variableName),
];
const caseWhereClause = (0, case_where_1.caseWhere)(new cypher_builder_1.default.Raw(predicate), columns);
const { cypher } = (0, build_clause_1.buildClause)(caseWhereClause, {
context,
prefix: "aggregateWhereFilter",
});
innerStrs.push(cypher);
}
else {
innerStrs.push(`WHERE ${predicate}`);
}
}
if (d.delete) {
const nestedDeleteInput = Object.entries(d.delete).reduce((d1, [k1, v1]) => ({ ...d1, [k1]: v1 }), {});
const importWithVars = [...withVars, variableName];
const deleteAndParams = createDeleteAndParams({
context,
node: refNode,
deleteInput: nestedDeleteInput,
varName: variableName,
withVars: importWithVars,
parentVar: variableName,
parameterPrefix: `${parameterPrefix}${!recursing ? `.${key}` : ""}${relationField.union ? `.${refNode.name}` : ""}${relationField.typeMeta.array ? `[${index}]` : ""}.delete`,
recursing: false,
});
innerStrs.push(deleteAndParams[0]);
res.params = { ...res.params, ...deleteAndParams[1] };
}
const statements = [
`WITH ${relationshipVariable}, collect(DISTINCT ${variableName}) AS ${nodeToDelete}`,
`CALL(${nodeToDelete}) {`,
`\tUNWIND ${nodeToDelete} AS x`,
`\tDETACH DELETE x`,
`}`,
`}`,
];
innerStrs.push(...statements);
res.strs.push(...innerStrs);
});
});
return res;
}
return res;
}
const { strs, params } = Object.entries(deleteInput).reduce(reducer, {
strs: [],
params: {},
});
return [strs.join("\n"), params];
}
exports.default = createDeleteAndParams;
//# sourceMappingURL=create-delete-and-params.js.map