thatdot / quine

Quine • a streaming graph • https://quine.io • Discord: https://discord.gg/GMhd8TE4MR
https://quine.io
Other
295 stars 39 forks source link

UNWIND regression in 1.2 release #9

Closed jiminoc closed 1 year ago

jiminoc commented 2 years ago

When trying to test the 1.2 JAR I was getting failures in previously working standing queries with UNWIND where I'm working with an expected map. When retested against the 1.1 open source JAR the queries were successfully accepted and working.

ERROR MATCH (n) WHERE id(n) = $sqMatch.data.id WITH n.tags AS tags, n UNWIND keys(tags) AS key MATCH (m) WHERE id(m) = idFrom(n.cid, 'tag', key, n.tags[key]) CREATE (n)-[:tag]->(m) SET m.key = key, m.value = n.tags[key], m:tag NOT Registered OK for tagquery on http://10.10.10.10:8080: ["Type mismatch: expected Map, Node or Relationship but was Boolean, Float, Integer, Number, Point, String, Duration, Date, Time, LocalTime, LocalDateTime, DateTime, List<Boolean>, List<Float>, List<Integer>, List<Number>, List<Point>, List<String>, List<Duration>, List<Date>, List<Time>, List<LocalTime>, List<LocalDateTime> or List<DateTime>"]

Queries standing_match_tags = """MATCH (n) WHERE exists(n.tags) RETURN id(n)""" standing_action_tags = ( """MATCH (n) WHERE id(n) = $sqMatch.data.id """ """WITH n.tags AS tags, n """ """UNWIND keys(tags) AS key """ """MATCH (m) WHERE id(m) = idFrom(n.foobar, 'tag', key, n.tags[key]) """ """CREATE (n)-[:tag]->(m) """ """SET m.key = key, m.value = n.tags[key], m:tag""" )

emanb29 commented 2 years ago

Reproduction using only ad-hoc queries:

Query 1:

MATCH (n) WHERE id(n) = idFrom(0) SET n = {
  tags: {
    foo: "bar",
    fizz: "buzz"
  }
}

Query 2:

MATCH (n) WHERE id(n) = idFrom(0)
UNWIND keys(n.tags) AS key RETURN key

On 1.1.0 this returns 2 rows for "key": "foo" and "fizz". On 1.2.0, it produces a type mismatch error like the one provided in the original ticket.

This seems tied to using a property specifically. Notably, Query 2 fails to compile in isolation (ie on an empty Quine instance) -- this implies the problem is in the cypher compiler

Additionally, both of the following work on 1.1.0 and 1.2.0:

UNWIND keys() of a map literal: UNWIND keys({foo: "bar", fizz: "buzz"}) AS key RETURN key UNWIND keys() of a node variable: MATCH (n) WHERE id(n) = idFrom(0) UNWIND keys(n) AS key RETURN key

emanb29 commented 2 years ago

As a temporary workaround, this also works on 1.2.0: instead of passing n.tags to keys(), pass properties(n)["tags"]

MATCH (n) WHERE id(n) = $sqMatch.data.id
UNWIND keys(properties(n)["tags"]) AS key
MATCH (m) WHERE id(m) = idFrom(n.cid, 'tag', key, n.tags[key])
CREATE (n)-[:tag]->(m)
SET m.key = key, m.value = n.tags[key], m:tag
emanb29 commented 2 years ago

The root cause seems to be upstream of Quine, in openCypher: Other cypher interpreters using openCypher have the same problem:

image

We may be able to patch around this issue in our compilation pipeline with a bit more custom logic during function resolution; looking into that possibility now.

emanb29 commented 1 year ago

A more thorough workaround has been introduced in https://github.com/thatdot/quine/commit/edecbcccd55206c9f028f1d68dc784e6ac38baff and is scheduled to be included in the next release. A new set of casting cypher functions may be used to hint to the compiler what the expected type of a value is: Here's an example of usage https://github.com/thatdot/quine/blob/edecbcccd55206c9f028f1d68dc784e6ac38baff/quine-cypher/src/test/scala/com/thatdot/quine/compiler/cypher/CypherComplete.scala#L741

Closing this for now, as while we'd like to implement a more thorough solution to this issue, we believe this workaround will be an effective mitigation in the near term