Skip to content

Commit

Permalink
Add deprecated directives to AggregationWhereInput (neo4j#4797)
Browse files Browse the repository at this point in the history
  • Loading branch information
a-alle authored Mar 4, 2024
1 parent 7f32f59 commit 19c2a7a
Show file tree
Hide file tree
Showing 7 changed files with 123 additions and 60 deletions.
5 changes: 5 additions & 0 deletions .changeset/violet-penguins-relate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@neo4j/graphql": patch
---

Fix user defined deprecated directives not propagated on all generated types
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,25 @@ export function createRelationshipFields({
const deprecatedDirectives = graphqlDirectivesToCompose(
(userDefinedDirectivesOnField || []).filter((directive) => directive.name.value === DEPRECATED)
);
const userDefinedDirectivesOnTargetFields = userDefinedFieldDirectivesForNode.get(
relationshipAdapter.target.name
);

const relationshipFieldsOpts: {
relationshipAdapter: RelationshipAdapter | RelationshipDeclarationAdapter;
composer: SchemaComposer<any>;
composeNode: ObjectTypeComposer<any, any> | InterfaceTypeComposer<any, any>;
userDefinedFieldDirectives: Map<string, DirectiveNode[]>;
deprecatedDirectives: Directive[];
userDefinedDirectivesOnTargetFields: Map<string, DirectiveNode[]> | undefined;
subgraph?: Subgraph;
} = {
relationshipAdapter,
composer: schemaComposer,
composeNode,
userDefinedFieldDirectives,
deprecatedDirectives,
userDefinedDirectivesOnTargetFields,
};

if (relationshipTarget instanceof UnionEntityAdapter) {
Expand Down Expand Up @@ -285,16 +290,23 @@ function createRelationshipFieldsForTarget({
composeNode,
userDefinedFieldDirectives,
deprecatedDirectives,
userDefinedDirectivesOnTargetFields,
subgraph, // only for concrete targets
}: {
relationshipAdapter: RelationshipAdapter | RelationshipDeclarationAdapter;
composer: SchemaComposer;
composeNode: ObjectTypeComposer | InterfaceTypeComposer;
userDefinedFieldDirectives: Map<string, DirectiveNode[]>;
userDefinedDirectivesOnTargetFields: Map<string, DirectiveNode[]> | undefined;
deprecatedDirectives: Directive[];
subgraph?: Subgraph;
}) {
withSourceWhereInputType({ relationshipAdapter, composer, deprecatedDirectives });
withSourceWhereInputType({
relationshipAdapter,
composer,
deprecatedDirectives,
userDefinedDirectivesOnTargetFields,
});

if (relationshipAdapter.target instanceof InterfaceEntityAdapter) {
withFieldInputType({ relationshipAdapter, composer, userDefinedFieldDirectives });
Expand Down
69 changes: 55 additions & 14 deletions packages/graphql/src/schema/generation/aggregate-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import type {
ObjectTypeComposerFieldConfigMapDefinition,
SchemaComposer,
} from "graphql-compose";
import { AGGREGATION_COMPARISON_OPERATORS } from "../../constants";
import { AGGREGATION_COMPARISON_OPERATORS, DEPRECATED } from "../../constants";
import type { AttributeAdapter } from "../../schema-model/attribute/model-adapters/AttributeAdapter";
import { ConcreteEntityAdapter } from "../../schema-model/entity/model-adapters/ConcreteEntityAdapter";
import type { InterfaceEntityAdapter } from "../../schema-model/entity/model-adapters/InterfaceEntityAdapter";
Expand Down Expand Up @@ -84,10 +84,12 @@ export 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,
}: {
relationshipAdapter: RelationshipAdapter | RelationshipDeclarationAdapter;
entityAdapter: ConcreteEntityAdapter;
composer: SchemaComposer;
userDefinedDirectivesOnTargetFields: Map<string, DirectiveNode[]> | undefined;
}): InputTypeComposer {
const aggregateInputTypeName = relationshipAdapter.operations.aggregateInputTypeName;
if (composer.has(aggregateInputTypeName)) {
Expand All @@ -113,6 +115,7 @@ export function withAggregateInputType({
relationshipAdapter,
entityAdapter,
composer,
userDefinedDirectivesOnTargetFields,
});
if (nodeWhereInputType) {
aggregateSelection.addFields({ node: nodeWhereInputType });
Expand All @@ -121,6 +124,7 @@ export function withAggregateInputType({
relationshipAdapter,
entityAdapter: relationshipAdapter,
composer,
userDefinedDirectivesOnTargetFields,
});
if (edgeWhereInputType) {
aggregateSelection.addFields({ edge: edgeWhereInputType });
Expand All @@ -132,10 +136,12 @@ function withAggregationWhereInputType({
relationshipAdapter,
entityAdapter,
composer,
userDefinedDirectivesOnTargetFields,
}: {
relationshipAdapter: RelationshipAdapter | RelationshipDeclarationAdapter;
entityAdapter: ConcreteEntityAdapter | RelationshipAdapter | RelationshipDeclarationAdapter;
composer: SchemaComposer;
userDefinedDirectivesOnTargetFields: Map<string, DirectiveNode[]> | undefined;
}): InputTypeComposer | undefined {
const aggregationInputName =
entityAdapter instanceof ConcreteEntityAdapter
Expand All @@ -160,20 +166,31 @@ function withAggregationWhereInputType({
OR: aggregationInput.NonNull.List,
NOT: aggregationInput,
});
aggregationInput.addFields(makeAggregationFields(aggregationFields));
aggregationInput.addFields(makeAggregationFields(aggregationFields, userDefinedDirectivesOnTargetFields));
return aggregationInput;
}

function makeAggregationFields(attributes: AttributeAdapter[]): InputTypeComposerFieldConfigMapDefinition {
function makeAggregationFields(
attributes: AttributeAdapter[],
userDefinedDirectivesOnTargetFields: Map<string, DirectiveNode[]> | undefined
): InputTypeComposerFieldConfigMapDefinition {
const aggregationFields = attributes
.map((attribute) => getAggregationFieldsByType(attribute))
.map((attribute) =>
getAggregationFieldsByType(attribute, userDefinedDirectivesOnTargetFields?.get(attribute.name))
)
.reduce((acc, el) => ({ ...acc, ...el }), {});
return aggregationFields;
}

// TODO: refactor this by introducing specialized Adapters
function getAggregationFieldsByType(attribute: AttributeAdapter): InputTypeComposerFieldConfigMapDefinition {
function getAggregationFieldsByType(
attribute: AttributeAdapter,
directivesOnField: DirectiveNode[] | undefined
): InputTypeComposerFieldConfigMapDefinition {
const fields: InputTypeComposerFieldConfigMapDefinition = {};
const deprecatedDirectives = graphqlDirectivesToCompose(
(directivesOnField || []).filter((d) => d.name.value === DEPRECATED)
);
if (attribute.typeHelper.isID()) {
fields[`${attribute.name}_EQUAL`] = {
type: GraphQLID,
Expand All @@ -199,9 +216,18 @@ function getAggregationFieldsByType(attribute: AttributeAdapter): InputTypeCompo
type: GraphQLInt,
directives: [DEPRECATE_IMPLICIT_LENGTH_AGGREGATION_FILTERS],
};
fields[`${attribute.name}_AVERAGE_LENGTH_${operator}`] = GraphQLFloat;
fields[`${attribute.name}_LONGEST_LENGTH_${operator}`] = GraphQLInt;
fields[`${attribute.name}_SHORTEST_LENGTH_${operator}`] = GraphQLInt;
fields[`${attribute.name}_AVERAGE_LENGTH_${operator}`] = {
type: GraphQLFloat,
directives: deprecatedDirectives,
};
fields[`${attribute.name}_LONGEST_LENGTH_${operator}`] = {
type: GraphQLInt,
directives: deprecatedDirectives,
};
fields[`${attribute.name}_SHORTEST_LENGTH_${operator}`] = {
type: GraphQLInt,
directives: deprecatedDirectives,
};
}
return fields;
}
Expand All @@ -215,17 +241,26 @@ function getAggregationFieldsByType(attribute: AttributeAdapter): InputTypeCompo
type: attribute.getTypeName(),
directives: [DEPRECATE_INVALID_AGGREGATION_FILTERS],
};
fields[`${attribute.name}_MIN_${operator}`] = attribute.getTypeName();
fields[`${attribute.name}_MAX_${operator}`] = attribute.getTypeName();
fields[`${attribute.name}_MIN_${operator}`] = {
type: attribute.getTypeName(),
directives: deprecatedDirectives,
};
fields[`${attribute.name}_MAX_${operator}`] = {
type: attribute.getTypeName(),
directives: deprecatedDirectives,
};
if (attribute.getTypeName() !== "Duration") {
fields[`${attribute.name}_SUM_${operator}`] = attribute.getTypeName();
fields[`${attribute.name}_SUM_${operator}`] = {
type: attribute.getTypeName(),
directives: deprecatedDirectives,
};
}
const averageType = attribute.typeHelper.isBigInt()
? "BigInt"
: attribute.typeHelper.isDuration()
? "Duration"
: GraphQLFloat;
fields[`${attribute.name}_AVERAGE_${operator}`] = averageType;
fields[`${attribute.name}_AVERAGE_${operator}`] = { type: averageType, directives: deprecatedDirectives };
}
return fields;
}
Expand All @@ -234,8 +269,14 @@ function getAggregationFieldsByType(attribute: AttributeAdapter): InputTypeCompo
type: attribute.getTypeName(),
directives: [DEPRECATE_INVALID_AGGREGATION_FILTERS],
};
fields[`${attribute.name}_MIN_${operator}`] = attribute.getTypeName();
fields[`${attribute.name}_MAX_${operator}`] = attribute.getTypeName();
fields[`${attribute.name}_MIN_${operator}`] = {
type: attribute.getTypeName(),
directives: deprecatedDirectives,
};
fields[`${attribute.name}_MAX_${operator}`] = {
type: attribute.getTypeName(),
directives: deprecatedDirectives,
};
}
return fields;
}
3 changes: 3 additions & 0 deletions packages/graphql/src/schema/generation/where-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,12 @@ export function withSourceWhereInputType({
relationshipAdapter,
composer,
deprecatedDirectives,
userDefinedDirectivesOnTargetFields,
}: {
relationshipAdapter: RelationshipAdapter | RelationshipDeclarationAdapter;
composer: SchemaComposer;
deprecatedDirectives: Directive[];
userDefinedDirectivesOnTargetFields: Map<string, DirectiveNode[]> | undefined;
}): InputTypeComposer | undefined {
const relationshipTarget = relationshipAdapter.target;
const relationshipSource = relationshipAdapter.source;
Expand All @@ -183,6 +185,7 @@ export function withSourceWhereInputType({
relationshipAdapter,
entityAdapter: relationshipTarget,
composer: composer,
userDefinedDirectivesOnTargetFields,
});

if (relationshipAdapter.isFilterableByAggregate()) {
Expand Down
31 changes: 16 additions & 15 deletions packages/graphql/tests/schema/directive-preserve.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4036,6 +4036,7 @@ describe("Directive-preserve", () => {
`);
});

// https://github.com/neo4j/graphql/issues/2676
test("Directives on unions preserved", async () => {
const typeDefs = gql`
union Content = Blog | Post
Expand Down Expand Up @@ -4183,11 +4184,11 @@ describe("Directive-preserve", () => {
content_AVERAGE_EQUAL: Float @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_AVERAGE_GT: Float @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_AVERAGE_GTE: Float @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_AVERAGE_LENGTH_EQUAL: Float
content_AVERAGE_LENGTH_GT: Float
content_AVERAGE_LENGTH_GTE: Float
content_AVERAGE_LENGTH_LT: Float
content_AVERAGE_LENGTH_LTE: Float
content_AVERAGE_LENGTH_EQUAL: Float @deprecated(reason: \\"Do not use post.content\\")
content_AVERAGE_LENGTH_GT: Float @deprecated(reason: \\"Do not use post.content\\")
content_AVERAGE_LENGTH_GTE: Float @deprecated(reason: \\"Do not use post.content\\")
content_AVERAGE_LENGTH_LT: Float @deprecated(reason: \\"Do not use post.content\\")
content_AVERAGE_LENGTH_LTE: Float @deprecated(reason: \\"Do not use post.content\\")
content_AVERAGE_LT: Float @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_AVERAGE_LTE: Float @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_EQUAL: String @deprecated(reason: \\"Aggregation filters that are not relying on an aggregating function will be deprecated.\\")
Expand All @@ -4196,23 +4197,23 @@ describe("Directive-preserve", () => {
content_LONGEST_EQUAL: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_LONGEST_GT: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_LONGEST_GTE: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_LONGEST_LENGTH_EQUAL: Int
content_LONGEST_LENGTH_GT: Int
content_LONGEST_LENGTH_GTE: Int
content_LONGEST_LENGTH_LT: Int
content_LONGEST_LENGTH_LTE: Int
content_LONGEST_LENGTH_EQUAL: Int @deprecated(reason: \\"Do not use post.content\\")
content_LONGEST_LENGTH_GT: Int @deprecated(reason: \\"Do not use post.content\\")
content_LONGEST_LENGTH_GTE: Int @deprecated(reason: \\"Do not use post.content\\")
content_LONGEST_LENGTH_LT: Int @deprecated(reason: \\"Do not use post.content\\")
content_LONGEST_LENGTH_LTE: Int @deprecated(reason: \\"Do not use post.content\\")
content_LONGEST_LT: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_LONGEST_LTE: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_LT: Int @deprecated(reason: \\"Aggregation filters that are not relying on an aggregating function will be deprecated.\\")
content_LTE: Int @deprecated(reason: \\"Aggregation filters that are not relying on an aggregating function will be deprecated.\\")
content_SHORTEST_EQUAL: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_SHORTEST_GT: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_SHORTEST_GTE: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_SHORTEST_LENGTH_EQUAL: Int
content_SHORTEST_LENGTH_GT: Int
content_SHORTEST_LENGTH_GTE: Int
content_SHORTEST_LENGTH_LT: Int
content_SHORTEST_LENGTH_LTE: Int
content_SHORTEST_LENGTH_EQUAL: Int @deprecated(reason: \\"Do not use post.content\\")
content_SHORTEST_LENGTH_GT: Int @deprecated(reason: \\"Do not use post.content\\")
content_SHORTEST_LENGTH_GTE: Int @deprecated(reason: \\"Do not use post.content\\")
content_SHORTEST_LENGTH_LT: Int @deprecated(reason: \\"Do not use post.content\\")
content_SHORTEST_LENGTH_LTE: Int @deprecated(reason: \\"Do not use post.content\\")
content_SHORTEST_LT: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
content_SHORTEST_LTE: Int @deprecated(reason: \\"Please use the explicit _LENGTH version for string aggregation.\\")
}
Expand Down
Loading

0 comments on commit 19c2a7a

Please sign in to comment.