Skip to content

Commit

Permalink
Add matcher for relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
Mats-SX committed Mar 3, 2016
1 parent ed7faee commit fc2bc36
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 48 deletions.
Expand Up @@ -21,14 +21,7 @@

import cypher.feature.parser.generated.FeatureResultsBaseListener;
import cypher.feature.parser.generated.FeatureResultsParser;
import cypher.feature.parser.matchers.BooleanMatcher;
import cypher.feature.parser.matchers.FloatMatcher;
import cypher.feature.parser.matchers.IntegerMatcher;
import cypher.feature.parser.matchers.ListMatcher;
import cypher.feature.parser.matchers.MapMatcher;
import cypher.feature.parser.matchers.NodeMatcher;
import cypher.feature.parser.matchers.StringMatcher;
import cypher.feature.parser.matchers.ValueMatcher;
import cypher.feature.parser.matchers.*;

import java.util.Deque;
import java.util.HashMap;
Expand All @@ -37,22 +30,20 @@
import java.util.Map;
import java.util.Set;

import org.neo4j.graphdb.RelationshipType;

class CypherMatchersCreator extends FeatureResultsBaseListener
{
private Deque<Object> oldworkload;
private Deque<ValueMatcher> workload;
private Deque<Integer> listCounters;
private Deque<Integer> mapCounters;
private Deque<String> keys;
private Deque<String> names;

private static final String INFINITY = "Inf";

CypherMatchersCreator()
{
this.workload = new LinkedList<>();
this.oldworkload = new LinkedList<>();
this.keys = new LinkedList<>();
this.listCounters = new LinkedList<>();
this.mapCounters = new LinkedList<>();
this.names = new LinkedList<>();
Expand Down Expand Up @@ -150,16 +141,16 @@ public void exitPropertyMap( FeatureResultsParser.PropertyMapContext ctx )
for ( int i = 0; i < counter; ++i )
{
ValueMatcher value = workload.pop();
String key = oldworkload.pop().toString();
String key = keys.pop();
map.put( key, value );
}
workload.push( new MapMatcher(map) );
workload.push( new MapMatcher( map ) );
}

@Override
public void enterPropertyKey( FeatureResultsParser.PropertyKeyContext ctx )
{
oldworkload.push( ctx.getText() );
keys.push( ctx.getText() );
}

@Override
Expand All @@ -176,23 +167,11 @@ public void exitNode( FeatureResultsParser.NodeContext ctx )
Set<String> labelNames = new HashSet<>();
while ( !names.isEmpty() )
{
labelNames.add( names.pop() );
labelNames.add( names.pop() );
}
workload.push( new NodeMatcher( labelNames, properties ) );
}

private Map<String,Object> getMapOrEmpty()
{
if ( oldworkload.isEmpty() )
{
return new HashMap<>();
}
else
{
return (Map<String,Object>) oldworkload.pop();
}
}

