UNPKG

@neo4j/graphql

Version:

A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations

168 lines 7.39 kB
"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