Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Better type error messages

Renamed iterable to collection
  • Loading branch information...
commit e84f6437b5d1979247346eb243286ed562c41c71 1 parent a519eb0
@systay authored
Showing with 146 additions and 103 deletions.
  1. +2 −2 cypher/src/docs/dev/ql/functions/index.txt
  2. +1 −1  cypher/src/main/scala/org/neo4j/cypher/CypherException.scala
  3. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/commands/AggregationExpression.scala
  4. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Expression.scala
  5. +10 −10 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Functions.scala
  6. +8 −8 cypher/src/main/scala/org/neo4j/cypher/internal/commands/InIterable.scala
  7. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/commands/MathFunction.scala
  8. +2 −2 cypher/src/main/scala/org/neo4j/cypher/internal/executionplan/builders/MatchBuilder.scala
  9. +5 −5 cypher/src/main/scala/org/neo4j/cypher/internal/mutation/ForeachAction.scala
  10. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/Predicates.scala
  11. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/Expressions.scala
  12. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Predicates.scala
  13. +2 −2 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Updates.scala
  14. +10 −1 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/matching/MatchingContext.scala
  15. +2 −2 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/matching/PatternNode.scala
  16. +2 −2 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/matching/PatternRelationship.scala
  17. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/symbols/AnyIterableType.scala
  18. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/symbols/AnyType.scala
  19. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/BooleanType.scala
  20. +7 −3 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/{IterableType.scala → CollectionType.scala}
  21. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/DoubleType.scala
  22. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/IntegerType.scala
  23. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/LongType.scala
  24. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/MapType.scala
  25. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/NodeType.scala
  26. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/NumberType.scala
  27. +1 −5 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/PathType.scala
  28. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/RelationshipType.scala
  29. +3 −4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/ScalarType.scala
  30. +3 −5 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/StringType.scala
  31. +1 −1  cypher/src/main/scala/org/neo4j/cypher/internal/symbols/SymbolTable.scala
  32. +1 −1  cypher/src/test/scala/org/neo4j/cypher/CypherParserTest.scala
  33. +20 −0 cypher/src/test/scala/org/neo4j/cypher/ErrorMessagesTest.scala
  34. +0 −2  cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala
  35. +4 −4 cypher/src/test/scala/org/neo4j/cypher/{SematicErrorTest.scala → SemanticErrorTest.scala}
  36. +1 −1  cypher/src/test/scala/org/neo4j/cypher/docgen/CreateTest.scala
  37. +21 −21 cypher/src/test/scala/org/neo4j/cypher/docgen/FunctionsTest.scala
  38. +2 −1  cypher/src/test/scala/org/neo4j/cypher/docgen/MatchTest.scala
  39. +2 −2 cypher/src/test/scala/org/neo4j/cypher/internal/commands/ExtractTest.scala
  40. +2 −2 cypher/src/test/scala/org/neo4j/cypher/internal/symbols/SymbolTableTest.scala
