@neo4j/graphql
Version:
A GraphQL to Cypher query execution layer for Neo4j and JavaScript GraphQL implementations
265 lines • 12.3 kB
JavaScript
"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