Skip to content

Commit

Permalink
Allow optimized FILTER_AS_MATCH strategy to be used with simple filte…
Browse files Browse the repository at this point in the history
…ring.

resolves #163
  • Loading branch information
Andy2003 committed Mar 3, 2021
1 parent 6ced50c commit 22f04d0
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class QueryHandler private constructor(

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

OptimizedFilterHandler(type).generateFilterQuery(variable, field, match, propertyContainer)
OptimizedFilterHandler(type).generateFilterQuery(variable, fieldDefinition, field, match, propertyContainer)

} else {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import graphql.language.Field
import graphql.language.NullValue
import graphql.language.ObjectValue
import graphql.language.Value
import graphql.schema.GraphQLFieldDefinition
import graphql.schema.GraphQLFieldsContainer
import org.neo4j.cypherdsl.core.*
import org.neo4j.cypherdsl.core.Cypher
import org.neo4j.cypherdsl.core.StatementBuilder.*
import org.neo4j.graphql.*
import org.neo4j.graphql.handler.projection.ProjectionBase
import org.neo4j.graphql.parser.ParsedQuery
import org.neo4j.graphql.parser.QueryParser
import org.neo4j.graphql.parser.QueryParser.parseFilter
import org.neo4j.graphql.parser.RelationPredicate

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

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

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

var withWithoutWhere: OngoingReading? = null
var ongoingReading: OngoingReading? = null

val filteredArguments = field.arguments.filterNot { setOf(FIRST, OFFSET, ORDER_BY, FILTER).contains(it.name) }
if (filteredArguments.isNotEmpty()) {
val parsedQuery = QueryParser.parseArguments(filteredArguments, fieldDefinition, type)
val condition = handleQuery(variable, "", rootNode, parsedQuery, type)
ongoingReading = readingWithoutWhere.where(condition)
}
for (argument in field.arguments) {
if (argument.name == FILTER) {
val parsedQuery = parseFilter(argument.value as ObjectValue, type)
withWithoutWhere = NestingLevelHandler(parsedQuery, false, rootNode, variable, readingWithoutWhere,
ongoingReading = NestingLevelHandler(parsedQuery, false, rootNode, variable, ongoingReading
?: readingWithoutWhere,
type, argument.value, linkedSetOf(rootNode.requiredSymbolicName))
.parseFilter()
}
}
return withWithoutWhere ?: readingWithoutWhere

return ongoingReading ?: readingWithoutWhere
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ open class ProjectionBase {
?: result
}

private fun handleQuery(
protected fun handleQuery(
variablePrefix: String,
variableSuffix: String,
propertyContainer: PropertyContainer,
Expand Down
59 changes: 56 additions & 3 deletions core/src/test/resources/issues/gh-163.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@
[source,graphql,schema=true]
----
type Person {
name: String
name: String
born: Int
actedIn: [Movie!]! @relation(name: "ACTED_IN", direction:OUT)
}
type Movie {
title: String!
}
----

== Issue
== Query without filter

.Query configuration
[source,json,query-config=true]
Expand Down Expand Up @@ -40,5 +46,52 @@ query {
.Cypher
[source,cypher]
----
MATCH (person: `Person`) where person.name = $personName RETURN person { .name } AS person
MATCH (person:Person)
WHERE person.name = $personName
RETURN person {
.name
} AS person
----

== Query with simple conditions and filter

.Query configuration
[source,json,query-config=true]
----
{ "optimizedQuery": ["FILTER_AS_MATCH"] }
----

.GraphQL-Query
[source,graphql]
----
query {
person(name:"test", filter: { born_gt: 1970, actedIn_none: { title: "Unforgiven" }}) {
name
}
}
----

.Cypher Params
[source,json]
----
{
"personActedInNoneTitle" : "Unforgiven",
"personBornGt" : 1970
}
----

.Cypher
[source,cypher]
----
MATCH (person:Person)
WHERE person.born > $personBornGt
WITH person
OPTIONAL MATCH (person)-[:ACTED_IN]->(personActedInNone:Movie)
WHERE personActedInNone.title = $personActedInNoneTitle
WITH person, count(DISTINCT personActedInNone) AS personActedInNoneCount
WHERE personActedInNoneCount = 0
WITH DISTINCT person
RETURN person {
.name
} AS person
----

0 comments on commit 22f04d0

Please sign in to comment.