@neo4j/graphql
Version:
A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations
168 lines • 7.39 kB
JavaScript
"use strict";
/*
* 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 });
exports.CreateOperation = void 0;
const cypher_builder_1 = __importDefault(require("@neo4j/cypher-builder"));
const utils_1 = require("../../../../utils/utils");
const check_authentication_1 = require("../../../authorization/check-authentication");
const create_node_from_entity_1 = require("../../utils/create-node-from-entity");
const ParamInputField_1 = require("../input-fields/ParamInputField");
const operations_1 = require("./operations");
class CreateOperation extends operations_1.MutationOperation {
constructor({ target, relationship, selectionPattern, }) {
super();
this.authFilters = [];
// The response fields in the mutation, currently only READ operations are supported in the MutationResponse
this.projectionOperations = [];
this.inputFields = [];
this.target = target;
this.relationship = relationship;
this.selectionPattern = selectionPattern;
}
/** Prints the name of the Node */
print() {
return `${super.print()} <${this.target.name}>`;
}
getChildren() {
return (0, utils_1.filterTruthy)([
this.selectionPattern,
...this.inputFields,
...this.authFilters,
...this.projectionOperations,
]);
}
addAuthFilters(...filter) {
this.authFilters.push(...filter);
}
addField(field) {
this.inputFields.push(field);
}
addProjectionOperations(operations) {
this.projectionOperations.push(...operations);
}
/** Post subqueries */
getAuthorizationSubqueries(_context) {
const nestedContext = this.nestedContext;
if (!nestedContext) {
throw new Error("Error parsing query, nested context not available, need to call transpile first. Please contact support");
}
return [
...this.getAuthorizationClauses(nestedContext),
...this.inputFields.flatMap((inputField) => {
return inputField.getAuthorizationSubqueries(nestedContext);
}),
];
}
transpile(context) {
if (!context.hasTarget()) {
throw new Error("No parent node found!");
}
context.env.topLevelOperationName = "CREATE";
const { nestedContext } = this.selectionPattern.apply(context);
this.nestedContext = nestedContext;
(0, check_authentication_1.checkEntityAuthentication)({
context: nestedContext.neo4jGraphQLContext,
entity: this.target.entity,
targetOperations: ["CREATE"],
});
this.inputFields.forEach((field) => {
if (field.attachedTo === "node" && field instanceof ParamInputField_1.ParamInputField) {
(0, check_authentication_1.checkEntityAuthentication)({
context: nestedContext.neo4jGraphQLContext,
entity: this.target.entity,
targetOperations: ["CREATE"],
field: field.name,
});
}
});
const createPattern = new cypher_builder_1.default.Pattern(nestedContext.target, {
labels: (0, create_node_from_entity_1.getEntityLabels)(this.target, context.neo4jGraphQLContext),
});
const createClause = new cypher_builder_1.default.Create(createPattern);
const setParams = Array.from(this.inputFields.values()).flatMap((input) => {
return input.getSetParams(nestedContext);
});
const mutationSubqueries = Array.from(this.inputFields.values()).flatMap((input) => {
return input.getSubqueries(nestedContext);
});
let mergeClause;
if (this.relationship) {
const relVar = nestedContext.relationship;
if (!relVar) {
throw new Error("GraphQL Error: Transpilation Error, relationship variable not available. Please contact support");
}
const relDirection = this.relationship.getCypherDirection();
const mergePattern = new cypher_builder_1.default.Pattern(context.target)
.related(relVar, { direction: relDirection, type: this.relationship.type })
.to(nestedContext.target);
mergeClause = new cypher_builder_1.default.Merge(mergePattern).set(...setParams);
}
else {
createClause.set(...setParams);
}
const clauses = cypher_builder_1.default.utils.concat(createClause, ...mutationSubqueries.map((sq) => cypher_builder_1.default.utils.concat(new cypher_builder_1.default.With("*"), sq)), mergeClause);
return { projectionExpr: nestedContext.target, clauses: [clauses] };
}
getAuthorizationClauses(context) {
const { selections, subqueries, predicates, validations } = this.transpileAuthClauses(context);
const predicate = cypher_builder_1.default.and(...predicates);
const lastSelection = selections[selections.length - 1];
if (!predicates.length && !validations.length) {
return [];
}
else {
if (lastSelection) {
lastSelection.where(predicate);
return [...subqueries, new cypher_builder_1.default.With("*"), ...selections, ...validations];
}
return [...subqueries, new cypher_builder_1.default.With("*").where(predicate), ...selections, ...validations];
}
}
transpileAuthClauses(context) {
const selections = [];
const subqueries = [];
const predicates = [];
const validations = [];
for (const authFilter of this.authFilters) {
const extraSelections = authFilter.getSelection(context);
const authSubqueries = authFilter.getSubqueries(context);
const authPredicate = authFilter.getPredicate(context);
const validation = authFilter.getValidation(context, "AFTER"); // CREATE only has AFTER auth
if (extraSelections) {
selections.push(...extraSelections);
}
if (authSubqueries) {
subqueries.push(...authSubqueries);
}
if (authPredicate) {
predicates.push(authPredicate);
}
if (validation) {
validations.push(validation);
}
}
return { selections, subqueries, predicates, validations };
}
}
exports.CreateOperation = CreateOperation;
//# sourceMappingURL=CreateOperation.js.map