Skip to content

Commit

Permalink
Merge pull request #9466 from pontusmelke/3.2-index-or
Browse files Browse the repository at this point in the history
Handle OR with indexes
  • Loading branch information
systay committed Jun 2, 2017
2 parents fd2b1d7 + 34db48f commit a56852e
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 3 deletions.
Expand Up @@ -25,9 +25,11 @@
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.IntStream;
Expand Down Expand Up @@ -70,16 +72,60 @@ public static Collection<?> toCollection( Object value )
{
return Collections.emptyList();
}
if ( value instanceof Collection<?> )
else if ( value instanceof Collection<?> )
{
return (Collection<?>) value;
}
// TODO: Handle primitive streams
else if ( value instanceof LongStream)
{
LongStream stream = (LongStream) value;
return stream.boxed().collect( Collectors.toList());
}
else if ( value instanceof IntStream )
{
IntStream stream = (IntStream) value;
return stream.boxed().collect( Collectors.toList());
}
else if ( value instanceof DoubleStream )
{
DoubleStream stream = (DoubleStream) value;
return stream.boxed().collect( Collectors.toList());
}

throw new CypherTypeException(
"Don't know how to create an iterable out of " + value.getClass().getSimpleName(), null );
}

public static Set<?> toSet( Object value )
{
if ( value == null )
{
return Collections.emptySet();
}
else if ( value instanceof Collection<?> )
{
return new HashSet<>( (Collection< ? >) value);
}
else if ( value instanceof LongStream)
{
LongStream stream = (LongStream) value;
return stream.boxed().collect( Collectors.toSet());
}
else if ( value instanceof IntStream )
{
IntStream stream = (IntStream) value;
return stream.boxed().collect( Collectors.toSet());
}
else if ( value instanceof DoubleStream )
{
DoubleStream stream = (DoubleStream) value;
return stream.boxed().collect( Collectors.toSet());
}

throw new CypherTypeException(
"Don't know how to create a set out of " + value.getClass().getSimpleName(), null );
}

public static CompositeKey compositeKey( long... keys )
{
return new CompositeKey( keys );
Expand Down
Expand Up @@ -20,6 +20,7 @@
package org.neo4j.cypher.internal.codegen

import java.util
import java.util.stream.{DoubleStream, IntStream, LongStream}

import org.mockito.Mockito.when
import org.neo4j.cypher.internal.frontend.v3_2.CypherTypeException
Expand Down Expand Up @@ -77,6 +78,15 @@ class CompiledConversionUtilsTest extends CypherFunSuite {
theMap(theKey) should equal(theObject)
}

test("should handle toSet") {
import scala.collection.JavaConverters._
CompiledConversionUtils.toSet(null) should equal(Set.empty.asJava)
CompiledConversionUtils.toSet(List(1,1,2,3).asJava) should equal(Set(1,2,3).asJava)
CompiledConversionUtils.toSet(IntStream.of(1,2,3,1)) should equal(Set(1,2,3).asJava)
CompiledConversionUtils.toSet(LongStream.of(1L,2L,3L,1L)) should equal(Set(1L,2L,3L).asJava)
CompiledConversionUtils.toSet(DoubleStream.of(1.1,2.2,3.3,1.1)) should equal(Set(1.1,2.2,3.3).asJava)
}

val testEquality = Seq(
(null, "foo") -> null,
(false, false) -> true,
Expand Down
Expand Up @@ -28,6 +28,36 @@ import org.neo4j.cypher.{ExecutionEngineFunSuite, NewPlannerTestSupport}
*/
class NodeIndexSeekAcceptanceTest extends ExecutionEngineFunSuite with NewPlannerTestSupport{

test("should handle OR when using index") {
// Given
graph.createIndex("L", "prop")
val node1 = createLabeledNode(Map("prop" -> 1), "L")
val node2 = createLabeledNode(Map("prop" -> 2), "L")
createLabeledNode(Map("prop" -> 3), "L")

// When
val result = executeWithAllPlannersAndRuntimesAndCompatibilityMode("MATCH (n:L) WHERE n.prop = 1 OR n.prop = 2 RETURN n")

// Then
result should useOperationTimes("NodeIndexSeek", 1)
result.toList should equal(List(Map("n" -> node1), Map("n" -> node2)))
}

test("should handle AND when using index") {
// Given
graph.createIndex("L", "prop")
createLabeledNode(Map("prop" -> 1), "L")
createLabeledNode(Map("prop" -> 2), "L")
createLabeledNode(Map("prop" -> 3), "L")

// When
val result = executeWithAllPlannersAndRuntimesAndCompatibilityMode("MATCH (n:L) WHERE n.prop = 1 AND n.prop = 2 RETURN n")

// Then
result should useOperationTimes("NodeIndexSeek", 1)
result.toList shouldBe empty
}

test("Should allow AND and OR with index and equality predicates") {
graph.createIndex("User", "prop1")
graph.createIndex("User", "prop2")
Expand Down
Expand Up @@ -619,7 +619,8 @@ class GeneratedMethodStructure(val fields: Fields, val generator: CodeBlock, aux
invoke(iterator, method[java.util.Iterator[_], Boolean]("hasNext"))

override def toSet(value: Expression) =
createNewInstance(typeRef[util.HashSet[Object]], (typeRef[util.Collection[_]], value))
invoke(methodReference(typeRef[CompiledConversionUtils], typeRef[java.util.Set[Object]], "toSet", typeRef[Object]),
value)

override def newDistinctSet(name: String, codeGenTypes: Iterable[CodeGenType]) = {
if (codeGenTypes.size == 1 && codeGenTypes.head.repr == LongType) {
Expand Down

0 comments on commit a56852e

Please sign in to comment.