Incorrect cypher for `_SOME` filters on relationships to unions
Type definitions
union Production = Movie | Series
type Movie {
title: String!
cost: Float
runtime: Int
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn")
}
type Series {
title: String!
episodes: Int
actors: [Actor!]! @relationship(type: "ACTED_IN", direction: IN, properties: "ActedIn")
}
type Actor {
name: String!
actedIn: [Production!]! @relationship(type: "ACTED_IN", direction: OUT, properties: "ActedIn")
}
type ActedIn @relationshipProperties {
screenTime: Int
}
Test data
CREATE(a:Actor{name:"Some Name"})
CREATE(:Movie{title:"The Office"})<-[:ACTED_IN]-(a)
CREATE(:Series{title:"The Office"})<-[:ACTED_IN]-(a)
Steps to reproduce
Run this query:
query actedInWhere {
actors(
where: {
actedIn_SOME: { Movie: { title_CONTAINS: "The Office" }, Series: { title_ENDS_WITH: "Office" } }
}
) {
name
}
}
What happened
The actor with name="Some Name" is returned.
Expected behaviour
The query suggests that "some" productions the actor has acted in should be both a Series and a Movie. This is not the case for this actor so it should not have been returned.
The following cypher is generated for this query:
MATCH (this:Actor)
WHERE (EXISTS {
MATCH (this)-[:ACTED_IN]->(this0:Movie)
WHERE this0.title CONTAINS $param0
} AND EXISTS {
MATCH (this)-[:ACTED_IN]->(this1:Series)
WHERE this1.title ENDS WITH $param1
})
RETURN this { .name } AS this
As you can see, the AND is applied outside the EXISTS.
However, I would have expected cypher along these lines (note this is sudo code - I think the labels syntax is probably wrong):
MATCH (this:Actor)
WHERE (EXISTS {
MATCH (this)-[:ACTED_IN]->(this0:Movie|Series)
WHERE (this0.title CONTAINS $param0 AND label(this0) = "Movie") AND (this0.title ENDS WITH $param1 AND label(this0) = "Series")
}
RETURN this { .name } AS this
Version
4.4.5
Database version
5.13
Relevant log output
No response
Many thanks for raising this bug report @Liam-Doodson. :bug: We will now attempt to reproduce the bug based on the steps you have provided.
Please ensure that you've provided the necessary information for a minimal reproduction, including but not limited to:
- Type definitions
- Resolvers
- Query and/or Mutation (or multiple) needed to reproduce
If you have a support agreement with Neo4j, please link this GitHub issue to a new or existing Zendesk ticket.
Thanks again! :pray:
We've been able to confirm this bug using the steps to reproduce that you provided - many thanks @Liam-Doodson! :pray: We will now prioritise the bug and address it appropriately.
Because unions are inherently separate entities (not supposed to be shared, that would be interfaces) a query asking an entity to be both items of an union would be incorrect
As such, filters on unions are treated as independent queries by convention
SOME { Movie... , Series...} is treated as SOME Movie AND SOME Series
This can be confusing, as the counterargument you mention is valid, but as this is the current convention, which makes the API more usable, for now I'd keep at as is and close this issue
Actually, after reviewing more carefully, @Liam-Doodson is right, these kind of operations can be confusing and the logic should be changed
I'm going to close this issue in favor of https://github.com/neo4j/graphql/issues/5940 as a duplicate