Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove deprecated aggregation fields #6027

Open
wants to merge 8 commits into
base: aggregation-7
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/quick-eagles-join.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@neo4j/graphql": major
---

Remove deprecated fields `*aggregate` in favor of the `aggregate` field in connections. Remove flag "deprecatedAggregateOperations"
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
*/

import { GraphQLNonNull, GraphQLString, type DirectiveNode } from "graphql";
import type { Directive, InterfaceTypeComposer, SchemaComposer } from "graphql-compose";
import { ObjectTypeComposer } from "graphql-compose";
import { ObjectTypeComposer, type Directive, type InterfaceTypeComposer, type SchemaComposer } from "graphql-compose";
import { type ComplexityEstimatorHelper } from "../../classes/ComplexityEstimatorHelper";
import type { Subgraph } from "../../classes/Subgraph";
import { DEPRECATED } from "../../constants";
Expand All @@ -30,7 +29,6 @@ import { RelationshipAdapter } from "../../schema-model/relationship/model-adapt
import { RelationshipDeclarationAdapter } from "../../schema-model/relationship/model-adapters/RelationshipDeclarationAdapter";
import type { Neo4jFeaturesSettings } from "../../types";
import { FieldAggregationComposer } from "../aggregations/field-aggregation-composer";
import { DEPRECATE_NESTED_AGGREGATION } from "../constants";
import {
augmentObjectOrInterfaceTypeWithConnectionField,
augmentObjectOrInterfaceTypeWithRelationshipField,
Expand All @@ -48,7 +46,6 @@ import { getRelationshipPropertiesTypeDescription, withObjectType } from "../gen
import { withRelationInputType } from "../generation/relation-input";
import { withSortInputType } from "../generation/sort-and-options-input";
import { augmentUpdateInputTypeWithUpdateFieldInput, withUpdateInputType } from "../generation/update-input";
import { shouldAddDeprecatedFields } from "../generation/utils";
import { withSourceWhereInputType, withWhereInputType } from "../generation/where-input";
import { graphqlDirectivesToCompose } from "../to-compose";

Expand Down Expand Up @@ -269,29 +266,7 @@ export function createRelationshipFields({
// make a new fn augmentObjectTypeWithAggregationField
const fieldAggregationComposer = new FieldAggregationComposer(schemaComposer, subgraph);

const aggregationTypeObject = fieldAggregationComposer.createAggregationTypeObject(
relationshipAdapter,
features
);

const aggregationFieldsBaseArgs = {
where: relationshipTarget.operations.whereInputTypeName,
};

if (relationshipAdapter.aggregate) {
if (shouldAddDeprecatedFields(features, "deprecatedAggregateOperations")) {
composeNode.addFields({
[relationshipAdapter.operations.aggregateFieldName]: {
type: aggregationTypeObject,
args: aggregationFieldsBaseArgs,
directives:
deprecatedDirectives.length > 0
? deprecatedDirectives
: [DEPRECATE_NESTED_AGGREGATION(relationshipAdapter)],
},
});
}
}
fieldAggregationComposer.createAggregationTypeObject(relationshipAdapter, features);
}

if (relationshipTarget instanceof ConcreteEntityAdapter) {
Expand Down
150 changes: 63 additions & 87 deletions packages/graphql/src/schema/make-augmented-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,13 +45,13 @@ import { cypherResolver } from "./resolvers/field/cypher";
import { createResolver } from "./resolvers/mutation/create";
import { deleteResolver } from "./resolvers/mutation/delete";
import { updateResolver } from "./resolvers/mutation/update";
import { aggregateResolver } from "./resolvers/query/aggregate";
import { findResolver } from "./resolvers/query/read";
import { rootConnectionResolver } from "./resolvers/query/root-connection";
import { attributeAdapterToComposeFields, graphqlDirectivesToCompose } from "./to-compose";

// GraphQL type imports
import type { GraphQLToolsResolveMethods } from "graphql-compose/lib/SchemaComposer";
import { type ComplexityEstimatorHelper } from "../classes/ComplexityEstimatorHelper";
import type { Subgraph } from "../classes/Subgraph";
import { SHAREABLE } from "../constants";
import { CreateInfo } from "../graphql/objects/CreateInfo";
Expand All @@ -72,7 +72,6 @@ import { RelationshipDeclarationAdapter } from "../schema-model/relationship/mod
import type { CypherField, Neo4jFeaturesSettings } from "../types";
import { asArray, filterTruthy } from "../utils/utils";
import { augmentVectorSchema } from "./augment/vector";
import { DEPRECATE_AGGREGATION } from "./constants";
import { createConnectionFields } from "./create-connection-fields";
import { addGlobalNodeFields } from "./create-global-nodes";
import { createRelationshipFields } from "./create-relationship-fields/create-relationship-fields";
Expand All @@ -83,14 +82,12 @@ import { withInterfaceType } from "./generation/interface-type";
import { withObjectType } from "./generation/object-type";
import { withMutationResponseTypes } from "./generation/response-types";
import { withUpdateInputType } from "./generation/update-input";
import { shouldAddDeprecatedFields } from "./generation/utils";
import { withUniqueWhereInputType, withWhereInputType } from "./generation/where-input";
import getNodes from "./get-nodes";
import { getResolveAndSubscriptionMethods } from "./get-resolve-and-subscription-methods";
import { filterInterfaceTypes } from "./make-augmented-schema/filter-interface-types";
import { getUserDefinedDirectives } from "./make-augmented-schema/user-defined-directives";
import { generateSubscriptionTypes } from "./subscriptions/generate-subscription-types";
import { type ComplexityEstimatorHelper } from "../classes/ComplexityEstimatorHelper";

function definitionNodeHasName(x: DefinitionNode): x is DefinitionNode & { name: NameNode } {
return "name" in x;
Expand Down Expand Up @@ -322,12 +319,12 @@ function makeAugmentedSchema({
graphqlDirectivesToCompose(userDefinedDirectivesForUnion.get(unionEntityAdapter.name) || [])
);
if (unionEntityAdapter.isReadable) {
complexityEstimatorHelper.registerField("Query", unionEntityAdapter.operations.rootTypeFieldNames.read)
complexityEstimatorHelper.registerField("Query", unionEntityAdapter.operations.rootTypeFieldNames.read);
composer.Query.addFields({
[unionEntityAdapter.operations.rootTypeFieldNames.read]: findResolver({
entityAdapter: unionEntityAdapter,
composer,
isLimitRequired: features?.limitRequired,
isLimitRequired: features?.limitRequired,
}),
});
}
Expand Down Expand Up @@ -463,9 +460,9 @@ function makeAugmentedSchema({
}

const generatedTypeDefs = composer.toSDL();

let parsedDoc = parse(generatedTypeDefs);

const documentNames = new Set(parsedDoc.definitions.filter(definitionNodeHasName).map((x) => x.name.value));

const resolveMethods = getResolveAndSubscriptionMethods(composer);
Expand Down Expand Up @@ -528,8 +525,12 @@ function makeAugmentedSchema({

parsedDoc = {
...parsedDoc,
definitions: getTransformedDefinitionNodesForAugmentedSchema({schemaExtensions, definitions: parsedDoc.definitions, complexityEstimatorHelper}),
}
definitions: getTransformedDefinitionNodesForAugmentedSchema({
schemaExtensions,
definitions: parsedDoc.definitions,
complexityEstimatorHelper,
}),
};

return {
nodes,
Expand All @@ -539,66 +540,61 @@ function makeAugmentedSchema({
};
}

function getTransformedDefinitionNodesForAugmentedSchema({
schemaExtensions,
definitions,
complexityEstimatorHelper,
function getTransformedDefinitionNodesForAugmentedSchema({
schemaExtensions,
definitions,
complexityEstimatorHelper,
}: {
schemaExtensions: SchemaExtensionNode | undefined;
definitions: readonly DefinitionNode[];
complexityEstimatorHelper: ComplexityEstimatorHelper
schemaExtensions: SchemaExtensionNode | undefined;
definitions: readonly DefinitionNode[];
complexityEstimatorHelper: ComplexityEstimatorHelper;
}): DefinitionNode[] {
const definitionNodes: DefinitionNode[] = []
const definitionNodes: DefinitionNode[] = [];
// do not propagate Neo4jGraphQL directives on schema extensions
asArray(schemaExtensions).reduce(
(acc, schemaExtension: SchemaExtensionNode) => {
acc.push({
kind: schemaExtension.kind,
loc: schemaExtension.loc,
operationTypes: schemaExtension.operationTypes,
directives: schemaExtension.directives?.filter(
(schemaDirective) =>
!["query", "mutation", "subscription", "authentication"].includes(schemaDirective.name.value)
),
})
return acc;
}, definitionNodes)
asArray(schemaExtensions).reduce((acc, schemaExtension: SchemaExtensionNode) => {
acc.push({
kind: schemaExtension.kind,
loc: schemaExtension.loc,
operationTypes: schemaExtension.operationTypes,
directives: schemaExtension.directives?.filter(
(schemaDirective) =>
!["query", "mutation", "subscription", "authentication"].includes(schemaDirective.name.value)
),
});
return acc;
}, definitionNodes);
// filter out some definition nodes
// add FieldEstimator extensions for complexity calculation
const seen = {}
const seen = {};
definitions.reduce<DefinitionNode[]>((acc, definition) => {
if (shouldKeepDefinitionNode(definition, seen)) {
acc.push(complexityEstimatorHelper.hydrateDefinitionNodeWithComplexityExtensions(definition))
acc.push(complexityEstimatorHelper.hydrateDefinitionNodeWithComplexityExtensions(definition));
}
return acc;
}, definitionNodes)
}, definitionNodes);
return definitionNodes;
}

function shouldKeepDefinitionNode(definition: DefinitionNode, seen: Record<string, any>) {
// Filter out default scalars, they are not needed and can cause issues
if (definition.kind === Kind.SCALAR_TYPE_DEFINITION) {
if (
[
GraphQLBoolean.name,
GraphQLFloat.name,
GraphQLID.name,
GraphQLInt.name,
GraphQLString.name,
].includes(definition.name.value)
) {
return false;
}
}
if (!("name" in definition)) {
return true;
}
const n = definition.name?.value as string;
if (seen[n]) {
return false;
}
seen[n] = n;
return true;
// Filter out default scalars, they are not needed and can cause issues
if (definition.kind === Kind.SCALAR_TYPE_DEFINITION) {
if (
[GraphQLBoolean.name, GraphQLFloat.name, GraphQLID.name, GraphQLInt.name, GraphQLString.name].includes(
definition.name.value
)
) {
return false;
}
}
if (!("name" in definition)) {
return true;
}
const n = definition.name?.value as string;
if (seen[n]) {
return false;
}
seen[n] = n;
return true;
}

export default makeAugmentedSchema;
Expand Down Expand Up @@ -669,7 +665,7 @@ function generateObjectType({
ensureNonEmptyInput(composer, concreteEntityAdapter.operations.createInputTypeName);

if (concreteEntityAdapter.isReadable) {
complexityEstimatorHelper.registerField("Query", concreteEntityAdapter.operations.rootTypeFieldNames.read)
complexityEstimatorHelper.registerField("Query", concreteEntityAdapter.operations.rootTypeFieldNames.read);
composer.Query.addFields({
[concreteEntityAdapter.operations.rootTypeFieldNames.read]: findResolver({
entityAdapter: concreteEntityAdapter,
Expand All @@ -682,8 +678,10 @@ function generateObjectType({
graphqlDirectivesToCompose(propagatedDirectives)
);


complexityEstimatorHelper.registerField("Query", concreteEntityAdapter.operations.rootTypeFieldNames.connection)
complexityEstimatorHelper.registerField(
"Query",
concreteEntityAdapter.operations.rootTypeFieldNames.connection
);
composer.Query.addFields({
[concreteEntityAdapter.operations.rootTypeFieldNames.connection]: rootConnectionResolver({
composer,
Expand All @@ -705,18 +703,6 @@ function generateObjectType({
composer,
features,
});

if (shouldAddDeprecatedFields(features, "deprecatedAggregateOperations")) {
composer.Query.addFields({
[concreteEntityAdapter.operations.rootTypeFieldNames.aggregate]: aggregateResolver({
entityAdapter: concreteEntityAdapter,
}),
});
composer.Query.setFieldDirectives(concreteEntityAdapter.operations.rootTypeFieldNames.aggregate, [
...graphqlDirectivesToCompose(propagatedDirectives),
DEPRECATE_AGGREGATION(concreteEntityAdapter),
]);
}
}

if (concreteEntityAdapter.isCreatable) {
Expand Down Expand Up @@ -816,7 +802,7 @@ function generateInterfaceObjectType({

const propagatedDirectives = propagatedDirectivesForNode.get(interfaceEntityAdapter.name) || [];
if (interfaceEntityAdapter.isReadable) {
complexityEstimatorHelper.registerField("Query", interfaceEntityAdapter.operations.rootTypeFieldNames.read)
complexityEstimatorHelper.registerField("Query", interfaceEntityAdapter.operations.rootTypeFieldNames.read);
composer.Query.addFields({
[interfaceEntityAdapter.operations.rootTypeFieldNames.read]: findResolver({
entityAdapter: interfaceEntityAdapter,
Expand All @@ -830,7 +816,10 @@ function generateInterfaceObjectType({
graphqlDirectivesToCompose(propagatedDirectives)
);

complexityEstimatorHelper.registerField("Query", interfaceEntityAdapter.operations.rootTypeFieldNames.connection)
complexityEstimatorHelper.registerField(
"Query",
interfaceEntityAdapter.operations.rootTypeFieldNames.connection
);
composer.Query.addFields({
[interfaceEntityAdapter.operations.rootTypeFieldNames.connection]: rootConnectionResolver({
composer,
Expand All @@ -852,18 +841,5 @@ function generateInterfaceObjectType({
composer,
features,
});

if (shouldAddDeprecatedFields(features, "deprecatedAggregateOperations")) {
composer.Query.addFields({
[interfaceEntityAdapter.operations.rootTypeFieldNames.aggregate]: aggregateResolver({
entityAdapter: interfaceEntityAdapter,
}),
});

composer.Query.setFieldDirectives(interfaceEntityAdapter.operations.rootTypeFieldNames.aggregate, [
...graphqlDirectivesToCompose(propagatedDirectives),
DEPRECATE_AGGREGATION(interfaceEntityAdapter),
]);
}
}
}
63 changes: 0 additions & 63 deletions packages/graphql/src/schema/resolvers/query/aggregate.ts

This file was deleted.

Loading