private MapMatcher getMapMatcher()
{
if ( workload.isEmpty() )
Expand All @@ -214,21 +193,8 @@ public void enterRelationshipTypeName( FeatureResultsParser.RelationshipTypeName
@Override
public void exitRelationship( FeatureResultsParser.RelationshipContext ctx )
{
final Map<String,Object> properties = getMapOrEmpty();
final RelationshipType type = RelationshipType.withName( names.pop() );
oldworkload.push( new ParsedRelationship()
{
@Override
public RelationshipType getType()
{
return type;
}

@Override
public Map<String,Object> getAllProperties()
{
return properties;
}
} );
MapMatcher properties = getMapMatcher();
String relTypeName = names.pop();
workload.push( new RelationshipMatcher( relTypeName, properties ) );
}
}
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2002-2016 "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 <http://www.gnu.org/licenses/>.
*/
package cypher.feature.parser.matchers;

import org.neo4j.graphdb.Relationship;

public class RelationshipMatcher implements ValueMatcher
{
private final String relationshipTypeName;
private final MapMatcher propertyMatcher;

public RelationshipMatcher( String relationshipTypeName, MapMatcher propertyMatcher )
{
this.relationshipTypeName = relationshipTypeName;
this.propertyMatcher = propertyMatcher;
}

@Override
public boolean matches( Object value )
{
if ( value instanceof Relationship )
{
Relationship relationship = (Relationship) value;

return relationship.getType().name().equals( relationshipTypeName )
&& propertyMatcher.matches( relationship.getAllProperties() );
}
return false;
}

@Override
public String toString()
{
return "RelationshipMatcher for type " + relationshipTypeName + " and properties: " + propertyMatcher;
}
}
@@ -1,8 +1,27 @@
/*
* Copyright (c) 2002-2016 "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 <http://www.gnu.org/licenses/>.
*/
package cypher.feature.parser

import cypher.feature.parser.matchers.ValueMatcher
import org.mockito.Mockito._
import org.neo4j.graphdb.{Label, Node}
import org.neo4j.graphdb.{RelationshipType, Relationship, Label, Node}
import org.scalatest.{Matchers, FunSuite}
import org.scalatest.matchers.{MatchResult, Matcher}

Expand All @@ -14,8 +33,18 @@ class ParsingTestSupport extends FunSuite with Matchers with DecorateAsJava {
val node = mock(classOf[Node])
when(node.getLabels).thenReturn(labels.map(Label.label).toIterable.asJava)
when(node.getAllProperties).thenReturn(properties.asJava)
when(node.toString).thenReturn(s"(${labels.mkString(":", ":", "")} $properties)")
node
}

def relationship(typ: String, properties: Map[String, AnyRef] = Map.empty): Relationship = {
val rel = mock(classOf[Relationship])
when(rel.getType).thenReturn(RelationshipType.withName(typ))
when(rel.getAllProperties).thenReturn(properties.asJava)
when(rel.toString).thenReturn(s"[:$typ $properties]")
rel
}

case class accept(value: Any) extends Matcher[ValueMatcher] {

override def apply(matcher: ValueMatcher): MatchResult = {
Expand Down
Expand Up @@ -34,7 +34,7 @@ import org.scalatest.{FunSuite, Matchers}
class expectedResultsParserTest extends ParsingTestSupport {

test("should parse null") {
valueParse("null") should equal(null)
parse("null") should accept(null)
}

test("should parse integer") {
Expand Down Expand Up @@ -133,8 +133,8 @@ class expectedResultsParserTest extends ParsingTestSupport {
}

test("should parse relationships") {
valueParse("[:T]") should equal(parsedRelationship("T"))
valueParse("[:T {k:0}]") should equal(parsedRelationship("T", Map("k" -> Long.valueOf(0L))))
parse("[:T]") should accept(relationship("T"))
parse("[:T {k:0}]") should accept(relationship("T", Map("k" -> Long.valueOf(0L))))
}

// test("should parse the zero-length path") {
Expand Down
@@ -0,0 +1,46 @@
/*
* Copyright (c) 2002-2016 "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 <http://www.gnu.org/licenses/>.
*/
package cypher.feature.parser.matchers

import cypher.feature.parser.ParsingTestSupport

class RelationshipMatcherTest extends ParsingTestSupport {

test("should match relationships") {
new RelationshipMatcher("T", MapMatcher.EMPTY) should accept(relationship("T"))
}

test("should match relationships with properties") {
val matcher = new RelationshipMatcher("T", new MapMatcher(Map[String, ValueMatcher]("key" -> new FloatMatcher(1e10)).asJava))

matcher should accept(relationship("T", Map("key" -> java.lang.Double.valueOf(1e10))))
}

test("should not match other types") {
new RelationshipMatcher("T", MapMatcher.EMPTY) shouldNot accept(node())
new RelationshipMatcher("T", MapMatcher.EMPTY) shouldNot accept(null)
new RelationshipMatcher("T", MapMatcher.EMPTY) shouldNot accept("relationship")
}

test("should not match when different type") {
new RelationshipMatcher("type1", MapMatcher.EMPTY) shouldNot accept(relationship("type2"))
}

}

0 comments on commit fc2bc36

Please sign in to comment.