UNPKG

@neo4j/graphql

Version:

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

232 lines 10.2 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. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.getWhereFieldsForAttributes = getWhereFieldsForAttributes; const constants_1 = require("../constants"); const ConcreteEntityAdapter_1 = require("../schema-model/entity/model-adapters/ConcreteEntityAdapter"); const augment_where_input_1 = require("./generation/augment-where-input"); const get_input_filter_from_attribute_type_1 = require("./generation/get-input-filter-from-attribute-type"); const utils_1 = require("./generation/utils"); const to_compose_1 = require("./to-compose"); // TODO: refactoring needed! // isWhereField, isFilterable, ... extracted out into attributes category // even more now as Cypher filters and generic input object are added in the mix function getWhereFieldsForAttributes({ attributes, userDefinedFieldDirectives, features, ignoreCypherFieldFilters, composer, }) { const result = {}; // Add the where fields for each attribute for (const field of attributes) { const userDefinedDirectivesOnField = userDefinedFieldDirectives?.get(field.name); const deprecatedDirectives = (0, to_compose_1.graphqlDirectivesToCompose)((userDefinedDirectivesOnField ?? []).filter((directive) => directive.name.value === constants_1.DEPRECATED)); if (field.annotations.cypher) { // If the field is a cypher field and ignoreCypherFieldFilters is true, skip it if (ignoreCypherFieldFilters === true) { continue; } // If the field is a cypher field with arguments, skip it if (field.args.length > 0) { continue; } if (field.annotations.cypher.targetEntity) { const targetEntityAdapter = new ConcreteEntityAdapter_1.ConcreteEntityAdapter(field.annotations.cypher.targetEntity); const type = targetEntityAdapter.operations.whereInputTypeName; // Add list where field filters (e.g. name_ALL, name_NONE, name_SINGLE, name_SOME) if (field.typeHelper.isList()) { addCypherRelationshipLegacyFilters({ field, type, result, deprecatedDirectives, }); addCypherRelationshipFilter({ field, type, result, deprecatedDirectives, composer }); } else { // Add base where field filter (e.g. name) result[field.name] = { type, directives: deprecatedDirectives, }; } continue; } } result[field.name] = { type: (0, get_input_filter_from_attribute_type_1.getInputFilterFromAttributeType)(field, features), directives: deprecatedDirectives, }; if (!(0, utils_1.shouldAddDeprecatedFields)(features, "attributeFilters")) { continue; } result[`${field.name}_EQ`] = { type: field.getInputTypeNames().where.pretty, directives: getAttributeDeprecationDirective(deprecatedDirectives, field, "EQ"), }; // If the field is a boolean, skip it // This is done here because the previous additions are still added for boolean fields if (field.typeHelper.isBoolean()) { continue; } // If the field is an array, add the includes and not includes fields // if (field.isArray()) { if (field.typeHelper.isList()) { result[`${field.name}_INCLUDES`] = { type: field.getInputTypeNames().where.type, directives: getAttributeDeprecationDirective(deprecatedDirectives, field, "INCLUDES"), }; continue; } // If the field is not an array, add the in and not in fields result[`${field.name}_IN`] = { type: field.getFilterableInputTypeName(), directives: getAttributeDeprecationDirective(deprecatedDirectives, field, "IN"), }; // If the field is a number or temporal, add the comparison operators if (field.isNumericalOrTemporal()) { ["LT", "LTE", "GT", "GTE"].forEach((comparator) => { result[`${field.name}_${comparator}`] = { type: field.getInputTypeNames().where.type, directives: getAttributeDeprecationDirective(deprecatedDirectives, field, comparator), }; }); continue; } // If the field is spatial, add the point comparison operators if (field.typeHelper.isSpatial()) { ["DISTANCE", "LT", "LTE", "GT", "GTE"].forEach((comparator) => { result[`${field.name}_${comparator}`] = { type: `${field.getTypeName()}Distance`, directives: getAttributeDeprecationDirective(deprecatedDirectives, field, comparator), }; }); continue; } // If the field is a string, add the string comparison operators if (field.typeHelper.isString() || field.typeHelper.isID()) { const stringWhereOperators = [ { comparator: "CONTAINS", typeName: field.getInputTypeNames().where.type }, { comparator: "STARTS_WITH", typeName: field.getInputTypeNames().where.type }, { comparator: "ENDS_WITH", typeName: field.getInputTypeNames().where.type }, ]; Object.entries(features?.filters?.[field.getInputTypeNames().where.type] || {}).forEach(([filter, enabled]) => { if (enabled) { if (filter === "MATCHES") { stringWhereOperators.push({ comparator: filter, typeName: "String" }); } else { stringWhereOperators.push({ comparator: filter, typeName: field.getInputTypeNames().where.type, }); } } }); stringWhereOperators.forEach(({ comparator, typeName }) => { const excludedComparators = ["CASE_INSENSITIVE"]; if (!excludedComparators.includes(comparator)) { result[`${field.name}_${comparator}`] = { type: typeName, directives: getAttributeDeprecationDirective(deprecatedDirectives, field, comparator), }; } }); } } return result; } function getAttributeDeprecationDirective(deprecatedDirectives, field, comparator) { if (deprecatedDirectives.length) { return deprecatedDirectives; } switch (comparator) { case "DISTANCE": case "LT": case "LTE": case "GT": case "GTE": case "CONTAINS": case "MATCHES": case "IN": case "INCLUDES": case "EQ": { return [ { name: constants_1.DEPRECATED, args: { reason: `Please use the relevant generic filter ${field.name}: { ${comparator.toLowerCase()}: ... }`, }, }, ]; } case "STARTS_WITH": { return [ { name: constants_1.DEPRECATED, args: { reason: `Please use the relevant generic filter ${field.name}: { startsWith: ... }`, }, }, ]; } case "ENDS_WITH": { return [ { name: constants_1.DEPRECATED, args: { reason: `Please use the relevant generic filter ${field.name}: { endsWith: ... }`, }, }, ]; } default: { throw new Error(`Unknown comparator: ${comparator}`); } } } function addCypherRelationshipFilter({ field, type, result, deprecatedDirectives, composer, }) { const targetName = field.annotations.cypher?.targetEntity?.name; if (!targetName) { throw new Error("Target entity is not defined for the cypher field"); } // Relationship filters const relationshipFiltersFields = (0, augment_where_input_1.fieldConfigsToFieldConfigMap)({ deprecatedDirectives: [], fields: (0, augment_where_input_1.getRelationshipFilters)({ relationshipInfo: { targetName, inputTypeName: type }, }), }); // this mimic the adapter RelationshipOperation field "relationshipFiltersTypeName" const relationshipType = `${targetName}RelationshipFilters`; composer.getOrCreateITC(relationshipType, (itc) => { itc.addFields(relationshipFiltersFields); }); result[field.name] = { type: relationshipType, directives: deprecatedDirectives, }; } function addCypherRelationshipLegacyFilters({ field, type, result, deprecatedDirectives, }) { const quantifiers = ["ALL", "NONE", "SINGLE", "SOME"]; for (const quantifier of quantifiers) { result[`${field.name}_${quantifier}`] = { type, directives: deprecatedDirectives, }; } } //# sourceMappingURL=get-where-fields.js.map