Permalink
Browse files

Fixes #946 - HAS(...) fails with ThisShouldNotHappenException for som…

…e patterns
  • Loading branch information...
1 parent 580d520 commit 4e227c5fe1b8f5232dbbeb9f45cf8208d77d6d08 @systay committed Oct 26, 2012
View
5 cypher/CHANGES.txt
@@ -1,3 +1,8 @@
+1.9.M02
+-------------------
+o The traversal pattern matcher now supports variable length relationship patterns
+o Fixes #946 - HAS(...) fails with ThisShouldNotHappenException for some patterns
+
1.9.M01 (2012-10-23)
--------------------
o Refactored the type system from the bottom up
View
29 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Predicate.scala
@@ -208,27 +208,30 @@ case class True() extends Predicate {
def symbolTableDependencies = Set()
}
-case class Has(property: Property) extends Predicate {
- def isMatch(m: ExecutionContext): Boolean = property match {
- case Property(identifier, propertyName) => {
- val propContainer = m(identifier).asInstanceOf[PropertyContainer]
- propContainer != null && propContainer.hasProperty(propertyName)
+case class Has(element: Expression, propertyName: String) extends Predicate {
+ def isMatch(m: ExecutionContext): Boolean = {
+ element(m) match {
+ case pc: PropertyContainer => pc.hasProperty(propertyName)
+ case null => false
+ case _ => throw new CypherTypeException("Expected " + element + " to be a property container.")
}
}
def atoms: Seq[Predicate] = Seq(this)
- override def toString(): String = "hasProp(" + property + ")"
+
+ override def toString(): String = "hasProp(" + propertyName + ")"
+
def containsIsNull = false
- def rewrite(f: (Expression) => Expression) = property.rewrite(f) match {
- case prop:Property => Has(prop)
- case _ => throw new ThisShouldNotHappenError("Andres", "Something went wrong rewriting a Has(Property)")
- }
- def filter(f: (Expression) => Boolean) = property.filter(f)
+
+ def rewrite(f: (Expression) => Expression) = Has(element.rewrite(f), propertyName)
+
+ def filter(f: (Expression) => Boolean) = element.filter(f)
+
def assertInnerTypes(symbols: SymbolTable) {
- property.assertTypes(symbols)
+ element.evaluateType(MapType(), symbols)
}
- def symbolTableDependencies = property.symbolTableDependencies
+ def symbolTableDependencies = element.symbolTableDependencies
}
case class LiteralRegularExpression(a: Expression, regex: Literal) extends Predicate {
View
8 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/Expressions.scala
@@ -170,14 +170,20 @@ trait Expressions extends Base {
| expressionOrEntity <~ ignoreCase("is not null") ^^ (x => Not(IsNull(x)))
| operators
| ignoreCase("not") ~> predicate ^^ ( inner => Not(inner) )
- | ignoreCase("has") ~> parens(property) ^^ ( prop => Has(prop.asInstanceOf[Property]))
+ | hasProperty
| parens(predicate)
| sequencePredicate
| hasRelationshipTo
| hasRelationship
| aggregateFunctionNames ~> parens(expression) ~> failure("aggregate functions can not be used in the WHERE clause")
)
+ def hasProperty = ignoreCase("has") ~> parens(property) ^^ {
+ case x =>
+ val prop = x.asInstanceOf[Property]
+ Has(Identifier(prop.entity), prop.property)
+ }
+
def sequencePredicate: Parser[Predicate] = allInSeq | anyInSeq | noneInSeq | singleInSeq | in
def symbolIterablePredicate: Parser[(Expression, String, Predicate)] =
View
9 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Predicates.scala
@@ -38,13 +38,20 @@ trait Predicates extends Base with ParserPattern with StringLiteral {
| operators
| ignoreCase("not") ~> parens(predicate) ^^ ( inner => Not(inner) )
| ignoreCase("not") ~> predicate ^^ ( inner => Not(inner) )
- | ignoreCase("has") ~> parens(property) ^^ ( prop => Has(prop.asInstanceOf[Property]))
+ | hasProperty
| parens(predicate)
| sequencePredicate
| patternPredicate
| aggregateFunctionNames ~> parens(expression) ~> failure("aggregate functions can not be used in the WHERE clause")
)
+ def hasProperty = ignoreCase("has") ~> parens(property) ^^ {
+ case x =>
+ val prop = x.asInstanceOf[Property]
+ Has(Identifier(prop.entity), prop.property)
+ }
+
+
def sequencePredicate: Parser[Predicate] = allInSeq | anyInSeq | noneInSeq | singleInSeq | in
def symbolIterablePredicate: Parser[(Expression, String, Predicate)] =
View
9 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_9/Predicates.scala
@@ -38,13 +38,20 @@ trait Predicates extends Base with ParserPattern with StringLiteral {
| operators
| ignoreCase("not") ~> parens(predicate) ^^ ( inner => Not(inner) )
| ignoreCase("not") ~> predicate ^^ ( inner => Not(inner) )
- | ignoreCase("has") ~> parens(property) ^^ ( prop => Has(prop.asInstanceOf[Property]))
+ | hasProperty
| parens(predicate)
| sequencePredicate
| patternPredicate
| aggregateFunctionNames ~> parens(expression) ~> failure("aggregate functions can not be used in the WHERE clause")
)
+ def hasProperty = ignoreCase("has") ~> parens(property) ^^ {
+ case x =>
+ val prop = x.asInstanceOf[Property]
+ Has(Identifier(prop.entity), prop.property)
+ }
+
+
def sequencePredicate: Parser[Predicate] = allInSeq | anyInSeq | noneInSeq | singleInSeq | in
def symbolIterablePredicate: Parser[(Expression, String, Predicate)] =
View
14 cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala
@@ -2270,4 +2270,18 @@ RETURN x0.name?
assert(result.toList === List(Map("b" -> b)))
}
+
+ @Test
+ def can_rewrite_has_property() {
+ val a = createNode()
+ val r = createNode("foo"->"bar")
+ val b = createNode()
+
+ relate(a,r)
+ relate(r,b)
+
+ val result = parseAndExecute("START a=node(1) MATCH a-->r-->b WHERE has(r.foo) RETURN b")
+
+ assert(result.toList === List(Map("b" -> b)))
+ }
}

0 comments on commit 4e227c5

Please sign in to comment.