View
4 cypher/src/docs/dev/ql/functions/index.txt
@@ -36,8 +36,8 @@ include::last.txt[]
:leveloffset: 2
-== Iterable functions ==
-Iterable functions return an iterable of things -- nodes in a path, and so on.
+== Collection functions ==
+Collection functions return collections of things -- nodes in a path, and so on.
:leveloffset: 3
View
2  cypher/src/main/scala/org/neo4j/cypher/CypherException.scala
@@ -33,7 +33,7 @@ class CypherTypeException(message: String, cause: Throwable = null) extends Cyph
class IterableRequiredException(message:String, cause:Throwable) extends CypherException(message, cause) {
def this(message:String) = this(message, null)
- def this(expression:Expression) = this("Expected " + expression.identifier.name + " to be an iterable, but it is not.", null)
+ def this(expression:Expression) = this("Expected " + expression.identifier.name + " to be a collection, but it is not.", null)
}
class ParameterNotFoundException(message:String, cause:Throwable) extends CypherException(message, cause) {
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/commands/AggregationExpression.scala
@@ -153,7 +153,7 @@ case class Avg(anInner: Expression) extends AggregationWithInnerExpression(anInn
}
case class Collect(anInner: Expression) extends AggregationWithInnerExpression(anInner) {
- def typ = new IterableType(anInner.identifier.typ)
+ def typ = new CollectionType(anInner.identifier.typ)
def name = "collect"
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Expression.scala
@@ -34,7 +34,7 @@ abstract class Expression extends (Map[String, Any] => Any) {
def dependencies(expectedType: AnyType): Seq[Identifier] = {
val myType = identifier.typ
if (!expectedType.isAssignableFrom(myType))
- throw new SyntaxException(identifier.name + " expected to be of type " + expectedType + " but it is of type " + identifier.typ)
+ throw new SyntaxException("`%s` expected to be a %s but it is a %s".format(identifier.name, expectedType, identifier.typ))
declareDependencies(expectedType)
}
@@ -238,7 +238,9 @@ case class Entity(entityName: String) extends CastableExpression {
case class Collection(expressions:Expression*) extends CastableExpression {
def compute(m: Map[String, Any]): Any = expressions.map(e=>e(m))
+
val identifier: Identifier = Identifier(name, AnyIterableType())
+
private def name = expressions.map(_.identifier.name).mkString("[", ", ", "]")
def declareDependencies(extectedType: AnyType): Seq[Identifier] = expressions.flatMap(_.declareDependencies(AnyType()))
def rewrite(f: (Expression) => Expression): Expression = f(Collection(expressions.map(f):_*))
View
20 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Functions.scala
@@ -36,8 +36,8 @@ abstract class NullInNullOutExpression(argument: Expression) extends Expression
}
}
-case class ExtractFunction(iterable: Expression, id: String, expression: Expression)
- extends NullInNullOutExpression(iterable)
+case class ExtractFunction(collection: Expression, id: String, expression: Expression)
+ extends NullInNullOutExpression(collection)
with IterableSupport
{
def compute(value: Any, m: Map[String, Any]) = makeTraversable(value).map(iterValue => {
@@ -45,19 +45,19 @@ case class ExtractFunction(iterable: Expression, id: String, expression: Express
expression(innerMap)
}).toList
- val identifier = Identifier("extract(" + id + " in " + iterable.identifier.name + " : " + expression.identifier.name + ")", new IterableType(expression.identifier.typ))
+ val identifier = Identifier("extract(" + id + " in " + collection.identifier.name + " : " + expression.identifier.name + ")", new CollectionType(expression.identifier.typ))
def declareDependencies(extectedType: AnyType): Seq[Identifier] =
// Extract depends on everything that the iterable and the expression depends on, except
// the new identifier inserted into the expression context, named with id
- iterable.dependencies(AnyIterableType()) ++ expression.dependencies(AnyType()).filterNot(_.name == id)
+ collection.dependencies(AnyIterableType()) ++ expression.dependencies(AnyType()).filterNot(_.name == id)
- def rewrite(f: (Expression) => Expression) = f(ExtractFunction(iterable.rewrite(f), id, expression.rewrite(f)))
+ def rewrite(f: (Expression) => Expression) = f(ExtractFunction(collection.rewrite(f), id, expression.rewrite(f)))
def filter(f: (Expression) => Boolean) = if (f(this))
- Seq(this) ++ iterable.filter(f) ++ expression.filter(f)
+ Seq(this) ++ collection.filter(f) ++ expression.filter(f)
else
- iterable.filter(f) ++ expression.filter(f)
+ collection.filter(f) ++ expression.filter(f)
}
case class RelationshipFunction(path: Expression) extends NullInNullOutExpression(path) {
@@ -66,7 +66,7 @@ case class RelationshipFunction(path: Expression) extends NullInNullOutExpressio
case x => throw new SyntaxException("Expected " + path.identifier.name + " to be a path.")
}
- val identifier = Identifier("RELATIONSHIPS(" + path.identifier.name + ")", new IterableType(RelationshipType()))
+ val identifier = Identifier("RELATIONSHIPS(" + path.identifier.name + ")", new CollectionType(RelationshipType()))
def declareDependencies(extectedType: AnyType): Seq[Identifier] = path.dependencies(PathType())
@@ -160,7 +160,7 @@ case class HeadFunction(collection: Expression) extends NullInNullOutExpression(
def compute(value: Any, m: Map[String, Any]) = makeTraversable(value).head
private def myType = collection.identifier.typ match {
- case x: IterableType => x.iteratedType
+ case x: CollectionType => x.iteratedType
case _ => ScalarType()
}
@@ -214,7 +214,7 @@ case class NodesFunction(path: Expression) extends NullInNullOutExpression(path)
case x => throw new SyntaxException("Expected " + path.identifier.name + " to be a path.")
}
- val identifier = Identifier("NODES(" + path.identifier.name + ")", new IterableType(NodeType()))
+ val identifier = Identifier("NODES(" + path.identifier.name + ")", new CollectionType(NodeType()))
def declareDependencies(extectedType: AnyType): Seq[Identifier] = path.dependencies(PathType())
View
16 cypher/src/main/scala/org/neo4j/cypher/internal/commands/InIterable.scala
@@ -54,36 +54,36 @@ abstract class InIterable(expression: Expression, symbol: String, closure: Predi
def filter(f: (Expression) => Boolean): Seq[Expression] = expression.filter(f) ++ closure.filter(f)
}
-case class AllInIterable(iterable: Expression, symbolName: String, inner: Predicate) extends InIterable(iterable, symbolName, inner) {
+case class AllInIterable(collection: Expression, symbolName: String, inner: Predicate) extends InIterable(collection, symbolName, inner) {
def seqMethod[U](f: Seq[U]): ((U) => Boolean) => Boolean = f.forall _
def name = "all"
- def rewrite(f: (Expression) => Expression) = AllInIterable(iterable.rewrite(f), symbolName, inner.rewrite(f))
+ def rewrite(f: (Expression) => Expression) = AllInIterable(collection.rewrite(f), symbolName, inner.rewrite(f))
}
-case class AnyInIterable(iterable: Expression, symbolName: String, inner: Predicate) extends InIterable(iterable, symbolName, inner) {
+case class AnyInIterable(collection: Expression, symbolName: String, inner: Predicate) extends InIterable(collection, symbolName, inner) {
def seqMethod[U](f: Seq[U]): ((U) => Boolean) => Boolean = f.exists _
def name = "any"
- def rewrite(f: (Expression) => Expression) = AnyInIterable(iterable.rewrite(f), symbolName, inner.rewrite(f))
+ def rewrite(f: (Expression) => Expression) = AnyInIterable(collection.rewrite(f), symbolName, inner.rewrite(f))
}
-case class NoneInIterable(iterable: Expression, symbolName: String, inner: Predicate) extends InIterable(iterable, symbolName, inner) {
+case class NoneInIterable(collection: Expression, symbolName: String, inner: Predicate) extends InIterable(collection, symbolName, inner) {
def seqMethod[U](f: Seq[U]): ((U) => Boolean) => Boolean = x => !f.exists(x)
def name = "none"
- def rewrite(f: (Expression) => Expression) = NoneInIterable(iterable.rewrite(f), symbolName, inner.rewrite(f))
+ def rewrite(f: (Expression) => Expression) = NoneInIterable(collection.rewrite(f), symbolName, inner.rewrite(f))
}
-case class SingleInIterable(iterable: Expression, symbolName: String, inner: Predicate) extends InIterable(iterable, symbolName, inner) {
+case class SingleInIterable(collection: Expression, symbolName: String, inner: Predicate) extends InIterable(collection, symbolName, inner) {
def seqMethod[U](f: Seq[U]): ((U) => Boolean) => Boolean = x => f.filter(x).length == 1
def name = "single"
- def rewrite(f: (Expression) => Expression) = SingleInIterable(iterable.rewrite(f), symbolName, inner.rewrite(f))
+ def rewrite(f: (Expression) => Expression) = SingleInIterable(collection.rewrite(f), symbolName, inner.rewrite(f))
}
object IsIterable extends IterableSupport {
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/commands/MathFunction.scala
@@ -85,7 +85,7 @@ case class RangeFunction(start: Expression, end: Expression, step: Expression) e
}
}
- val identifier = Identifier("range("+ start + "," + end + "," + step + ")", new IterableType(NumberType()))
+ val identifier = Identifier("range("+ start + "," + end + "," + step + ")", new CollectionType(NumberType()))
def rewrite(f: (Expression) => Expression) = f(RangeFunction(start.rewrite(f), end.rewrite(f), step.rewrite(f)))
}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/executionplan/builders/MatchBuilder.scala
@@ -99,10 +99,10 @@ trait PatternGraphBuilder {
patternRelMap(rel) = leftNode.relateTo(rel, rightNode, relType, dir, optional, predicate)
}
- case VarLengthRelatedTo(pathName, start, end, minHops, maxHops, relType, dir, iterableRel, optional, predicate) => {
+ case VarLengthRelatedTo(pathName, start, end, minHops, maxHops, relType, dir, relsCollection, optional, predicate) => {
val startNode: PatternNode = patternNodeMap.getOrElseUpdate(start, new PatternNode(start))
val endNode: PatternNode = patternNodeMap.getOrElseUpdate(end, new PatternNode(end))
- patternRelMap(pathName) = startNode.relateViaVariableLengthPathTo(pathName, endNode, minHops, maxHops, relType, dir, iterableRel, optional, predicate)
+ patternRelMap(pathName) = startNode.relateViaVariableLengthPathTo(pathName, endNode, minHops, maxHops, relType, dir, relsCollection, optional, predicate)
}
case _ =>
})
View
10 cypher/src/main/scala/org/neo4j/cypher/internal/mutation/ForeachAction.scala
@@ -24,7 +24,7 @@ import org.neo4j.cypher.internal.symbols.AnyIterableType
import org.neo4j.cypher.internal.pipes.{QueryState, ExecutionContext}
-case class ForeachAction(iterable: Expression, symbol: String, actions: Seq[UpdateAction])
+case class ForeachAction(collection: Expression, symbol: String, actions: Seq[UpdateAction])
extends UpdateAction
with IterableSupport {
def dependencies = {
@@ -34,13 +34,13 @@ case class ForeachAction(iterable: Expression, symbol: String, actions: Seq[Upda
filterNot(_.name == symbol). //remove dependencies to the symbol we're introducing
filterNot(ownIdentifiers contains) //remove dependencies to identifiers we are introducing
- iterable.dependencies(AnyIterableType()) ++ updateDeps
+ collection.dependencies(AnyIterableType()) ++ updateDeps
}
def exec(context: ExecutionContext, state: QueryState) = {
val before = context.get(symbol)
- val seq = makeTraversable(iterable(context))
+ val seq = makeTraversable(collection(context))
seq.foreach(element => {
context.put(symbol, element)
@@ -59,9 +59,9 @@ case class ForeachAction(iterable: Expression, symbol: String, actions: Seq[Upda
Stream(context)
}
- def filter(f: (Expression) => Boolean) = Some(iterable).filter(f).toSeq ++ actions.flatMap(_.filter(f))
+ def filter(f: (Expression) => Boolean) = Some(collection).filter(f).toSeq ++ actions.flatMap(_.filter(f))
- def rewrite(f: (Expression) => Expression) = ForeachAction(f(iterable), symbol, actions.map(_.rewrite(f)))
+ def rewrite(f: (Expression) => Expression) = ForeachAction(f(collection), symbol, actions.map(_.rewrite(f)))
def identifier = Seq.empty
}
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/Predicates.scala
@@ -57,7 +57,7 @@ trait Predicates extends Base with Expressions with ReturnItems {
def sequencePredicate: Parser[Predicate] = allInSeq | anyInSeq | noneInSeq | singleInSeq
def symbolIterablePredicate: Parser[(Expression, String, Predicate)] =
- (identity ~ ignoreCase("in") ~ expression ~ ignoreCase("where") ~ predicate ^^ { case symbol ~ in ~ iterable ~ where ~ klas => (iterable, symbol, klas) }
+ (identity ~ ignoreCase("in") ~ expression ~ ignoreCase("where") ~ predicate ^^ { case symbol ~ in ~ collection ~ where ~ klas => (collection, symbol, klas) }
|identity ~> ignoreCase("in") ~ expression ~> failure("expected where"))
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/Expressions.scala
@@ -181,7 +181,7 @@ trait Expressions extends Base {
def sequencePredicate: Parser[Predicate] = allInSeq | anyInSeq | noneInSeq | singleInSeq | in
def symbolIterablePredicate: Parser[(Expression, String, Predicate)] =
- (identity ~ ignoreCase("in") ~ expression ~ ignoreCase("where") ~ predicate ^^ { case symbol ~ in ~ iterable ~ where ~ klas => (iterable, symbol, klas) }
+ (identity ~ ignoreCase("in") ~ expression ~ ignoreCase("where") ~ predicate ^^ { case symbol ~ in ~ collection ~ where ~ klas => (collection, symbol, klas) }
|identity ~> ignoreCase("in") ~ expression ~> failure("expected where"))
def in : Parser[Predicate] = expression ~ ignoreCase("in") ~ expression ^^ {
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Predicates.scala
@@ -47,7 +47,7 @@ trait Predicates extends Base with ParserPattern with StringLiteral {
def sequencePredicate: Parser[Predicate] = allInSeq | anyInSeq | noneInSeq | singleInSeq | in
def symbolIterablePredicate: Parser[(Expression, String, Predicate)] =
- (identity ~ ignoreCase("in") ~ expression ~ ignoreCase("where") ~ predicate ^^ { case symbol ~ in ~ iterable ~ where ~ klas => (iterable, symbol, klas) }
+ (identity ~ ignoreCase("in") ~ expression ~ ignoreCase("where") ~ predicate ^^ { case symbol ~ in ~ collection ~ where ~ klas => (collection, symbol, klas) }
|identity ~> ignoreCase("in") ~ expression ~> failure("expected where"))
def in: Parser[Predicate] = expression ~ ignoreCase("in") ~ expression ^^ {
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Updates.scala
@@ -27,13 +27,13 @@ trait Updates extends Base with Expressions with StartClause {
def updates: Parser[(Seq[UpdateAction], Seq[NamedPath])] = rep(delete | set | foreach) ^^ (cmds => reduce(cmds))
def foreach: Parser[(Seq[UpdateAction], Seq[NamedPath])] = ignoreCase("foreach") ~> "(" ~> identity ~ ignoreCase("in") ~ expression ~ ":" ~ opt(createStart) ~ opt(updates) <~ ")" ^^ {
- case id ~ in ~ iterable ~ ":" ~ creates ~ innerUpdates => {
+ case id ~ in ~ collection ~ ":" ~ creates ~ innerUpdates => {
val createCmds = creates.toSeq.map(_._1.map(_.asInstanceOf[UpdateAction])).flatten
val reducedItems: (Seq[UpdateAction], Seq[NamedPath]) = reduce(innerUpdates.toSeq)
val updateCmds = reducedItems._1
val namedPaths = reducedItems._2 ++ creates.toSeq.flatMap(_._2)
if(namedPaths.nonEmpty) throw new SyntaxException("Paths can't be created inside of foreach")
- (Seq(ForeachAction(iterable, id, createCmds ++ updateCmds)), Seq())
+ (Seq(ForeachAction(collection, id, createCmds ++ updateCmds)), Seq())
}
}
View
11 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/matching/MatchingContext.scala
@@ -38,7 +38,16 @@ class MatchingContext(boundIdentifiers: SymbolTable,
private def identifiers:Seq[Identifier] = patternGraph.patternRels.values.flatMap(p => p.identifiers).toSeq
- lazy val symbols = boundIdentifiers.add(identifiers: _*)
+ lazy val symbols = {
+ val ids = identifiers
+
+ val identifiersAlreadyInContext = ids.filter(identifier => boundIdentifiers.keys.contains(identifier.name))
+
+ identifiersAlreadyInContext.foreach( boundIdentifiers.assertHas )
+
+ boundIdentifiers.keys.filter(_)
+ boundIdentifiers.add(ids: _*)
+ }
def getMatches(sourceRow: Map[String, Any]): Traversable[Map[String, Any]] = {
builder.getMatches(sourceRow)
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/matching/PatternNode.scala
@@ -43,10 +43,10 @@ class PatternNode(key: String) extends PatternElement(key) {
maxHops: Option[Int],
relType: Seq[String],
dir: Direction,
- iterableRel: Option[String],
+ collectionOfRels: Option[String],
optional: Boolean,
predicate: Predicate): PatternRelationship = {
- val rel = new VariableLengthPatternRelationship(pathName, this, end, iterableRel, minHops, maxHops, relType, dir, optional, predicate)
+ val rel = new VariableLengthPatternRelationship(pathName, this, end, collectionOfRels, minHops, maxHops, relType, dir, optional, predicate)
relationships.add(rel)
end.relationships.add(rel)
rel
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/matching/PatternRelationship.scala
@@ -119,8 +119,8 @@ class VariableLengthPatternRelationship(pathName: String,
override def identifiers : Seq[Identifier] = Seq(
Identifier(startNode.key, NodeType()),
Identifier(endNode.key, NodeType()),
- Identifier(key, new IterableType(RelationshipType()))) ++
- relIterable.toSeq.map(Identifier(_, new IterableType(RelationshipType())))
+ Identifier(key, new CollectionType(RelationshipType()))) ++
+ relIterable.toSeq.map(Identifier(_, new CollectionType(RelationshipType())))
override def getGraphRelationships(node: PatternNode, realNode: Node): Seq[GraphRelationship] = {
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/symbols/AnyIterableType.scala
@@ -20,6 +20,6 @@
package org.neo4j.cypher.internal.symbols
object AnyIterableType {
- val instance = new IterableType(AnyType())
+ val instance = new CollectionType(AnyType())
def apply() = instance
}
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/symbols/AnyType.scala
@@ -55,7 +55,7 @@ class AnyType {
def isAssignableFrom(other: AnyType): Boolean = this.getClass.isAssignableFrom(other.getClass)
- override def toString: String = this.getClass.getSimpleName
+ override def toString: String = "Any"
}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/BooleanType.scala
@@ -25,4 +25,6 @@ object BooleanType {
def apply() = instance
}
-class BooleanType extends ScalarType
+class BooleanType extends ScalarType {
+ override def toString = "Boolean"
+}
View
10 .../neo4j/cypher/internal/symbols/IterableType.scala → ...eo4j/cypher/internal/symbols/CollectionType.scala
@@ -22,11 +22,15 @@ package org.neo4j.cypher.internal.symbols
import java.lang.String
-class IterableType(val iteratedType: AnyType) extends AnyType {
+class CollectionType(val iteratedType: AnyType) extends AnyType {
- override def toString: String = "IterableType<" + iteratedType + ">"
+ override def toString: String =
+ if (iteratedType.isInstanceOf[AnyType])
+ "Collection"
+ else
+ "Collection<" + iteratedType + ">"
- override def isAssignableFrom(other:AnyType):Boolean = super.isAssignableFrom(other) && iteratedType.isAssignableFrom(other.asInstanceOf[IterableType].iteratedType)
+ override def isAssignableFrom(other: AnyType): Boolean = super.isAssignableFrom(other) && iteratedType.isAssignableFrom(other.asInstanceOf[CollectionType].iteratedType)
}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/DoubleType.scala
@@ -25,7 +25,9 @@ object DoubleType {
def apply() = instance
}
-class DoubleType extends NumberType
+class DoubleType extends NumberType {
+ override def toString = "Double"
+}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/IntegerType.scala
@@ -26,7 +26,9 @@ object IntegerType {
def apply() = instance
}
-class IntegerType extends NumberType
+class IntegerType extends NumberType {
+ override def toString = "Integer"
+}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/LongType.scala
@@ -25,7 +25,9 @@ object LongType {
def apply() = instance
}
-class LongType extends NumberType
+class LongType extends NumberType {
+ override def toString = "Long"
+}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/MapType.scala
@@ -26,7 +26,9 @@ object MapType {
}
-class MapType extends AnyType
+class MapType extends AnyType {
+ override def toString = "Map"
+}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/NodeType.scala
@@ -26,7 +26,9 @@ object NodeType {
}
-class NodeType extends MapType
+class NodeType extends MapType {
+ override def toString = "Node"
+}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/NumberType.scala
@@ -26,7 +26,9 @@ object NumberType {
def apply(): NumberType = instance
}
-class NumberType extends ScalarType
+class NumberType extends ScalarType {
+ override def toString = "Number"
+}
View
6 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/PathType.scala
@@ -19,11 +19,7 @@
*/
package org.neo4j.cypher.internal.symbols
-/**
- * TODO
- */
-
object PathType {
- lazy val instance = new IterableType(MapType())
+ lazy val instance = new CollectionType(MapType())
def apply() = instance
}
View
4 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/RelationshipType.scala
@@ -26,7 +26,9 @@ object RelationshipType {
}
-class RelationshipType extends MapType
+class RelationshipType extends MapType {
+ override def toString = "Relationship"
+}
View
7 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/ScalarType.scala
@@ -19,9 +19,6 @@
*/
package org.neo4j.cypher.internal.symbols
-/**
- * TODO
- */
object ScalarType
{
val instance = new ScalarType()
@@ -29,7 +26,9 @@ object ScalarType
def apply() = instance
}
-class ScalarType extends AnyType
+class ScalarType extends AnyType {
+ override def toString = "Scalar"
+}
View
8 cypher/src/main/scala/org/neo4j/cypher/internal/symbols/StringType.scala
@@ -19,10 +19,6 @@
*/
package org.neo4j.cypher.internal.symbols
-/**
- * TODO
- */
-
object StringType
{
val instance = new StringType()
@@ -30,7 +26,9 @@ object StringType
def apply() = instance
}
-class StringType extends ScalarType
+class StringType extends ScalarType {
+ override def toString = "String"
+}
View
2  cypher/src/main/scala/org/neo4j/cypher/internal/symbols/SymbolTable.scala
@@ -48,7 +48,7 @@ class SymbolTable(val identifiers: Identifier*) {
case None => throwMissingKey(expected.name)
case Some(existing) =>
if (!(expected.typ.isAssignableFrom(existing.typ) || existing.typ.isAssignableFrom(expected.typ))) {
- throw new CypherTypeException("Expected `" + expected.name + "` to be a " + expected.typ + " but it was " + existing.typ)
+ throw new CypherTypeException("Expected `%s` to be a %s but it was a %s".format(expected.name, expected.typ, existing.typ))
}
}
}
View
2  cypher/src/test/scala/org/neo4j/cypher/CypherParserTest.scala
@@ -1464,7 +1464,7 @@ class CypherParserTest extends JUnitSuite with Assertions {
testFrom_1_8("start a = node(1) with a create (b {age : a.age * 2}) return b", q)
}
- @Test def variable_length_path_with_iterable_name() {
+ @Test def variable_length_path_with_collection_for_relationships() {
testAll("start a=node(0) match a -[r?*1..3]-> x return x",
Query.
start(NodeById("a", 0)).
View
20 cypher/src/test/scala/org/neo4j/cypher/ErrorMessagesTest.scala
@@ -196,6 +196,26 @@ class ErrorMessagesTest extends ExecutionEngineHelper with Assertions with Strin
"Unknown identifier `missing`")
}
+ @Test def create_with_identifier_already_existing() {
+ expectError(
+ "START a=node(0) CREATE a = {name:'foo'} RETURN a",
+ "Can't create `a` with properties here. It already exists in this context")
+ }
+
+ @Test def create_with_identifier_already_existing2() {
+ expectError(
+ "START a=node(0) CREATE UNIQUE (a {name:'foo'})-[:KNOWS]->() RETURN a",
+ "Can't create `a` with properties here. It already exists in this context")
+ }
+
+ @Test def type_of_identifier_is_wrong() {
+ expectError(
+ "start n=node(0) with [n] as users MATCH users-->messages RETURN messages",
+ "Expected `users` to be a Node but it was a Collection")
+ }
+
+
+
private def expectError[T <: CypherException](query: String, expectedError: String)(implicit manifest: Manifest[T]): T = {
val error = intercept[T](engine.execute(query).toList)
View
2  cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala
@@ -2212,6 +2212,4 @@ RETURN x0.name?
assert(result.startNode() === b)
assert(result.endNode() === a)
}
-
-
}
View
8 ...est/scala/org/neo4j/cypher/SematicErrorTest.scala → ...st/scala/org/neo4j/cypher/SemanticErrorTest.scala
@@ -22,7 +22,7 @@ package org.neo4j.cypher
import org.junit.Assert._
import org.junit.Test
-class SematicErrorTest extends ExecutionEngineHelper {
+class SemanticErrorTest extends ExecutionEngineHelper {
@Test def returnNodeThatsNotThere() {
expectedError("start x=node(0) return bar",
"""Unknown identifier `bar`.""")
@@ -45,12 +45,12 @@ class SematicErrorTest extends ExecutionEngineHelper {
@Test def cantUseTYPEOnNodes() {
expectedError("start r=node(0) return type(r)",
- "Expected `r` to be a RelationshipType but it was NodeType")
+ "Expected `r` to be a Relationship but it was a Node")
}
@Test def cantUseLENGTHOnNodes() {
expectedError("start n=node(0) return length(n)",
- "Expected `n` to be a IterableType<AnyType> but it was NodeType")
+ "Expected `n` to be a Collection but it was a Node")
}
@Test def cantReUseRelationshipIdentifier() {
@@ -60,7 +60,7 @@ class SematicErrorTest extends ExecutionEngineHelper {
@Test def shouldKnowNotToCompareStringsAndNumbers() {
expectedError("start a=node(0) where a.age =~ 13 return a",
- "13 expected to be of type StringType but it is of type NumberType")
+ "`13` expected to be a String but it is a Number")
}
@Test def shouldComplainAboutUnknownIdentifier() {
View
2  cypher/src/test/scala/org/neo4j/cypher/docgen/CreateTest.scala
@@ -92,7 +92,7 @@ class CreateTest extends DocumentingTestBase with StatisticsChecker {
)
}
- @Test def set_property_to_an_iterable() {
+ @Test def set_property_to_a_collection() {
val (aId, bId) = db.inTx(() => {
val a = db.createNode()
val b = db.createNode()
View
42 cypher/src/test/scala/org/neo4j/cypher/docgen/FunctionsTest.scala
@@ -40,17 +40,17 @@ class FunctionsTest extends DocumentingTestBase {
def section = "functions"
val common_arguments = List(
- "iterable" -> "An array property, or an iterable symbol, or an iterable function.",
+ "collection" -> "An expression that returns a collection",
"identifier" -> "This is the identifier that can be used from the predicate.",
- "predicate" -> "A predicate that is tested against all items in iterable."
+ "predicate" -> "A predicate that is tested against all items in the collection."
)
@Test def all() {
testThis(
title = "ALL",
- syntax = "ALL(identifier in iterable WHERE predicate)",
+ syntax = "ALL(identifier in collection WHERE predicate)",
arguments = common_arguments,
- text = """Tests whether a predicate holds for all element of this iterable collection.""",
+ text = """Tests whether a predicate holds for all element of this collection collection.""",
queryText = """start a=node(%A%), b=node(%D%) match p=a-[*1..3]->b where all(x in nodes(p) WHERE x.age > 30) return p""",
returns = """All nodes in the returned paths will have an `age` property of at least 30.""",
assertions = (p) => assertEquals(1, p.toSeq.length))
@@ -59,9 +59,9 @@ class FunctionsTest extends DocumentingTestBase {
@Test def any() {
testThis(
title = "ANY",
- syntax = "ANY(identifier in iterable WHERE predicate)",
+ syntax = "ANY(identifier in collection WHERE predicate)",
arguments = common_arguments,
- text = """Tests whether a predicate holds for at least one element of this iterable collection.""",
+ text = """Tests whether a predicate holds for at least one element in the collection.""",
queryText = """start a=node(%E%) where any(x in a.array WHERE x = "one") return a""",
returns = """All nodes in the returned paths has at least one `one` value set in the array property named `array`.""",
assertions = (p) => assertEquals(List(Map("a"->node("E"))), p.toList))
@@ -70,9 +70,9 @@ class FunctionsTest extends DocumentingTestBase {
@Test def none() {
testThis(
title = "NONE",
- syntax = "NONE(identifier in iterable WHERE predicate)",
+ syntax = "NONE(identifier in collection WHERE predicate)",
arguments = common_arguments,
- text = """Returns true if the predicate holds for no element in the iterable.""",
+ text = """Returns true if the predicate holds for no element in the collection.""",
queryText = """start n=node(%A%) match p=n-[*1..3]->b where NONE(x in nodes(p) WHERE x.age = 25) return p""",
returns = """No nodes in the returned paths has a `age` property set to `25`.""",
assertions = (p) => assertEquals(2, p.toSeq.length))
@@ -81,9 +81,9 @@ class FunctionsTest extends DocumentingTestBase {
@Test def single() {
testThis(
title = "SINGLE",
- syntax = "SINGLE(identifier in iterable WHERE predicate)",
+ syntax = "SINGLE(identifier in collection WHERE predicate)",
arguments = common_arguments,
- text = """Returns true if the predicate holds for exactly one of the elements in the iterable.""",
+ text = """Returns true if the predicate holds for exactly one of the elements in the collection.""",
queryText = """start n=node(%A%) match p=n-->b where SINGLE(var in nodes(p) WHERE var.eyes = "blue") return p""",
returns = """Exactly one node in every returned path will have the `eyes` property set to `"blue"`.""",
assertions = (p) => assertEquals(1, p.toSeq.length))
@@ -103,9 +103,9 @@ class FunctionsTest extends DocumentingTestBase {
@Test def length() {
testThis(
title = "LENGTH",
- syntax = "LENGTH( iterable )",
- arguments = List("iterable" -> "An iterable, value or function call."),
- text = """To return or filter on the length of a path, use the `LENGTH()` function.""",
+ syntax = "LENGTH( collection )",
+ arguments = List("collection" -> "An expression that returns a collection"),
+ text = """To return or filter on the length of a collection, use the `LENGTH()` function.""",
queryText = """start a=node(%A%) match p=a-->b-->c return length(p)""",
returns = """The length of the path `p` is returned by the query.""",
assertions = (p) => assertEquals(2, p.columnAs[Int]("length(p)").toList.head))
@@ -114,15 +114,15 @@ class FunctionsTest extends DocumentingTestBase {
@Test def extract() {
testThis(
title = "EXTRACT",
- syntax = "EXTRACT( identifier in iterable : expression )",
+ syntax = "EXTRACT( identifier in collection : expression )",
arguments = List(
- "iterable" -> "An array property, or an iterable identifier, or an iterable function.",
+ "collection" -> "An expression that returns a collection",
"identifier" -> "The closure will have an identifier introduced in it's context. Here you decide which identifier to use.",
- "expression" -> "This expression will run once per value in the iterable, and produces the result iterable."
+ "expression" -> "This expression will run once per value in the collection, and produces the result collection."
),
- text = """To return a single property, or the value of a function from an iterable of nodes or relationships,
- you can use `EXTRACT`. It will go through all enitities in the iterable, and run an expression, and return the results
- in an iterable with these values. It works like the `map` method in functional languages such as Lisp and Scala.""",
+ text = """To return a single property, or the value of a function from a collection of nodes or relationships,
+ you can use `EXTRACT`. It will go through a collection, run an expression on every element, and return the results
+ in an collection with these values. It works like the `map` method in functional languages such as Lisp and Scala.""",
queryText = """start a=node(%A%), b=node(%B%), c=node(%D%) match p=a-->b-->c return extract(n in nodes(p) : n.age)""",
returns = """The age property of all nodes in the path are returned.""",
assertions = (p) => assertEquals(List(Map("extract(n in nodes(p) : n.age)" -> List(38, 25, 54))), p.toList))
@@ -173,9 +173,9 @@ class FunctionsTest extends DocumentingTestBase {
@Test def filter() {
testThis(
title = "FILTER",
- syntax = "FILTER(identifier in iterable : predicate)",
+ syntax = "FILTER(identifier in collection : predicate)",
arguments = common_arguments,
- text = "`FILTER` returns all the elements in an iterable that comply to a predicate.",
+ text = "`FILTER` returns all the elements in a collection that comply to a predicate.",
queryText = """start a=node(%E%) return a.array, filter(x in a.array : length(x) = 3)""",
returns = "This returns the property named `array` and a list of values in it, which have the length `3`.",
assertions = (p) => {
View
3  cypher/src/test/scala/org/neo4j/cypher/docgen/MatchTest.scala
@@ -143,7 +143,8 @@ class MatchTest extends DocumentingTestBase {
@Test def variableLengthPathWithIterableRels() {
testQuery(
title = "Relationship identifier in variable length relationships",
- text = """When the connection between two nodes is of variable length, a relationship identifier becomes an iterable of relationships.""",
+ text = "When the connection between two nodes is of variable length, " +
+ "a relationship identifier becomes an collection of relationships.",
queryText = """start a=node(%A%), x=node(%E%, %B%) match a-[r:KNOWS*1..3]->x return r""",
returns = "The query returns the relationships, if there is a path between 1 and 3 relationships away.",
assertions = (p) => assertEquals(2, p.toList.size)
View
4 cypher/src/test/scala/org/neo4j/cypher/internal/commands/ExtractTest.scala
@@ -29,10 +29,10 @@ class ExtractTest extends Assertions {
val l = Seq("x", "xxx", "xx")
val expression = LengthFunction(Entity("n"))
- val iterable = Entity("l")
+ val collection = Entity("l")
val m = Map("l" -> l)
- val extract = ExtractFunction(iterable, "n", expression)
+ val extract = ExtractFunction(collection, "n", expression)
assert(extract.apply(m) === Seq(1, 3, 2))
}
View
4 cypher/src/test/scala/org/neo4j/cypher/internal/symbols/SymbolTableTest.scala
@@ -45,8 +45,8 @@ class SymbolTableTest extends JUnitSuite {
}
@Test def givenSymbolTableWithIterableOfStringWhenAskForIterableOfAnyThenReturn() {
- val symbols = new SymbolTable(Identifier("x", new IterableType(StringType())))
- symbols.assertHas(Identifier("x", new IterableType(AnyType())))
+ val symbols = new SymbolTable(Identifier("x", new CollectionType(StringType())))
+ symbols.assertHas(Identifier("x", new CollectionType(AnyType())))
}
@Test def givenSymbolTableWithStringIdentifierWhenMergedWithNumberIdentifierThenContainsBoth() {
Please sign in to comment.
Something went wrong with that request. Please try again.