Skip to content

Commit ffc8298

Browse files
committed
Allow optimized FILTER_AS_MATCH strategy to be used with simple filtering.
resolves #163
1 parent a289935 commit ffc8298

File tree

4 files changed

+72
-9
lines changed

4 files changed

+72
-9
lines changed

core/src/main/kotlin/org/neo4j/graphql/handler/QueryHandler.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class QueryHandler private constructor(
8686

8787
val ongoingReading = if ((env.getContext() as? QueryContext)?.optimizedQuery?.contains(QueryContext.OptimizationStrategy.FILTER_AS_MATCH) == true) {
8888

89-
OptimizedFilterHandler(type).generateFilterQuery(variable, field, match, propertyContainer)
89+
OptimizedFilterHandler(type).generateFilterQuery(variable, fieldDefinition, field, match, propertyContainer)
9090

9191
} else {
9292

core/src/main/kotlin/org/neo4j/graphql/handler/filter/OptimizedFilterHandler.kt

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ import graphql.language.Field
44
import graphql.language.NullValue
55
import graphql.language.ObjectValue
66
import graphql.language.Value
7+
import graphql.schema.GraphQLFieldDefinition
78
import graphql.schema.GraphQLFieldsContainer
89
import org.neo4j.cypherdsl.core.*
910
import org.neo4j.cypherdsl.core.Cypher
1011
import org.neo4j.cypherdsl.core.StatementBuilder.*
1112
import org.neo4j.graphql.*
1213
import org.neo4j.graphql.handler.projection.ProjectionBase
1314
import org.neo4j.graphql.parser.ParsedQuery
15+
import org.neo4j.graphql.parser.QueryParser
1416
import org.neo4j.graphql.parser.QueryParser.parseFilter
1517
import org.neo4j.graphql.parser.RelationPredicate
1618

@@ -24,22 +26,30 @@ typealias ConditionBuilder = (ExposesWith) -> OrderableOngoingReadingAndWithWith
2426

2527
class OptimizedFilterHandler(val type: GraphQLFieldsContainer) : ProjectionBase() {
2628

27-
fun generateFilterQuery(variable: String, field: Field, readingWithoutWhere: OngoingReadingWithoutWhere, rootNode: PropertyContainer): OngoingReading {
29+
fun generateFilterQuery(variable: String, fieldDefinition: GraphQLFieldDefinition, field: Field, readingWithoutWhere: OngoingReadingWithoutWhere, rootNode: PropertyContainer): OngoingReading {
2830
if (type.isRelationType()) {
2931
throw OptimizedQueryException("Optimization for relationship entity type is not implemented. Please provide a test case to help adding further cases.")
3032
}
3133

32-
var withWithoutWhere: OngoingReading? = null
34+
var ongoingReading: OngoingReading? = null
3335

36+
val filteredArguments = field.arguments.filterNot { setOf(FIRST, OFFSET, ORDER_BY, FILTER).contains(it.name) }
37+
if (filteredArguments.isNotEmpty()) {
38+
val parsedQuery = QueryParser.parseArguments(filteredArguments, fieldDefinition, type)
39+
val condition = handleQuery(variable, "", rootNode, parsedQuery, type)
40+
ongoingReading = readingWithoutWhere.where(condition)
41+
}
3442
for (argument in field.arguments) {
3543
if (argument.name == FILTER) {
3644
val parsedQuery = parseFilter(argument.value as ObjectValue, type)
37-
withWithoutWhere = NestingLevelHandler(parsedQuery, false, rootNode, variable, readingWithoutWhere,
45+
ongoingReading = NestingLevelHandler(parsedQuery, false, rootNode, variable, ongoingReading
46+
?: readingWithoutWhere,
3847
type, argument.value, linkedSetOf(rootNode.requiredSymbolicName))
3948
.parseFilter()
4049
}
4150
}
42-
return withWithoutWhere ?: readingWithoutWhere
51+
52+
return ongoingReading ?: readingWithoutWhere
4353
}
4454

4555
/**

core/src/main/kotlin/org/neo4j/graphql/handler/projection/ProjectionBase.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ open class ProjectionBase {
8888
?: result
8989
}
9090

91-
private fun handleQuery(
91+
protected fun handleQuery(
9292
variablePrefix: String,
9393
variableSuffix: String,
9494
propertyContainer: PropertyContainer,

core/src/test/resources/issues/gh-163.adoc

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,17 @@
77
[source,graphql,schema=true]
88
----
99
type Person {
10-
name: String
10+
name: String
11+
born: Int
12+
actedIn: [Movie!]! @relation(name: "ACTED_IN", direction:OUT)
13+
}
14+
15+
type Movie {
16+
title: String!
1117
}
1218
----
1319

14-
== Issue
20+
== Query without filter
1521

1622
.Query configuration
1723
[source,json,query-config=true]
@@ -40,5 +46,52 @@ query {
4046
.Cypher
4147
[source,cypher]
4248
----
43-
MATCH (person: `Person`) where person.name = $personName RETURN person { .name } AS person
49+
MATCH (person:Person)
50+
WHERE person.name = $personName
51+
RETURN person {
52+
.name
53+
} AS person
54+
----
55+
56+
== Query with simple conditions and filter
57+
58+
.Query configuration
59+
[source,json,query-config=true]
60+
----
61+
{ "optimizedQuery": ["FILTER_AS_MATCH"] }
62+
----
63+
64+
.GraphQL-Query
65+
[source,graphql]
66+
----
67+
query {
68+
person(name:"test", filter: { born_gt: 1970, actedIn_none: { title: "Unforgiven" }}) {
69+
name
70+
}
71+
}
72+
----
73+
74+
.Cypher Params
75+
[source,json]
76+
----
77+
{
78+
"personActedInNoneTitle" : "Unforgiven",
79+
"personBornGt" : 1970
80+
}
81+
----
82+
83+
.Cypher
84+
[source,cypher]
85+
----
86+
MATCH (person:Person)
87+
WHERE person.born > $personBornGt
88+
WITH person
89+
OPTIONAL MATCH (person)-[:ACTED_IN]->(personActedInNone:Movie)
90+
WHERE personActedInNone.title = $personActedInNoneTitle
91+
WITH person, count(DISTINCT personActedInNone) AS personActedInNoneCount
92+
WHERE personActedInNoneCount = 0
93+
WITH DISTINCT person
94+
RETURN person {
95+
.name
96+
} AS person
4497
----

0 commit comments

Comments
 (0)