cypher-for-gremlin icon indicating copy to clipboard operation
cypher-for-gremlin copied to clipboard

OPTIONAL match should generate an `optional()` call not `choose()`

Open ExtReMLapin opened this issue 9 months ago • 1 comments

Hello 👋🏻 ,

Right now, the query :

MATCH (doc:DOCUMENT)
OPTIONAL MATCH (ner:NER {subtype: 'LOCATION'})
RETURN distinct(ID(doc))

Is currently translated to

g.V().as('doc').hasLabel('DOCUMENT').choose(__.V().hasLabel('NER').has('subtype', eq('LOCATION')), __.V().hasLabel('NER').has('subtype', eq('LOCATION')), __.constant('  cypher.null')).select('doc').project('(ID(doc))').by(__.choose(neq('  cypher.null'), __.id())).dedup()

but it should be translated to

g.V().hasLabel('DOCUMENT').as('doc')
    .optional(__.V().hasLabel('NER').has('subtype', 'LOCATION'))
    .select('doc')
    .id()
    .dedup()

I literally CANNOT get the project to build and use it correctly in ArcadeDB, issue with missing symbols.

Some tests are failing, which is expected considering some of they searches 'choose' inside it and others are failing like :

(Some of the failing tests)

matchAndReverseOptionalMatch

java.lang.AssertionError: [Extracted: a1.name, r.name, b2.name] 
Actual and expected should have same size but actual size was:
  <0>
while expected size was:
  <1>
Actual was:
  <[]>
Expected was:
  <[("A", "T", null)]>

    @Test
    @Category(SkipWithCosmosDB.Truncate4096.class)
    public void matchAndReverseOptionalMatch() throws Exception {
        submitAndGet("CREATE (:A {name: 'A'})-[:T {name: 'T'}]->(:B {name: 'B'})");
        List<Map<String, Object>> results = submitAndGet(
            "MATCH (a1)-[r]->() " +
                "WITH r, a1 " +
                "OPTIONAL MATCH (a1)<-[r]-(b2) " +
                "RETURN a1.name, r.name, b2.name"
        );

        assertThat(results)
            .extracting("a1.name", "r.name", "b2.name")
            .containsExactly(tuple("A", "T", null));
    }

optionalMatchOnEmptyGraph


java.lang.AssertionError: [Extracted: n] 
Actual and expected should have same size but actual size was:
  <0>
while expected size was:
  <1>
Actual was:
  <[]>
Expected was:
  <[null]>

    @Test
    public void optionalMatchOnEmptyGraph() throws Exception {
        List<Map<String, Object>> results = submitAndGet(
            "OPTIONAL MATCH (n) " +
                "RETURN n"
        );

        assertThat(results)
            .extracting("n")
            .containsExactly((Object) null);
    }

optionalStartEndNode

java.lang.AssertionError: [Extracted: a, b] 
Expecting:
  <[]>
to contain exactly in any order:
  <[(null, null)]>
but could not find the following elements:
  <[(null, null)]>

    @Test
    public void optionalStartEndNode() {
        List<Map<String, Object>> results = submitAndGet(
            "OPTIONAL MATCH ()-[r:notExisting]-()\n" +
                "RETURN startNode(r) as a, endNode(r) as b");

        assertThat(results)
            .extracting("a", "b")
            .containsExactlyInAnyOrder(tuple(null, null));
    }

This feature being broken sounds QUITE CRITICAL.

Opened issues on arcadedb using gremlin+cypher

https://github.com/ArcadeData/arcadedb/issues/1929

https://github.com/ArcadeData/arcadedb/issues/1948

ExtReMLapin avatar Mar 19 '25 09:03 ExtReMLapin

Thanks for opening this PR. Unfortunately, we do not maintain the cypher-to-gremlin transpiler anymore. However, it is under Apache License v2 license, so you may fork the repo and work with the fork as you see fit.

hvub avatar Mar 24 '25 16:03 hvub