UNPKG

@neo4j/graphql

Version:

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

265 lines 12.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.withAggregateSelectionType = withAggregateSelectionType; exports.withConnectionAggregateInputType = withConnectionAggregateInputType; exports.withAggregateInputType = withAggregateInputType; const graphql_1 = require("graphql"); const constants_1 = require("../../constants"); const CountScalarAggregationFilters_1 = require("../../graphql/input-objects/generic-aggregation-filters/CountScalarAggregationFilters"); const IntScalarFilters_1 = require("../../graphql/input-objects/generic-operators/IntScalarFilters"); const ConcreteEntityAdapter_1 = require("../../schema-model/entity/model-adapters/ConcreteEntityAdapter"); const InterfaceEntityAdapter_1 = require("../../schema-model/entity/model-adapters/InterfaceEntityAdapter"); const RelationshipDeclarationAdapter_1 = require("../../schema-model/relationship/model-adapters/RelationshipDeclarationAdapter"); const constants_2 = require("../constants"); const numerical_1 = require("../resolvers/field/numerical"); const to_compose_1 = require("../to-compose"); const get_aggregation_filter_from_attribute_type_1 = require("./get-aggregation-filter-from-attribute-type"); const utils_1 = require("./utils"); function withAggregateSelectionType({ entityAdapter, aggregationTypesMapper, propagatedDirectives, composer, features, }) { const aggregateSelection = composer.createObjectTC({ name: entityAdapter.operations.aggregateTypeNames.selection, fields: { count: { type: new graphql_1.GraphQLNonNull(graphql_1.GraphQLInt), resolve: numerical_1.numericalResolver, args: {}, }, }, directives: (0, to_compose_1.graphqlDirectivesToCompose)(propagatedDirectives), }); aggregateSelection.addFields(makeAggregableFields({ entityAdapter, aggregationTypesMapper, features })); createConnectionAggregate({ entityAdapter, aggregationTypesMapper, propagatedDirectives, composer, features, }); return aggregateSelection; } /** Create aggregate field inside connections */ function createConnectionAggregate({ entityAdapter, aggregationTypesMapper, propagatedDirectives, composer, features, }) { const aggregableFields = makeAggregableFields({ entityAdapter, aggregationTypesMapper, features }); let aggregateNode; const hasNodeAggregateFields = Object.keys(aggregableFields).length > 0; if (hasNodeAggregateFields) { aggregateNode = composer.createObjectTC({ name: entityAdapter.operations.aggregateTypeNames.node, fields: {}, directives: (0, to_compose_1.graphqlDirectivesToCompose)(propagatedDirectives), }); aggregateNode.addFields(aggregableFields); } const connectionAggregate = composer.createObjectTC({ name: entityAdapter.operations.aggregateTypeNames.connection, fields: { count: aggregationTypesMapper.getCountType().NonNull, }, directives: (0, to_compose_1.graphqlDirectivesToCompose)(propagatedDirectives), }); if (aggregateNode) { connectionAggregate.addFields({ node: aggregateNode.NonNull, }); } return connectionAggregate; } function makeAggregableFields({ entityAdapter, aggregationTypesMapper, features, }) { const aggregableFields = {}; const aggregableAttributes = entityAdapter.aggregableFields; for (const attribute of aggregableAttributes) { const objectTypeComposer = aggregationTypesMapper.getAggregationType(attribute.getTypeName()); if (objectTypeComposer) { aggregableFields[attribute.name] = { type: objectTypeComposer.NonNull }; } } return aggregableFields; } function withConnectionAggregateInputType({ relationshipAdapter, entityAdapter, composer, userDefinedDirectivesOnTargetFields, features, }) { const aggregateInputTypeName = relationshipAdapter.operations.connectionAggregateInputTypeName; if (composer.has(aggregateInputTypeName)) { return composer.getITC(aggregateInputTypeName); } const aggregateWhereInput = composer.createInputTC({ name: aggregateInputTypeName, fields: { count: CountScalarAggregationFilters_1.ConnectionAggregationCountFilterInput, }, }); aggregateWhereInput.addFields({ AND: aggregateWhereInput.NonNull.List, OR: aggregateWhereInput.NonNull.List, NOT: aggregateWhereInput, }); const nodeWhereInputType = withAggregationWhereInputType({ relationshipAdapter, entityAdapter, composer, userDefinedDirectivesOnTargetFields, features, }); if (nodeWhereInputType) { aggregateWhereInput.addFields({ node: nodeWhereInputType }); } const edgeWhereInputType = withAggregationWhereInputType({ relationshipAdapter, entityAdapter: relationshipAdapter, composer, userDefinedDirectivesOnTargetFields, features, }); if (edgeWhereInputType) { aggregateWhereInput.addFields({ edge: edgeWhereInputType }); } return aggregateWhereInput; } /** * Deprecated Aggregation filters, for the Aggregation inside Connection input see withConnectionAggregateInputType **/ function withAggregateInputType({ relationshipAdapter, entityAdapter, // TODO: this is relationshipAdapter.target but from the context above it is known to be ConcreteEntity and we don't know this yet!!! composer, userDefinedDirectivesOnTargetFields, features, }) { const aggregateInputTypeName = relationshipAdapter.operations.aggregateInputTypeName; if (composer.has(aggregateInputTypeName)) { return composer.getITC(aggregateInputTypeName); } const aggregateWhereInput = composer.createInputTC({ name: aggregateInputTypeName, fields: { count_EQ: graphql_1.GraphQLInt, count_LT: graphql_1.GraphQLInt, count_LTE: graphql_1.GraphQLInt, count_GT: graphql_1.GraphQLInt, count_GTE: graphql_1.GraphQLInt, count: IntScalarFilters_1.IntScalarFilters, }, }); aggregateWhereInput.addFields({ AND: aggregateWhereInput.NonNull.List, OR: aggregateWhereInput.NonNull.List, NOT: aggregateWhereInput, }); const nodeWhereInputType = withAggregationWhereInputType({ relationshipAdapter, entityAdapter, composer, userDefinedDirectivesOnTargetFields, features, }); if (nodeWhereInputType) { aggregateWhereInput.addFields({ node: nodeWhereInputType }); } const edgeWhereInputType = withAggregationWhereInputType({ relationshipAdapter, entityAdapter: relationshipAdapter, composer, userDefinedDirectivesOnTargetFields, features, }); if (edgeWhereInputType) { aggregateWhereInput.addFields({ edge: edgeWhereInputType }); } return aggregateWhereInput; } function withAggregationWhereInputType({ relationshipAdapter, entityAdapter, composer, userDefinedDirectivesOnTargetFields, features, }) { const aggregationInputName = entityAdapter instanceof ConcreteEntityAdapter_1.ConcreteEntityAdapter || entityAdapter instanceof InterfaceEntityAdapter_1.InterfaceEntityAdapter ? relationshipAdapter.operations.nodeAggregationWhereInputTypeName : relationshipAdapter.operations.edgeAggregationWhereInputTypeName; if (composer.has(aggregationInputName)) { return composer.getITC(aggregationInputName); } if (entityAdapter instanceof RelationshipDeclarationAdapter_1.RelationshipDeclarationAdapter) { return; } const aggregationFields = entityAdapter.aggregationWhereFields; if (!aggregationFields.length) { return; } const aggregationInput = composer.createInputTC({ name: aggregationInputName, fields: {}, }); aggregationInput.addFields({ AND: aggregationInput.NonNull.List, OR: aggregationInput.NonNull.List, NOT: aggregationInput, }); const aggrFields = makeAggregationFields(aggregationFields, userDefinedDirectivesOnTargetFields, features); aggregationInput.addFields(aggrFields); return aggregationInput; } function makeAggregationFields(attributes, userDefinedDirectivesOnTargetFields, features) { const fields = {}; for (const attribute of attributes) { if ((0, utils_1.shouldAddDeprecatedFields)(features, "aggregationFilters")) { addDeprecatedAggregationFieldsByType(attribute, userDefinedDirectivesOnTargetFields?.get(attribute.name), fields); } if (attribute.isAggregationWhereField()) { fields[attribute.name] = (0, get_aggregation_filter_from_attribute_type_1.getAggregationFilterFromAttributeType)(attribute); } } return fields; } // TODO: refactor this by introducing specialized Adapters function addDeprecatedAggregationFieldsByType(attribute, directivesOnField, fields) { if (attribute.typeHelper.isString()) { for (const operator of constants_1.AGGREGATION_COMPARISON_OPERATORS) { fields[`${attribute.name}_AVERAGE_LENGTH_${operator}`] = { type: graphql_1.GraphQLFloat, directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "averageLength", operator)], }; fields[`${attribute.name}_LONGEST_LENGTH_${operator}`] = { type: graphql_1.GraphQLInt, directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "longestLength", operator)], }; fields[`${attribute.name}_SHORTEST_LENGTH_${operator}`] = { type: graphql_1.GraphQLInt, directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "shortestLength", operator)], }; } return fields; } if (attribute.typeHelper.isNumeric() || attribute.typeHelper.isDuration()) { // Types that you can average // https://neo4j.com/docs/cypher-manual/current/functions/aggregating/#functions-avg // https://neo4j.com/docs/cypher-manual/current/functions/aggregating/#functions-avg-duration // String uses avg(size()) for (const operator of constants_1.AGGREGATION_COMPARISON_OPERATORS) { fields[`${attribute.name}_MIN_${operator}`] = { type: attribute.getTypeName(), directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "min", operator)], }; fields[`${attribute.name}_MAX_${operator}`] = { type: attribute.getTypeName(), directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "max", operator)], }; if (attribute.getTypeName() !== "Duration") { fields[`${attribute.name}_SUM_${operator}`] = { type: attribute.getTypeName(), directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "sum", operator)], }; } const averageType = attribute.typeHelper.isBigInt() ? "BigInt" : attribute.typeHelper.isDuration() ? "Duration" : graphql_1.GraphQLFloat; fields[`${attribute.name}_AVERAGE_${operator}`] = { type: averageType, directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "average", operator)], }; } return fields; } for (const operator of constants_1.AGGREGATION_COMPARISON_OPERATORS) { fields[`${attribute.name}_MIN_${operator}`] = { type: attribute.getTypeName(), directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "min", operator)], }; fields[`${attribute.name}_MAX_${operator}`] = { type: attribute.getTypeName(), directives: [(0, constants_2.DEPRECATE_AGGREGATION_FILTERS)(attribute.name, "max", operator)], }; } return fields; } //# sourceMappingURL=aggregate-types.js.map