From 22b7005802d56f1d62b86e2a49ad4144fe9f09d3 Mon Sep 17 00:00:00 2001 From: fickludd Date: Fri, 9 Jun 2017 13:31:51 +0200 Subject: [PATCH] First structure for virtual values + ListValue and MapValue --- .../neo4j/kernel/api/schema/IndexQuery.java | 8 +- .../{StorableValue.java => AnyValue.java} | 12 +- .../java/org/neo4j/values/AnyValueWriter.java | 61 ++++ .../java/org/neo4j/values/ArrayValue.java | 2 +- .../java/org/neo4j/values/ScalarValue.java | 2 +- .../src/main/java/org/neo4j/values/Value.java | 13 +- .../org/neo4j/values/ValueComparator.java | 12 +- .../java/org/neo4j/values/ValueTuple.java | 2 +- .../main/java/org/neo4j/values/Values.java | 8 +- .../java/org/neo4j/values/VirtualValue.java | 93 +----- .../neo4j/values/virtual/ArrayHelpers.java | 55 ++++ .../org/neo4j/values/virtual/ListValue.java | 86 ++++++ .../org/neo4j/values/virtual/MapValue.java | 105 +++++++ .../values/virtual/VirtualValueGroup.java | 34 +++ .../neo4j/values/virtual/VirtualValues.java | 45 +++ .../java/org/neo4j/values/AnyValuesTest.java | 57 ++++ .../org/neo4j/values/BufferValueWriter.java | 2 +- .../java/org/neo4j/values/MyVirtualValue.java | 19 +- .../org/neo4j/values/ValueComparisonTest.java | 4 +- .../java/org/neo4j/values/ValuesTest.java | 21 -- .../values/virtual/BufferAnyValueWriter.java | 284 ++++++++++++++++++ .../org/neo4j/values/virtual/ListTest.java | 117 ++++++++ .../org/neo4j/values/virtual/MapTest.java | 128 ++++++++ .../virtual/VirtualValueWriteToTest.java | 104 +++++++ 24 files changed, 1116 insertions(+), 158 deletions(-) rename community/values/src/main/java/org/neo4j/values/{StorableValue.java => AnyValue.java} (79%) create mode 100644 community/values/src/main/java/org/neo4j/values/AnyValueWriter.java create mode 100644 community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java create mode 100644 community/values/src/main/java/org/neo4j/values/virtual/ListValue.java create mode 100644 community/values/src/main/java/org/neo4j/values/virtual/MapValue.java create mode 100644 community/values/src/main/java/org/neo4j/values/virtual/VirtualValueGroup.java create mode 100644 community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java create mode 100644 community/values/src/test/java/org/neo4j/values/AnyValuesTest.java create mode 100644 community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java create mode 100644 community/values/src/test/java/org/neo4j/values/virtual/ListTest.java create mode 100644 community/values/src/test/java/org/neo4j/values/virtual/MapTest.java create mode 100644 community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java diff --git a/community/kernel/src/main/java/org/neo4j/kernel/api/schema/IndexQuery.java b/community/kernel/src/main/java/org/neo4j/kernel/api/schema/IndexQuery.java index 4351ae7ee8112..04e6dde5a6858 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/api/schema/IndexQuery.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/api/schema/IndexQuery.java @@ -273,7 +273,7 @@ public boolean test( Value value ) { if ( from != Values.NO_VALUE ) { - int compare = Values.VALUE_COMPARATOR.compare( value, from ); + int compare = Values.COMPARATOR.compare( value, from ); if ( compare < 0 || !fromInclusive && compare == 0 ) { return false; @@ -281,7 +281,7 @@ public boolean test( Value value ) } if ( to != Values.NO_VALUE ) { - int compare = Values.VALUE_COMPARATOR.compare( value, to ); + int compare = Values.COMPARATOR.compare( value, to ); if ( compare > 0 || !toInclusive && compare == 0 ) { return false; @@ -348,7 +348,7 @@ public boolean test( Value value ) } if ( from != Values.NO_VALUE ) { - int compare = Values.VALUE_COMPARATOR.compare( value, from ); + int compare = Values.COMPARATOR.compare( value, from ); if ( compare < 0 || !fromInclusive && compare == 0 ) { return false; @@ -356,7 +356,7 @@ public boolean test( Value value ) } if ( to != Values.NO_VALUE ) { - int compare = Values.VALUE_COMPARATOR.compare( value, to ); + int compare = Values.COMPARATOR.compare( value, to ); if ( compare > 0 || !toInclusive && compare == 0 ) { return false; diff --git a/community/values/src/main/java/org/neo4j/values/StorableValue.java b/community/values/src/main/java/org/neo4j/values/AnyValue.java similarity index 79% rename from community/values/src/main/java/org/neo4j/values/StorableValue.java rename to community/values/src/main/java/org/neo4j/values/AnyValue.java index f0b817173c5ed..9649fa3d8c839 100644 --- a/community/values/src/main/java/org/neo4j/values/StorableValue.java +++ b/community/values/src/main/java/org/neo4j/values/AnyValue.java @@ -19,9 +19,13 @@ */ package org.neo4j.values; -/** - * Value that can be stored as a node, relationship or graph property. - */ -abstract class StorableValue extends Value +public abstract class AnyValue { + @Override + public abstract boolean equals( Object other ); + + @Override + public abstract int hashCode(); + + public abstract void writeTo( AnyValueWriter writer ); } diff --git a/community/values/src/main/java/org/neo4j/values/AnyValueWriter.java b/community/values/src/main/java/org/neo4j/values/AnyValueWriter.java new file mode 100644 index 0000000000000..f9320eb1a4aad --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/AnyValueWriter.java @@ -0,0 +1,61 @@ +/* + * 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; + +/** + * Writer of any values. + */ +public interface AnyValueWriter extends ValueWriter +{ + + void beginNode( long nodeId ); + + void endNode(); + + void beginLabels( int numberOfLabels ); + + void writeLabel( int labelId ); + + void endLabels(); + + void beginProperties( int numberOfProperties ); + + void writePropertyKeyId( int propertyKeyId ); + + void endProperties(); + + void beginEdge( long edgeId ); + + void endEdge(); + + void beginMap( int size ); + + void writeKeyId( int keyId ); + + void endMap(); + + void beginList( int size ); + + void endList(); + + void beginPath( int length ); + + void endPath(); +} diff --git a/community/values/src/main/java/org/neo4j/values/ArrayValue.java b/community/values/src/main/java/org/neo4j/values/ArrayValue.java index e9cbfa7a61680..475b01d1797a1 100644 --- a/community/values/src/main/java/org/neo4j/values/ArrayValue.java +++ b/community/values/src/main/java/org/neo4j/values/ArrayValue.java @@ -22,7 +22,7 @@ /** * Array of one of the storable primitives */ -abstract class ArrayValue extends StorableValue +abstract class ArrayValue extends Value { abstract int length(); diff --git a/community/values/src/main/java/org/neo4j/values/ScalarValue.java b/community/values/src/main/java/org/neo4j/values/ScalarValue.java index 9cb7dfa0b9377..f1002707b1022 100644 --- a/community/values/src/main/java/org/neo4j/values/ScalarValue.java +++ b/community/values/src/main/java/org/neo4j/values/ScalarValue.java @@ -22,7 +22,7 @@ /** * Single instance of one of the storable primitives. */ -abstract class ScalarValue extends StorableValue +abstract class ScalarValue extends Value { @Override public boolean equals( byte[] x ) diff --git a/community/values/src/main/java/org/neo4j/values/Value.java b/community/values/src/main/java/org/neo4j/values/Value.java index 5d6c4661b4940..0634bcf0b4cff 100644 --- a/community/values/src/main/java/org/neo4j/values/Value.java +++ b/community/values/src/main/java/org/neo4j/values/Value.java @@ -19,14 +19,8 @@ */ package org.neo4j.values; -public abstract class Value +public abstract class Value extends AnyValue { - @Override - public abstract boolean equals( Object other ); - - @Override - public abstract int hashCode(); - public abstract boolean equals( Value other ); public abstract boolean equals( byte[] x ); @@ -53,6 +47,11 @@ public abstract class Value public abstract boolean equals( String[] x ); + public void writeTo( AnyValueWriter writer ) + { + writeTo( (ValueWriter)writer ); + } + public abstract void writeTo( ValueWriter writer ); /** diff --git a/community/values/src/main/java/org/neo4j/values/ValueComparator.java b/community/values/src/main/java/org/neo4j/values/ValueComparator.java index 27ad7601c5521..9821c67c03e99 100644 --- a/community/values/src/main/java/org/neo4j/values/ValueComparator.java +++ b/community/values/src/main/java/org/neo4j/values/ValueComparator.java @@ -29,14 +29,11 @@ public class ValueComparator implements Comparator { private final Comparator valueGroupComparator; - private final Comparator virtualValueComparator; ValueComparator( - Comparator valueGroupComparator, - Comparator virtualValueComparator ) + Comparator valueGroupComparator ) { this.valueGroupComparator = valueGroupComparator; - this.virtualValueComparator = virtualValueComparator; } @Override @@ -96,11 +93,10 @@ public int compare( Value v1, Value v2 ) case BOOLEAN_ARRAY: return ((BooleanArray) v1).compareTo( (BooleanArray) v2 ); - case VIRTUAL: - return virtualValueComparator.compare( (VirtualValue)v1, (VirtualValue)v2 ); - default: - throw new UnsupportedOperationException( format( "Unknown ValueGroup id '%s'", id1 ) ); + throw new UnsupportedOperationException( format( + "Cannot compare ValueGroup id '%s' using ValueComparator", id1 + ) ); } } return x; diff --git a/community/values/src/main/java/org/neo4j/values/ValueTuple.java b/community/values/src/main/java/org/neo4j/values/ValueTuple.java index e363b0dd5e52f..1ab1a922309ef 100644 --- a/community/values/src/main/java/org/neo4j/values/ValueTuple.java +++ b/community/values/src/main/java/org/neo4j/values/ValueTuple.java @@ -145,7 +145,7 @@ private static boolean noNulls( Object[] values ) int compare = 0; for ( int i = 0; i < left.values.length; i++ ) { - compare = Values.VALUE_COMPARATOR.compare( left.valueAt( i ), right.valueAt( i ) ); + compare = Values.COMPARATOR.compare( left.valueAt( i ), right.valueAt( i ) ); if ( compare != 0 ) { return compare; diff --git a/community/values/src/main/java/org/neo4j/values/Values.java b/community/values/src/main/java/org/neo4j/values/Values.java index dfd1126280f65..b8ed1fce9d5f6 100644 --- a/community/values/src/main/java/org/neo4j/values/Values.java +++ b/community/values/src/main/java/org/neo4j/values/Values.java @@ -51,13 +51,9 @@ private Values() /** * Default value comparator. Will correctly compare all storable values and order the value groups according the - * to comparability group. Virtual values are sorted in a random but deterministic fashion (by hashCode). + * to comparability group. */ - public static final ValueComparator VALUE_COMPARATOR = - new ValueComparator( - ValueGroup::compareTo, - Comparator.comparingInt( VirtualValue::hashCode ) - ); + public static final Comparator COMPARATOR = new ValueComparator( ValueGroup::compareTo ); public static boolean isNumberValue( Object value ) { diff --git a/community/values/src/main/java/org/neo4j/values/VirtualValue.java b/community/values/src/main/java/org/neo4j/values/VirtualValue.java index 3597090f8dc4b..5557e57bf6716 100644 --- a/community/values/src/main/java/org/neo4j/values/VirtualValue.java +++ b/community/values/src/main/java/org/neo4j/values/VirtualValue.java @@ -19,83 +19,14 @@ */ package org.neo4j.values; +import org.neo4j.values.virtual.VirtualValueGroup; + /** * Value that can exist transiently during computations, but that cannot be stored as a property value. A Virtual * Value could be a NodeReference for example. */ -public abstract class VirtualValue extends Value +public abstract class VirtualValue extends AnyValue { - @Override - public final boolean equals( byte[] x ) - { - return false; - } - - @Override - public final boolean equals( short[] x ) - { - return false; - } - - @Override - public final boolean equals( int[] x ) - { - return false; - } - - @Override - public final boolean equals( long[] x ) - { - return false; - } - - @Override - public final boolean equals( float[] x ) - { - return false; - } - - @Override - public final boolean equals( double[] x ) - { - return false; - } - - @Override - public final boolean equals( boolean x ) - { - return false; - } - - @Override - public final boolean equals( boolean[] x ) - { - return false; - } - - @Override - public final boolean equals( char x ) - { - return false; - } - - @Override - public final boolean equals( String x ) - { - return false; - } - - @Override - public final boolean equals( char[] x ) - { - return false; - } - - @Override - public final boolean equals( String[] x ) - { - return false; - } @Override public final boolean equals( Object other ) @@ -103,12 +34,6 @@ public final boolean equals( Object other ) return other != null && other instanceof VirtualValue && equals( (VirtualValue) other ); } - @Override - public final boolean equals( Value other ) - { - return other != null && other instanceof VirtualValue && equals( (VirtualValue) other ); - } - @Override public final int hashCode() { @@ -119,15 +44,5 @@ public final int hashCode() public abstract boolean equals( VirtualValue other ); - @Override - public final ValueGroup valueGroup() - { - return ValueGroup.VIRTUAL; - } - - @Override - public final NumberType numberType() - { - return NumberType.NO_NUMBER; - } + public abstract VirtualValueGroup valueGroup(); } diff --git a/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java b/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java new file mode 100644 index 0000000000000..ca844379711c1 --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/virtual/ArrayHelpers.java @@ -0,0 +1,55 @@ +/* + * 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.virtual; + +import org.neo4j.values.AnyValue; +import org.neo4j.values.Values; + +/** + * This class is way too similar to org.neo4j.collection.primitive.PrimitiveArrays. + * + * Should we introduce dependency on primitive collections? + */ +class ArrayHelpers +{ + static boolean isSortedSet( int[] keys ) + { + for ( int i = 0; i < keys.length - 1; i++ ) + { + if ( keys[i] >= keys[i + 1] ) + { + return false; + } + } + return true; + } + + static boolean hasNullOrNoValue( AnyValue[] values ) + { + for ( AnyValue value : values ) + { + if ( value == null || value == Values.NO_VALUE ) + { + return true; + } + } + return false; + } +} diff --git a/community/values/src/main/java/org/neo4j/values/virtual/ListValue.java b/community/values/src/main/java/org/neo4j/values/virtual/ListValue.java new file mode 100644 index 0000000000000..e0ef8ce3a983b --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/virtual/ListValue.java @@ -0,0 +1,86 @@ +/* + * 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.virtual; + +import java.util.Arrays; + +import org.neo4j.values.AnyValue; +import org.neo4j.values.AnyValueWriter; +import org.neo4j.values.VirtualValue; + +import static org.neo4j.values.virtual.ArrayHelpers.hasNullOrNoValue; + +final class ListValue extends VirtualValue +{ + private final AnyValue[] values; + + ListValue( AnyValue[] values ) + { + assert values != null; + assert !hasNullOrNoValue( values ); + + this.values = values; + } + + @Override + public boolean equals( VirtualValue other ) + { + if ( other == null || !(other instanceof ListValue) ) + { + return false; + } + ListValue that = (ListValue) other; + return size() == that.size() && + Arrays.equals( values, that.values ); + } + + @Override + public int hash() + { + return Arrays.hashCode( values ); + } + + @Override + public void writeTo( AnyValueWriter writer ) + { + writer.beginList( values.length ); + for ( AnyValue value : values ) + { + value.writeTo( writer ); + } + writer.endList(); + } + + @Override + public VirtualValueGroup valueGroup() + { + return VirtualValueGroup.MAP; + } + + public int size() + { + return values.length; + } + + public AnyValue value( int offset ) + { + return values[offset]; + } +} diff --git a/community/values/src/main/java/org/neo4j/values/virtual/MapValue.java b/community/values/src/main/java/org/neo4j/values/virtual/MapValue.java new file mode 100644 index 0000000000000..91953fbf958c4 --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/virtual/MapValue.java @@ -0,0 +1,105 @@ +/* + * 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.virtual; + +import java.util.Arrays; + +import org.neo4j.values.AnyValue; +import org.neo4j.values.AnyValueWriter; +import org.neo4j.values.VirtualValue; + +import static org.neo4j.values.virtual.ArrayHelpers.hasNullOrNoValue; +import static org.neo4j.values.virtual.ArrayHelpers.isSortedSet; + +final class MapValue extends VirtualValue +{ + private final int[] keys; + private final AnyValue[] values; + + MapValue( int[] keys, AnyValue[] values ) + { + assert keys != null; + assert values != null; + assert keys.length == values.length; + assert isSortedSet( keys ); + assert !hasNullOrNoValue( values ); + + this.keys = keys; + this.values = values; + } + + @Override + public boolean equals( VirtualValue other ) + { + if ( other == null || !(other instanceof MapValue) ) + { + return false; + } + MapValue that = (MapValue) other; + return size() == that.size() && + Arrays.equals( keys, that.keys ) && + Arrays.equals( values, that.values ); + } + + @Override + public int hash() + { + int result = 0; + for ( int i = 0; i < keys.length; i++ ) + { + result += 31 * ( result + keys[i] ); + result += 31 * ( result + values[i].hashCode() ); + } + return result; + } + + @Override + public void writeTo( AnyValueWriter writer ) + { + writer.beginMap( keys.length ); + for ( int i = 0; i < keys.length; i++ ) + { + writer.writeKeyId( keys[i] ); + values[i].writeTo( writer ); + } + writer.endMap(); + } + + @Override + public VirtualValueGroup valueGroup() + { + return VirtualValueGroup.MAP; + } + + public int size() + { + return keys.length; + } + + public int propertyKeyId( int offset ) + { + return keys[offset]; + } + + public AnyValue value( int offset ) + { + return values[offset]; + } +} diff --git a/community/values/src/main/java/org/neo4j/values/virtual/VirtualValueGroup.java b/community/values/src/main/java/org/neo4j/values/virtual/VirtualValueGroup.java new file mode 100644 index 0000000000000..cd38697fd9a31 --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/virtual/VirtualValueGroup.java @@ -0,0 +1,34 @@ +/* + * 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.virtual; + +/** + * The ValueGroup is the logical group or type of a Value. For example byte, short, int and long are all attempting + * to represent mathematical integers, meaning that for comparison purposes they should be treated the same. + */ +public enum VirtualValueGroup +{ + NO_VALUE, + LIST, + MAP, + NODE, + EDGE, + PATH +} diff --git a/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java b/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java new file mode 100644 index 0000000000000..ea9dd2f7df086 --- /dev/null +++ b/community/values/src/main/java/org/neo4j/values/virtual/VirtualValues.java @@ -0,0 +1,45 @@ +/* + * 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.virtual; + +import org.neo4j.values.AnyValue; + +/** + * Entry point to the virtual values library. + */ +@SuppressWarnings( "WeakerAccess" ) +public class VirtualValues +{ + private VirtualValues() + { + } + + // DIRECT FACTORY METHODS + + public static ListValue list( AnyValue... values ) + { + return new ListValue( values ); + } + + public static MapValue map( int[] keys, AnyValue[] values ) + { + return new MapValue( keys, values ); + } +} diff --git a/community/values/src/test/java/org/neo4j/values/AnyValuesTest.java b/community/values/src/test/java/org/neo4j/values/AnyValuesTest.java new file mode 100644 index 0000000000000..2f20e86c4bfb8 --- /dev/null +++ b/community/values/src/test/java/org/neo4j/values/AnyValuesTest.java @@ -0,0 +1,57 @@ +/* + * 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; + +import org.junit.Test; + +import static junit.framework.TestCase.assertFalse; +import static org.neo4j.values.Values.booleanValue; +import static org.neo4j.values.Values.byteValue; +import static org.neo4j.values.Values.doubleValue; +import static org.neo4j.values.Values.floatValue; +import static org.neo4j.values.Values.intValue; +import static org.neo4j.values.Values.longValue; +import static org.neo4j.values.Values.shortValue; +import static org.neo4j.values.Values.stringValue; + +public class AnyValuesTest +{ + + @Test + public void shouldNotEqualVirtualValue() + { + VirtualValue virtual = new MyVirtualValue( 42 ); + + assertNotEqual( booleanValue( false ), virtual ); + assertNotEqual( byteValue( (byte)0 ), virtual ); + assertNotEqual( shortValue( (short)0 ), virtual ); + assertNotEqual( intValue( 0 ), virtual ); + assertNotEqual( longValue( 0 ), virtual ); + assertNotEqual( floatValue( 0.0f ), virtual ); + assertNotEqual( doubleValue( 0.0 ), virtual ); + assertNotEqual( stringValue( "" ), virtual ); + } + + private void assertNotEqual( AnyValue a, AnyValue b ) + { + assertFalse( "should not be equal", a.equals( b ) ); + assertFalse( "should not be equal", b.equals( a ) ); + } +} diff --git a/community/values/src/test/java/org/neo4j/values/BufferValueWriter.java b/community/values/src/test/java/org/neo4j/values/BufferValueWriter.java index 264a5d93cc556..b0f662a0b810c 100644 --- a/community/values/src/test/java/org/neo4j/values/BufferValueWriter.java +++ b/community/values/src/test/java/org/neo4j/values/BufferValueWriter.java @@ -88,7 +88,7 @@ public String toString() } } - private List buffer = new ArrayList<>(); + protected List buffer = new ArrayList<>(); @SuppressWarnings( "WeakerAccess" ) public void assertBuffer( Object... writeEvents ) diff --git a/community/values/src/test/java/org/neo4j/values/MyVirtualValue.java b/community/values/src/test/java/org/neo4j/values/MyVirtualValue.java index ed2e55d2106a1..8bc55ece073b2 100644 --- a/community/values/src/test/java/org/neo4j/values/MyVirtualValue.java +++ b/community/values/src/test/java/org/neo4j/values/MyVirtualValue.java @@ -19,6 +19,8 @@ */ package org.neo4j.values; +import org.neo4j.values.virtual.VirtualValueGroup; + public class MyVirtualValue extends VirtualValue { private final int hashCode; @@ -35,25 +37,18 @@ public boolean equals( VirtualValue other ) } @Override - public int hash() - { - return hashCode; - } - - @Override - public void writeTo( ValueWriter writer ) + public VirtualValueGroup valueGroup() { + return null; } @Override - public Object asObjectCopy() + public int hash() { - return this; + return hashCode; } - @Override - public String prettyPrint() + public void writeTo( AnyValueWriter writer ) { - return null; } } diff --git a/community/values/src/test/java/org/neo4j/values/ValueComparisonTest.java b/community/values/src/test/java/org/neo4j/values/ValueComparisonTest.java index 77f368890d9bb..21c67e626967b 100644 --- a/community/values/src/test/java/org/neo4j/values/ValueComparisonTest.java +++ b/community/values/src/test/java/org/neo4j/values/ValueComparisonTest.java @@ -35,7 +35,7 @@ public class ValueComparisonTest @Rule public ExpectedException thrown = ExpectedException.none(); - private ValueComparator comparator = Values.VALUE_COMPARATOR; + private Comparator comparator = Values.COMPARATOR; private Object[] objs = new Object[]{ // OTHER @@ -94,8 +94,6 @@ public class ValueComparisonTest public void shouldOrderValuesCorrectly() { List values = Arrays.stream( objs ).map( Values::of ).collect( Collectors.toList() ); - values.add( new MyVirtualValue( 0 ) ); - values.add( new MyVirtualValue( 1 ) ); for ( int i = 0; i < values.size(); i++ ) { diff --git a/community/values/src/test/java/org/neo4j/values/ValuesTest.java b/community/values/src/test/java/org/neo4j/values/ValuesTest.java index 0aeeeff6a4cfa..3ffde05df182f 100644 --- a/community/values/src/test/java/org/neo4j/values/ValuesTest.java +++ b/community/values/src/test/java/org/neo4j/values/ValuesTest.java @@ -119,31 +119,10 @@ public void shouldBeEqualToItself() assertEqual( stringArray( new String[]{"hi"} ), lazyStringArray( () -> new String[]{"hi"} ) ); } - @Test - public void shouldNotEqualVirtualValue() - { - VirtualValue virtual = new MyVirtualValue( 42 ); - - assertNotEqual( booleanValue( false ), virtual ); - assertNotEqual( byteValue( (byte)0 ), virtual ); - assertNotEqual( shortValue( (short)0 ), virtual ); - assertNotEqual( intValue( 0 ), virtual ); - assertNotEqual( longValue( 0 ), virtual ); - assertNotEqual( floatValue( 0.0f ), virtual ); - assertNotEqual( doubleValue( 0.0 ), virtual ); - assertNotEqual( stringValue( "" ), virtual ); - } - private void assertEqual( Value a, Value b ) { assertTrue( "should be equal", a.equals( b ) ); assertTrue( "should be equal", b.equals( a ) ); assertTrue( "should have same has", a.hashCode() == b.hashCode() ); } - - private void assertNotEqual( Value a, Value b ) - { - assertFalse( "should not be equal", a.equals( b ) ); - assertFalse( "should not be equal", b.equals( a ) ); - } } diff --git a/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java b/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java new file mode 100644 index 0000000000000..1d06c594a78cc --- /dev/null +++ b/community/values/src/test/java/org/neo4j/values/virtual/BufferAnyValueWriter.java @@ -0,0 +1,284 @@ +/* + * 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.virtual; + +import org.neo4j.values.AnyValueWriter; +import org.neo4j.values.BufferValueWriter; + +import static java.lang.String.format; + +public class BufferAnyValueWriter extends BufferValueWriter implements AnyValueWriter +{ + + enum SpecialKind + { + BeginNode, + EndNode, + BeginLabels, + WriteLabel, + EndLabels, + BeginProperties, + WritePropertyKeyId, + EndProperties, + BeginEdge, + EndEdge, + BeginMap, + WriteKeyId, + EndMap, + BeginList, + EndList, + BeginPath, + EndPath + } + + public static class Special + { + final SpecialKind kind; + final String key; + + @Override + public boolean equals( Object o ) + { + if ( o == null || getClass() != o.getClass() ) + { + return false; + } + + Special special = (Special) o; + return kind == special.kind && key.equals( special.key ); + } + + @Override + public int hashCode() + { + return 31 * kind.hashCode() + key.hashCode(); + } + + Special( SpecialKind kind, String key ) + { + this.kind = kind; + this.key = key; + } + + Special( SpecialKind kind, int key ) + { + this.kind = kind; + this.key = Integer.toString( key ); + } + + @Override + public String toString() + { + return format( "Special(%s)", key ); + } + } + + @Override + public void beginNode( long nodeId ) + { + buffer.add( Specials.beginNode( nodeId ) ); + } + + @Override + public void endNode() + { + buffer.add( SpecialKind.EndNode ); + } + + @Override + public void beginLabels( int numberOfLabels ) + { + buffer.add( SpecialKind.BeginLabels ); + } + + @Override + public void writeLabel( int labelId ) + { + buffer.add( SpecialKind.WriteLabel ); + } + + @Override + public void endLabels() + { + buffer.add( SpecialKind.EndLabels ); + } + + @Override + public void beginProperties( int numberOfProperties ) + { + buffer.add( SpecialKind.BeginProperties ); + } + + @Override + public void writePropertyKeyId( int propertyKeyId ) + { + buffer.add( SpecialKind.WritePropertyKeyId ); + } + + @Override + public void endProperties() + { + buffer.add( SpecialKind.EndProperties ); + } + + @Override + public void beginEdge( long edgeId ) + { + buffer.add( SpecialKind.BeginEdge ); + } + + @Override + public void endEdge() + { + buffer.add( SpecialKind.EndEdge ); + } + + @Override + public void beginMap( int size ) + { + buffer.add( SpecialKind.BeginMap ); + } + + @Override + public void writeKeyId( int keyId ) + { + buffer.add( SpecialKind.WriteKeyId ); + } + + @Override + public void endMap() + { + buffer.add( SpecialKind.EndMap ); + } + + @Override + public void beginList( int size ) + { + buffer.add( SpecialKind.BeginList ); + } + + @Override + public void endList() + { + buffer.add( SpecialKind.EndList ); + } + + @Override + public void beginPath( int length ) + { + buffer.add( SpecialKind.BeginPath ); + } + + @Override + public void endPath() + { + buffer.add( SpecialKind.EndPath ); + } + + @SuppressWarnings( "WeakerAccess" ) + public static class Specials + { + + public static Special beginNode( long nodeId ) + { + return new Special( SpecialKind.BeginNode, (int)nodeId ); + } + + public static Special endNode() + { + return new Special( SpecialKind.EndNode, 0 ); + } + + public static Special beginLabels( int numberOfLabels ) + { + return new Special( SpecialKind.BeginLabels, numberOfLabels ); + } + + public static Special writeLabel( int labelId ) + { + return new Special( SpecialKind.WriteLabel, labelId ); + } + + public static Special endLabels() + { + return new Special( SpecialKind.EndLabels, 0 ); + } + + public static Special beginProperties( int numberOfProperties ) + { + return new Special( SpecialKind.BeginProperties, numberOfProperties ); + } + + public static Special writePropertyKeyId( int propertyKeyId ) + { + return new Special( SpecialKind.WritePropertyKeyId, propertyKeyId ); + } + + public static Special endProperties() + { + return new Special( SpecialKind.EndProperties, 0 ); + } + + public static Special beginEdge( long edgeId ) + { + return new Special( SpecialKind.BeginEdge, (int)edgeId ); + } + + public static Special endEdge() + { + return new Special( SpecialKind.EndEdge, 0 ); + } + + public static Special beginMap( int size ) + { + return new Special( SpecialKind.BeginMap, size ); + } + + public static Special writeKeyId( int keyId ) + { + return new Special( SpecialKind.WriteKeyId, keyId ); + } + + public static Special endMap() + { + return new Special( SpecialKind.EndMap, 0 ); + } + + public static Special beginList( int size ) + { + return new Special( SpecialKind.BeginList, size ); + } + + public static Special endList() + { + return new Special( SpecialKind.EndList, 0 ); + } + + public static Special beginPath( int length ) + { + return new Special( SpecialKind.BeginPath, length ); + } + + public static Special endPath() + { + return new Special( SpecialKind.EndPath, 0 ); + } + } +} diff --git a/community/values/src/test/java/org/neo4j/values/virtual/ListTest.java b/community/values/src/test/java/org/neo4j/values/virtual/ListTest.java new file mode 100644 index 0000000000000..2793eb642876f --- /dev/null +++ b/community/values/src/test/java/org/neo4j/values/virtual/ListTest.java @@ -0,0 +1,117 @@ +/* + * 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.virtual; + +import org.junit.Test; + +import org.neo4j.values.AnyValue; +import org.neo4j.values.Values; +import org.neo4j.values.VirtualValue; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ListTest +{ + @Test + public void shouldBeEqualToItself() + { + assertEqual( + list( new String[]{"hi"}, 3.0 ), + list( new String[]{"hi"}, 3.0 ) ); + + assertEqual( list(), list() ); + } + + @Test + public void shouldNotEqual() + { + assertNotEqual( list(), list( 2 ) ); + assertNotEqual( list(), list( 1, 2 ) ); + assertNotEqual( list( 1 ), list( 2 ) ); + assertNotEqual( list( 1 ), list( 1, 2 ) ); + assertNotEqual( list( 1, 1 ), list( 1, 2 ) ); + assertNotEqual( list( 1, "d" ), list( 1, "f" ) ); + assertNotEqual( list( 1, "d" ), list( "d", 1 ) ); + assertNotEqual( list( "d" ), list( false ) ); + assertNotEqual( + list( Values.stringArray( new String[]{"d"} ) ), + list( "d" ) ); + + assertNotEqual( + list( Values.longArray( new long[]{3, 4, 5} ) ), + list( Values.intArray( new int[]{3, 4, 50} ) ) ); + } + + @Test + public void shouldCoerce() + { + assertEqual( + list( new String[]{"h"}, 3.0 ), + list( new char[]{'h'}, 3 ) ); + } + + @Test + public void shouldRecurse() + { + assertEqual( + list( 'a', list( 'b', list( 'c' ) ) ), + list( 'a', list( 'b', list( 'c' ) ) ) ); + } + + @Test + public void shouldRecurseAndCoerce() + { + assertEqual( + list( "a", list( 'b', list( "c" ) ) ), + list( 'a', list( "b", list( 'c' ) ) ) ); + } + + private VirtualValue list( Object... objects ) + { + AnyValue[] values = new AnyValue[objects.length]; + for ( int i = 0; i < objects.length; i++ ) + { + Object o = objects[i]; + if ( o instanceof AnyValue ) + { + values[i] = (AnyValue)o; + } + else + { + values[i] = Values.of( o ); + } + } + return VirtualValues.list( values ); + } + + private void assertEqual( VirtualValue a, VirtualValue b ) + { + assertTrue( "should be equal", a.equals( b ) ); + assertTrue( "should be equal", b.equals( a ) ); + assertTrue( "should have same has", a.hashCode() == b.hashCode() ); + } + + private void assertNotEqual( VirtualValue a, VirtualValue b ) + { + assertFalse( "should not equal", a.equals( b ) ); + assertFalse( "should not equal", b.equals( a ) ); + } +} diff --git a/community/values/src/test/java/org/neo4j/values/virtual/MapTest.java b/community/values/src/test/java/org/neo4j/values/virtual/MapTest.java new file mode 100644 index 0000000000000..88ab25d5892cb --- /dev/null +++ b/community/values/src/test/java/org/neo4j/values/virtual/MapTest.java @@ -0,0 +1,128 @@ +/* + * 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.virtual; + +import org.junit.Test; + +import org.neo4j.values.AnyValue; +import org.neo4j.values.Values; +import org.neo4j.values.VirtualValue; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class MapTest +{ + @Test + public void shouldBeEqualToItself() + { + assertEqual( + map( 1, false, 20, new short[]{4} ), + map( 1, false, 20, new short[]{4} ) ); + + assertEqual( + map( 1, 101L, 20, "yo" ), + map( 1, 101L, 20, "yo" ) ); + } + + @Test + public void shouldCoerce() + { + assertEqual( + map( 1, 1, 20, 'a' ), + map( 1, 1.0, 20, "a" ) ); + + assertEqual( + map( 1, new byte[]{1}, 20, new String[]{"x"} ), + map( 1, new short[]{1}, 20, new char[]{'x'} ) ); + + assertEqual( + map( 1, new int[]{1}, 20, new double[]{2.0} ), + map( 1, new float[]{1.0f}, 20, new float[]{2.0f} ) ); + } + + @Test + public void shouldRecurse() + { + assertEqual( + map( 1, map( 2, map( 3, "hi" ) ) ), + map( 1, map( 2, map( 3, "hi" ) ) ) ); + } + + @Test + public void shouldRecurseAndCoerce() + { + assertEqual( + map( 1, map( 2, map( 3, "x" ) ) ), + map( 1, map( 2, map( 3, 'x' ) ) ) ); + + assertEqual( + map( 1, map( 2, map( 3, 1.0 ) ) ), + map( 1, map( 2, map( 3, 1 ) ) ) ); + } + + private VirtualValue map( Object... keyOrVal ) + { + assert keyOrVal.length % 2 == 0; + int[] keys = new int[keyOrVal.length / 2]; + AnyValue[] values = new AnyValue[keyOrVal.length / 2]; + for ( int i = 0; i < keyOrVal.length; i+=2 ) + { + keys[i/2] = (Integer)keyOrVal[i]; + values[i/2] = toAnyValue( keyOrVal[i+1] ); + } + return VirtualValues.map( keys, values ); + } + + private VirtualValue list( Object... objects ) + { + AnyValue[] values = new AnyValue[objects.length]; + for ( int i = 0; i < objects.length; i++ ) + { + values[i] = toAnyValue( objects[i] ); + } + return VirtualValues.list( values ); + } + + private AnyValue toAnyValue( Object o ) + { + if ( o instanceof AnyValue ) + { + return (AnyValue)o; + } + else + { + return Values.of( o ); + } + } + + private void assertEqual( VirtualValue a, VirtualValue b ) + { + assertTrue( "should be equal", a.equals( b ) ); + assertTrue( "should be equal", b.equals( a ) ); + assertTrue( "should have same has", a.hashCode() == b.hashCode() ); + } + + private void assertNotEqual( VirtualValue a, VirtualValue b ) + { + assertFalse( "should not equal", a.equals( b ) ); + assertFalse( "should not equal", b.equals( a ) ); + } +} diff --git a/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java b/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java new file mode 100644 index 0000000000000..2569025dfac14 --- /dev/null +++ b/community/values/src/test/java/org/neo4j/values/virtual/VirtualValueWriteToTest.java @@ -0,0 +1,104 @@ +/* + * 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.virtual; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.util.Arrays; + +import org.neo4j.values.BufferValueWriter; +import org.neo4j.values.Value; +import org.neo4j.values.Values; + +import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.beginList; +import static org.neo4j.values.virtual.BufferAnyValueWriter.Specials.endList; + +@RunWith( value = Parameterized.class ) +public class VirtualValueWriteToTest +{ + + @Parameterized.Parameters( name = "{0}" ) + public static Iterable data() + { + return Arrays.asList( + // scalar properties + shouldWrite( + VirtualValues.list( + Values.booleanValue( false ), + Values.byteArray( new byte[]{3, 4, 5} ), + Values.stringValue( "yo" ) + ), + beginList( 3 ), + false, new byte[]{3, 4, 5}, "yo", + endList() + ) + ); + } + + private WriteTest currentTest; + + public VirtualValueWriteToTest( WriteTest currentTest ) + { + this.currentTest = currentTest; + } + + private static WriteTest shouldWrite( Object value, Object... expected ) + { + return new WriteTest( Values.of( value ), expected ); + } + + private static WriteTest shouldWrite( Value value, Object... expected ) + { + return new WriteTest( value, expected ); + } + + @Test + public void runTest() + { + currentTest.verifyWriteTo(); + } + + private static class WriteTest + { + private final Value value; + private final Object[] expected; + + private WriteTest( Value value, Object... expected ) + { + this.value = value; + this.expected = expected; + } + + @Override + public String toString() + { + return String.format( "%s should write %s", value, Arrays.toString( expected ) ); + } + + void verifyWriteTo() + { + BufferValueWriter writer = new BufferValueWriter(); + value.writeTo( writer ); + writer.assertBuffer( expected ); + } + } +}