From e65c8e64fb56831f5bf52482f073f312350f7a2a Mon Sep 17 00:00:00 2001 From: Andreas Berger Date: Wed, 14 Apr 2021 11:53:26 +0200 Subject: [PATCH] Augment filter argument for nested fields If the field of GraphQL Type maps to an *..n relation (a list) and there is currently no `filter`-argument defined, we now generate it in the augmented schema. The logic for handling these nested filters is already implementd, so no further code-adjustments are required. resolves #129 --- .../kotlin/org/neo4j/graphql/SchemaBuilder.kt | 18 ++++++++++++------ .../src/test/resources/augmentation-tests.adoc | 6 +++--- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/core/src/main/kotlin/org/neo4j/graphql/SchemaBuilder.kt b/core/src/main/kotlin/org/neo4j/graphql/SchemaBuilder.kt index fdb6c57d..e99cd4fd 100644 --- a/core/src/main/kotlin/org/neo4j/graphql/SchemaBuilder.kt +++ b/core/src/main/kotlin/org/neo4j/graphql/SchemaBuilder.kt @@ -79,7 +79,7 @@ object SchemaBuilder { val handler = getHandler(config) - var targetSchema = augmentSchema(sourceSchema, handler) + var targetSchema = augmentSchema(sourceSchema, handler, config) targetSchema = addDataFetcher(targetSchema, dataFetchingInterceptor, handler) return targetSchema } @@ -128,7 +128,7 @@ object SchemaBuilder { return handler } - private fun augmentSchema(sourceSchema: GraphQLSchema, handler: List): GraphQLSchema { + private fun augmentSchema(sourceSchema: GraphQLSchema, handler: List, schemaConfig: SchemaConfig): GraphQLSchema { val types = sourceSchema.typeMap.toMutableMap() val env = BuildingEnv(types, sourceSchema) val queryTypeName = sourceSchema.queryTypeName() @@ -157,11 +157,11 @@ object SchemaBuilder { builder.clearFields().clearInterfaces() // to prevent duplicated types in schema sourceType.interfaces.forEach { builder.withInterface(GraphQLTypeReference(it.name)) } - sourceType.fieldDefinitions.forEach { f -> builder.field(enhanceRelations(f, env)) } + sourceType.fieldDefinitions.forEach { f -> builder.field(enhanceRelations(f, env, schemaConfig)) } } sourceType is GraphQLInterfaceType -> sourceType.transform { builder -> builder.clearFields() - sourceType.fieldDefinitions.forEach { f -> builder.field(enhanceRelations(f, env)) } + sourceType.fieldDefinitions.forEach { f -> builder.field(enhanceRelations(f, env, schemaConfig)) } } else -> sourceType } @@ -177,7 +177,7 @@ object SchemaBuilder { .build() } - private fun enhanceRelations(fd: GraphQLFieldDefinition, env: BuildingEnv): GraphQLFieldDefinition { + private fun enhanceRelations(fd: GraphQLFieldDefinition, env: BuildingEnv, schemaConfig: SchemaConfig): GraphQLFieldDefinition { return fd.transform { fieldBuilder -> // to prevent duplicated types in schema fieldBuilder.type(fd.type.ref() as GraphQLOutputType) @@ -192,7 +192,7 @@ object SchemaBuilder { if (fd.getArgument(ProjectionBase.OFFSET) == null) { fieldBuilder.argument { a -> a.name(ProjectionBase.OFFSET).type(Scalars.GraphQLInt) } } - if (fd.getArgument(ProjectionBase.ORDER_BY) == null && fd.type.isList()) { + if (fd.getArgument(ProjectionBase.ORDER_BY) == null) { (fd.type.inner() as? GraphQLFieldsContainer)?.let { fieldType -> env.addOrdering(fieldType)?.let { orderingTypeName -> val orderType = GraphQLList(GraphQLNonNull(GraphQLTypeReference(orderingTypeName))) @@ -200,6 +200,12 @@ object SchemaBuilder { } } } + if (schemaConfig.query.enabled && fd.getArgument(ProjectionBase.FILTER) == null) { + (fd.type.inner() as? GraphQLFieldsContainer)?.let { fieldType -> + val filterTypeName = env.addFilterType(fieldType) + fieldBuilder.argument(input(ProjectionBase.FILTER, GraphQLTypeReference(filterTypeName))) + } + } } } diff --git a/core/src/test/resources/augmentation-tests.adoc b/core/src/test/resources/augmentation-tests.adoc index fa51077a..5647cf73 100644 --- a/core/src/test/resources/augmentation-tests.adoc +++ b/core/src/test/resources/augmentation-tests.adoc @@ -396,7 +396,7 @@ schema { } interface HasMovies { - movies(first: Int, offset: Int, orderBy: [_MovieOrdering!]): [Movie] + movies(filter: _MovieFilter, first: Int, offset: Int, orderBy: [_MovieOrdering!]): [Movie] } type Knows0 @relation(direction : OUT, from : "source", name : "KNOWS", to : "knows") { @@ -454,7 +454,7 @@ type Person4 { type Person5 implements HasMovies { id: ID! - movies(first: Int, offset: Int, orderBy: [_MovieOrdering!]): [Movie] @relation(direction : OUT, from : "from", name : "LIKES", to : "to") + movies(filter: _MovieFilter, first: Int, offset: Int, orderBy: [_MovieOrdering!]): [Movie] @relation(direction : OUT, from : "from", name : "LIKES", to : "to") } type Publisher { @@ -472,7 +472,7 @@ type Query { person3(born: _Neo4jLocalTimeInput, filter: _Person3Filter, first: Int, name: String, offset: Int, orderBy: [_Person3Ordering!]): [Person3!]! person4(born: _Neo4jLocalDateTimeInput, filter: _Person4Filter, first: Int, id: ID, name: String, offset: Int, orderBy: [_Person4Ordering!]): [Person4!]! person5(filter: _Person5Filter, first: Int, id: ID, offset: Int, orderBy: [_Person5Ordering!]): [Person5!]! - PersonByLocation(first: Int, location: _Neo4jPointInput, offset: Int, orderBy: [_Person0Ordering!]): [Person0!]! + PersonByLocation(filter: _Person0Filter, first: Int, location: _Neo4jPointInput, offset: Int, orderBy: [_Person0Ordering!]): [Person0!]! publisher(filter: _PublisherFilter, first: Int, name: ID, offset: Int, orderBy: [_PublisherOrdering!]): [Publisher!]! }