From ba1bdc7b934c506aaf0a9268336bc05d51b5e818 Mon Sep 17 00:00:00 2001 From: Dwitry Date: Tue, 28 Aug 2018 16:11:51 +0300 Subject: [PATCH] Custom functions cypherProperties and cypherSize fallback (#160) - cypherSize - treat input as collection if type information and extensions are not available - cypherProperties - treat input as element if type information and extensions are not available - +2 TCK on Native Signed-off-by: Dwitry dwitry@users.noreply.github.com --- .../ir/rewrite/CustomFunctionFallback.scala | 10 ++++++-- .../gremlin/translation/CypherAstTest.java | 4 +-- .../rewrite/CustomFunctionsFallbackTest.scala | 25 +++++++++++++++++++ .../ir/verify/NoCustomFunctionsTest.scala | 4 +-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/translation/src/main/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionFallback.scala b/translation/src/main/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionFallback.scala index c0f97452..a644aed2 100644 --- a/translation/src/main/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionFallback.scala +++ b/translation/src/main/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionFallback.scala @@ -15,12 +15,12 @@ */ package org.opencypher.gremlin.translation.ir.rewrite -import org.apache.tinkerpop.gremlin.structure.Column.values +import org.apache.tinkerpop.gremlin.process.traversal.Scope.local import org.opencypher.gremlin.translation.Tokens.NULL import org.opencypher.gremlin.translation.exception.CypherExceptions import org.opencypher.gremlin.translation.ir.TraversalHelper._ import org.opencypher.gremlin.translation.ir.model._ -import org.opencypher.gremlin.traversal.CustomFunction.{cypherException, cypherPlus} +import org.opencypher.gremlin.traversal.CustomFunction.{cypherException, cypherPlus, cypherProperties, cypherSize} /** * Replaces Custom Functions with "The Best We Could Do" Gremlin native alternatives @@ -37,6 +37,12 @@ object CustomFunctionFallback extends GremlinRewriter { case SelectC(values) :: MapF(function) :: rest if function.getName == cypherPlus().getName => SelectC(values) :: Local(Unfold :: ChooseP(Neq(NULL), Sum :: Nil, Constant(NULL) :: Nil) :: Nil) :: rest + + case MapF(function) :: rest if function.getName == cypherSize().getName => + CountS(local) :: rest + + case MapF(function) :: rest if function.getName == cypherProperties().getName => + Local(Properties() :: Group :: By(Key :: Nil, None) :: By(MapT(Value :: Nil) :: Nil, None) :: Nil) :: rest }))(steps) } } diff --git a/translation/src/test/java/org/opencypher/gremlin/translation/CypherAstTest.java b/translation/src/test/java/org/opencypher/gremlin/translation/CypherAstTest.java index b9a4c377..df6e7e45 100644 --- a/translation/src/test/java/org/opencypher/gremlin/translation/CypherAstTest.java +++ b/translation/src/test/java/org/opencypher/gremlin/translation/CypherAstTest.java @@ -196,11 +196,11 @@ public void noCypherExtensions() { "MATCH (n:N) " + "WITH n.p AS s " + "WHERE s STARTS WITH 'x' AND s ENDS WITH 'x' AND s CONTAINS 'x' " + - "RETURN size(s), toString(s)" + "RETURN toString(s)" ); Translator translator = Translator.builder().gremlinGroovy().build(); assertThatThrownBy(() -> ast.buildTranslation(translator)) - .hasMessageContaining("cypherContains, cypherEndsWith, cypherSize, cypherStarsWith, cypherToString"); + .hasMessageContaining("cypherContains, cypherEndsWith, cypherStarsWith, cypherToString"); } } diff --git a/translation/src/test/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionsFallbackTest.scala b/translation/src/test/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionsFallbackTest.scala index b4221a27..dee2b718 100644 --- a/translation/src/test/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionsFallbackTest.scala +++ b/translation/src/test/scala/org/opencypher/gremlin/translation/ir/rewrite/CustomFunctionsFallbackTest.scala @@ -15,6 +15,7 @@ */ package org.opencypher.gremlin.translation.ir.rewrite +import org.apache.tinkerpop.gremlin.process.traversal.Scope import org.apache.tinkerpop.gremlin.structure.Column import org.junit.Test import org.opencypher.gremlin.translation.CypherAst.parse @@ -61,4 +62,28 @@ class CustomFunctionsFallbackTest { .local(__.unfold().choose(P.neq(Tokens.NULL), __.sum(), __.start().constant(Tokens.NULL)))) } + @Test + def cypherSizeFallback(): Unit = { + assertThat(parse("RETURN size($noType) AS a")) + .withFlavor(flavor) + .rewritingWith(CustomFunctionFallback) + .removes(__.map(CustomFunction.cypherSize())) + .adds(__.count(Scope.local)) + } + + @Test + def cypherPropertiesFallback(): Unit = { + assertThat(parse("RETURN properties($noType) AS a")) + .withFlavor(flavor) + .rewritingWith(CustomFunctionFallback) + .removes(__.map(CustomFunction.cypherProperties())) + .adds( + __.local( + __.properties() + .group() + .by(__.key()) + .by(__.map(__.value())) + )) + } + } diff --git a/translation/src/test/scala/org/opencypher/gremlin/translation/ir/verify/NoCustomFunctionsTest.scala b/translation/src/test/scala/org/opencypher/gremlin/translation/ir/verify/NoCustomFunctionsTest.scala index 2ddfeda4..ca9bb11d 100644 --- a/translation/src/test/scala/org/opencypher/gremlin/translation/ir/verify/NoCustomFunctionsTest.scala +++ b/translation/src/test/scala/org/opencypher/gremlin/translation/ir/verify/NoCustomFunctionsTest.scala @@ -35,11 +35,11 @@ class NoCustomFunctionsTest { |MATCH (n:N) |WITH n.p AS s |WHERE s STARTS WITH 'x' AND s ENDS WITH 'x' AND s CONTAINS 'x' - |RETURN size(s), toString(s) + |RETURN toString(s) """.stripMargin) val translator = Translator.builder.gremlinGroovy.build(flavor) assertThatThrownBy(() => ast.buildTranslation(translator)) - .hasMessageContaining("cypherContains, cypherEndsWith, cypherSize, cypherStarsWith, cypherToString") + .hasMessageContaining("cypherContains, cypherEndsWith, cypherStarsWith, cypherToString") } }