From 723ead671b16b1217c6e3b9b270b63932f822c35 Mon Sep 17 00:00:00 2001 From: Pontus Melke Date: Thu, 19 Oct 2017 16:15:27 +0200 Subject: [PATCH] Support for adding two UTF8StringValue --- .../runtime/commands/expressions/Add.scala | 5 +- .../v3_4/runtime/commands/AddTest.scala | 28 ++++++++-- .../neo4j/values/storable/StringValue.java | 5 ++ .../org/neo4j/values/storable/Values.java | 8 +-- .../org/neo4j/values/utils/UTF8Utils.java | 52 +++++++++++++++++++ 5 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 community/values/src/main/java/org/neo4j/values/utils/UTF8Utils.java diff --git a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/expressions/Add.scala b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/expressions/Add.scala index 75e77af13e53..7b9b33b06fc5 100644 --- a/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/expressions/Add.scala +++ b/community/cypher/cypher/src/main/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/expressions/Add.scala @@ -19,13 +19,15 @@ */ package org.neo4j.cypher.internal.compatibility.v3_4.runtime.commands.expressions -import org.neo4j.cypher.internal.util.v3_4.CypherTypeException import org.neo4j.cypher.internal.compatibility.v3_4.runtime.ExecutionContext import org.neo4j.cypher.internal.compatibility.v3_4.runtime.helpers.{IsList, TypeSafeMathSupport} import org.neo4j.cypher.internal.compatibility.v3_4.runtime.pipes.QueryState +import org.neo4j.cypher.internal.util.v3_4.CypherTypeException import org.neo4j.cypher.internal.util.v3_4.symbols._ import org.neo4j.values._ +import org.neo4j.values.storable.StringValue.UTF8StringValue import org.neo4j.values.storable._ +import org.neo4j.values.utils.UTF8Utils import org.neo4j.values.virtual.VirtualValues case class Add(a: Expression, b: Expression) extends Expression with TypeSafeMathSupport { @@ -37,6 +39,7 @@ case class Add(a: Expression, b: Expression) extends Expression with TypeSafeMat case (x, y) if x == Values.NO_VALUE || y == Values.NO_VALUE => Values.NO_VALUE case (x: IntegralValue, y: IntegralValue) => Values.longValue(StrictMath.addExact(x.longValue(),y.longValue())) case (x: NumberValue, y: NumberValue) => Values.doubleValue(x.doubleValue() + y.doubleValue()) + case (x: UTF8StringValue, y: UTF8StringValue) => UTF8Utils.add(x, y) case (x: TextValue, y: TextValue) => Values.stringValue(x.stringValue() + y.stringValue()) case (IsList(x), IsList(y)) => VirtualValues.concat(x, y) case (IsList(x), y) => VirtualValues.appendToList(x, y) diff --git a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/AddTest.scala b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/AddTest.scala index 8604ebc7f00e..85ef0ca121c3 100644 --- a/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/AddTest.scala +++ b/community/cypher/cypher/src/test/scala/org/neo4j/cypher/internal/compatibility/v3_4/runtime/commands/AddTest.scala @@ -19,13 +19,18 @@ */ package org.neo4j.cypher.internal.compatibility.v3_4.runtime.commands -import org.neo4j.cypher.internal.util.v3_4.CypherTypeException +import java.nio.charset.StandardCharsets + import org.neo4j.cypher.internal.compatibility.v3_4.runtime.ExecutionContext -import org.neo4j.cypher.internal.compatibility.v3_4.runtime.commands.expressions.{Add, Literal} +import org.neo4j.cypher.internal.compatibility.v3_4.runtime.commands.expressions.{Add, Literal, ParameterExpression} import org.neo4j.cypher.internal.compiler.v3_4._ +import org.neo4j.cypher.internal.util.v3_4.CypherTypeException import org.neo4j.cypher.internal.util.v3_4.test_helpers.CypherFunSuite +import org.neo4j.values.AnyValue +import org.neo4j.values.storable.StringValue.UTF8StringValue import org.neo4j.values.storable.Values -import org.neo4j.values.storable.Values.{longValue, stringValue} +import org.neo4j.values.storable.Values.{longValue, stringValue, utf8Value} +import org.neo4j.values.virtual.VirtualValues class AddTest extends CypherFunSuite { @@ -64,4 +69,21 @@ class AddTest extends CypherFunSuite { val expr = Add(Literal("1"), Literal(true)) intercept[CypherTypeException](expr(m, s)) } + + test("UTF8 value addition") { + import scala.collection.JavaConverters._ + // Given + val hello = "hello".getBytes(StandardCharsets.UTF_8) + val world = "world".getBytes(StandardCharsets.UTF_8) + val params: Map[String, AnyValue] = Map("p1" -> utf8Value(hello), "p2" -> utf8Value(world)) + val state = QueryStateHelper.newWith(params = VirtualValues.map(params.asJava)) + + // When + val result = Add(ParameterExpression("p1"), ParameterExpression("p2"))(m,state) + + // Then + result shouldBe a[UTF8StringValue] + result should equal(utf8Value("helloworld".getBytes(StandardCharsets.UTF_8))) + result should equal(Values.stringValue("helloworld")) + } } diff --git a/community/values/src/main/java/org/neo4j/values/storable/StringValue.java b/community/values/src/main/java/org/neo4j/values/storable/StringValue.java index 8511c4ee58e2..36573409358b 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/StringValue.java +++ b/community/values/src/main/java/org/neo4j/values/storable/StringValue.java @@ -183,6 +183,11 @@ public int length() { return value().length(); } + + public byte[] bytes() + { + return bytes; + } } } diff --git a/community/values/src/main/java/org/neo4j/values/storable/Values.java b/community/values/src/main/java/org/neo4j/values/storable/Values.java index 1d4a84b38cce..d6a504ce6672 100644 --- a/community/values/src/main/java/org/neo4j/values/storable/Values.java +++ b/community/values/src/main/java/org/neo4j/values/storable/Values.java @@ -23,6 +23,8 @@ import java.util.Arrays; import java.util.Comparator; +import org.neo4j.values.storable.StringValue.UTF8StringValue; + import static java.lang.String.format; /** @@ -107,14 +109,14 @@ public static double coerceToDouble( Value value ) public static final Value NO_VALUE = NoValue.NO_VALUE; - public static TextValue utf8Value( byte[] bytes ) + public static UTF8StringValue utf8Value( byte[] bytes ) { return utf8Value( bytes, 0, bytes.length ); } - public static TextValue utf8Value( byte[] bytes, int offset, int length ) + public static UTF8StringValue utf8Value( byte[] bytes, int offset, int length ) { - return new StringValue.UTF8StringValue( bytes, offset, length ); + return new UTF8StringValue( bytes, offset, length ); } public static TextValue stringValue( String value ) diff --git a/community/values/src/main/java/org/neo4j/values/utils/UTF8Utils.java b/community/values/src/main/java/org/neo4j/values/utils/UTF8Utils.java new file mode 100644 index 000000000000..26e4a168233c --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/utils/UTF8Utils.java @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2002-2017 "Neo Technology," + * Network Engine for Objects in Lund AB [http://neotechnology.com] + * + * This file is part of Neo4j. + * + * Neo4j is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package org.neo4j.values.utils; + +import org.neo4j.values.storable.StringValue.UTF8StringValue; + +import static org.neo4j.values.storable.Values.utf8Value; + +/** + * Utility class for operations on utf-8 values. + */ +public final class UTF8Utils +{ + private UTF8Utils() + { + throw new UnsupportedOperationException( "Do not instantiate" ); + } + + /** + * Add two values. + * @param a value to add + * @param b value to add + * @return the value a + b + */ + public static UTF8StringValue add( UTF8StringValue a, UTF8StringValue b ) + { + byte[] bytesA = a.bytes(); + byte[] bytesB = b.bytes(); + + byte[] bytes = new byte[bytesA.length + bytesB.length]; + System.arraycopy( bytesA, 0, bytes, 0, bytesA.length ); + System.arraycopy( bytesB, 0, bytes, bytesA.length, bytesB.length ); + return utf8Value(bytes); + } +}