@neo4j/graphql
Version:
A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations
160 lines • 7.25 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.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConnectFactory = void 0;
const utils_1 = require("../../../../utils/utils");
const MutationOperationField_1 = require("../../ast/input-fields/MutationOperationField");
const ParamInputField_1 = require("../../ast/input-fields/ParamInputField");
const CompositeConnectOperation_1 = require("../../ast/operations/composite/CompositeConnectOperation");
const CompositeConnectPartial_1 = require("../../ast/operations/composite/CompositeConnectPartial");
const ConnectOperation_1 = require("../../ast/operations/ConnectOperation");
const NodeSelectionPattern_1 = require("../../ast/selection/SelectionPattern/NodeSelectionPattern");
const is_concrete_entity_1 = require("../../utils/is-concrete-entity");
const is_interface_entity_1 = require("../../utils/is-interface-entity");
const raise_attribute_ambiguity_1 = require("../../utils/raise-attribute-ambiguity");
class ConnectFactory {
constructor(queryASTFactory) {
this.queryASTFactory = queryASTFactory;
}
createConnectOperation(entity, relationship, input, context) {
const connectOP = new ConnectOperation_1.ConnectOperation({
target: entity,
selectionPattern: new NodeSelectionPattern_1.NodeSelectionPattern({
target: entity,
}),
relationship,
});
this.hydrateConnectOperation({
target: entity,
relationship,
input,
connect: connectOP,
context,
});
return connectOP;
}
createCompositeConnectOperation(entity, relationship, input, context) {
const partials = [];
for (const concreteEntity of entity.concreteEntities) {
const partial = this.createCompositeConnectPartial(concreteEntity, relationship, input, context);
partials.push(partial);
}
return new CompositeConnectOperation_1.CompositeConnectOperation({
partials,
target: entity,
});
}
createCompositeConnectPartial(entity, relationship, input, context) {
const connectOP = new CompositeConnectPartial_1.CompositeConnectPartial({
target: entity,
selectionPattern: new NodeSelectionPattern_1.NodeSelectionPattern({
target: entity,
}),
relationship,
});
this.hydrateConnectOperation({
target: entity,
relationship,
input,
connect: connectOP,
context,
});
return connectOP;
}
hydrateConnectOperation({ target, relationship, input, connect, context, }) {
this.addEntityAuthorization({
entity: target,
context,
operation: connect,
});
(0, utils_1.asArray)(input).forEach((inputItem) => {
const { whereArg, connectArg } = this.parseConnectArgs(inputItem);
const nodeFilters = [];
if (whereArg.node) {
if ((0, is_concrete_entity_1.isConcreteEntity)(relationship.target)) {
nodeFilters.push(...this.queryASTFactory.filterFactory.createNodeFilters(target, whereArg.node));
}
else if ((0, is_interface_entity_1.isInterfaceEntity)(relationship.target)) {
nodeFilters.push(...this.queryASTFactory.filterFactory.createInterfaceNodeFilters({
entity: relationship.target,
targetEntity: target,
whereFields: whereArg.node,
relationship,
}));
}
}
connect.addFilters(...nodeFilters);
(0, utils_1.asArray)(connectArg).forEach((nestedConnectInputFields) => {
Object.entries(nestedConnectInputFields).forEach(([key, value]) => {
const nestedRelationship = target.relationships.get(key);
if (!nestedRelationship) {
throw new Error("Expected relationship on connect operation. Please contact support");
}
const nestedEntity = nestedRelationship.target;
(0, utils_1.asArray)(value).forEach((nestedConnectInputItem) => {
const nestedConnectOperation = this.queryASTFactory.operationsFactory.createConnectOperation(nestedEntity, nestedRelationship, nestedConnectInputItem, context);
const mutationOperationField = new MutationOperationField_1.MutationOperationField(nestedConnectOperation, key);
connect.addField(mutationOperationField, "node");
});
});
});
const targetInputEdge = this.getInputEdge(inputItem, relationship);
/* Create the attributes for the edge */
(0, raise_attribute_ambiguity_1.raiseAttributeAmbiguity)(Object.keys(targetInputEdge), relationship);
for (const key of Object.keys(targetInputEdge)) {
const attribute = relationship.attributes.get(key);
if (attribute) {
const attachedTo = "relationship";
const paramInputField = new ParamInputField_1.ParamInputField({
attachedTo,
attribute,
inputValue: targetInputEdge[key],
});
connect.addField(paramInputField, attachedTo);
}
}
});
}
addEntityAuthorization({ entity, context, operation, }) {
const authFilters = this.queryASTFactory.authorizationFactory.getAuthFilters({
entity,
operations: ["CREATE_RELATIONSHIP"],
context,
afterValidation: true,
});
operation.addAuthFilters(...authFilters);
}
getInputEdge(inputItem, relationship) {
const edge = inputItem.edge ?? {};
// Deals with composite relationships
if (relationship.propertiesTypeName && edge[relationship.propertiesTypeName]) {
return edge[relationship.propertiesTypeName];
}
return edge;
}
parseConnectArgs(args) {
const rawWhere = args.where ?? {};
const whereArg = { node: rawWhere.node, edge: {} };
const connectArg = args.connect ?? {};
return { whereArg, connectArg };
}
}
exports.ConnectFactory = ConnectFactory;
//# sourceMappingURL=ConnectFactory.js.map