Permalink
Browse files

CREATE and RELATE can assign paths to identifiers

  • Loading branch information...
1 parent c8f09ec commit 676299d7aa8afc2a27e16da7340491c3ae3b1c95 @systay committed Jun 10, 2012
Showing with 313 additions and 173 deletions.
  1. +1 −1 cypher/src/main/scala/org/neo4j/cypher/internal/ReattachAliasedExpressions.scala
  2. +1 −1 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Expression.scala
  3. +30 −15 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Query.scala
  4. +9 −9 cypher/src/main/scala/org/neo4j/cypher/internal/commands/QueryBuilder.scala
  5. +6 −6 cypher/src/main/scala/org/neo4j/cypher/internal/executionplan/PartiallySolvedQuery.scala
  6. +4 −6 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/CypherParserImpl.scala
  7. +4 −4 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/MatchClause.scala
  8. +3 −3 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/OrderByClause.scala
  9. +4 −5 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/ReturnClause.scala
  10. +1 −1 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_6/StartClause.scala
  11. +4 −6 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/CypherParserImpl.scala
  12. +6 −6 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/MatchClause.scala
  13. +3 −3 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/OrderByClause.scala
  14. +4 −5 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/ReturnClause.scala
  15. +1 −1 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_7/StartClause.scala
  16. +49 −33 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/CypherParserImpl.scala
  17. +4 −5 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Expressions.scala
  18. +9 −13 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/MatchClause.scala
  19. +3 −3 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/OrderByClause.scala
  20. +30 −12 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/ParserPattern.scala
  21. +6 −6 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/ReturnClause.scala
  22. +29 −8 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/StartClause.scala
  23. +54 −19 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Updates.scala
  24. +3 −1 cypher/src/main/scala/org/neo4j/cypher/internal/pipes/MatchPipe.scala
  25. +35 −1 cypher/src/test/scala/org/neo4j/cypher/CypherParserTest.scala
  26. +10 −0 cypher/src/test/scala/org/neo4j/cypher/ExecutionEngineTest.scala
@@ -28,7 +28,7 @@ so the user can either use the raw expression, or the alias
*/
object ReattachAliasedExpressions {
def apply(q: Query): Query = {
- val newSort = q.sort.map(oldSort => Sort(oldSort.sortItems.map(rewrite(q.returns.returnItems)): _*))
+ val newSort = q.sort.map(rewrite(q.returns.returnItems))
q.copy(sort = newSort)
}
@@ -225,7 +225,7 @@ case class Property(entity: String, property: String) extends CastableExpression
}
case class Entity(entityName: String) extends CastableExpression {
- def compute(m: Map[String, Any]): Any = m.getOrElse(entityName, throw new NotFoundException)
+ def compute(m: Map[String, Any]): Any = m.getOrElse(entityName, throw new NotFoundException("Failed to find `" + entityName + "`"))
val identifier: Identifier = Identifier(entityName, AnyType())
override def toString(): String = entityName
def declareDependencies(extectedType: AnyType): Seq[Identifier] = Seq(Identifier(entityName, extectedType))
@@ -29,14 +29,14 @@ object Query {
}
case class Query(returns: Return,
- start: Start,
+ start: Seq[StartItem],
updatedCommands:Seq[UpdateAction],
- matching: Option[Match],
+ matching: Seq[Pattern],
where: Option[Predicate],
- aggregation: Option[Aggregation],
- sort: Option[Sort],
+ aggregation: Option[Seq[AggregationExpression]],
+ sort: Seq[SortItem],
slice: Option[Slice],
- namedPaths: Option[NamedPaths],
+ namedPaths: Seq[NamedPath],
tail:Option[Query] = None,
queryString: String = "") {
override def equals(p1: Any): Boolean =
@@ -57,18 +57,33 @@ case class Query(returns: Return,
namedPaths == other.namedPaths &&
tail == other.tail
}
+
+ override def toString: String =
+"""
+start : %s
+updates: %s
+match : %s
+paths : %s
+where : %s
+aggreg : %s
+return : %s
+order : %s
+slice : %s
+next : %s
+""".format(
+ start.mkString,
+ updatedCommands.mkString,
+ matching,
+ namedPaths,
+ where,
+ aggregation,
+ returns.returnItems.mkString,
+ sort,
+ slice,
+ tail
+)
}
case class Return(columns: List[String], returnItems: ReturnColumn*)
-case class Start(startItems: StartItem*)
-
-case class Match(patterns: Pattern*)
-
-case class NamedPaths(paths: NamedPath*)
-
-case class Aggregation(aggregationItems: AggregationExpression*)
-
-case class Sort(sortItems: SortItem*)
-
case class Slice(from: Option[Expression], limit: Option[Expression])
@@ -23,18 +23,18 @@ import org.neo4j.cypher.internal.mutation.UpdateAction
class QueryBuilder(startItems: Seq[StartItem]) {
var updates = Seq[UpdateAction]()
- var matching: Option[Match] = None
+ var matching: Seq[Pattern] = Seq()
var where: Option[Predicate] = None
- var aggregation: Option[Aggregation] = None
- var orderBy: Option[Sort] = None
+ var aggregation: Option[Seq[AggregationExpression]] = None
+ var orderBy: Seq[SortItem] = Seq()
var skip: Option[Expression] = None
var limit: Option[Expression] = None
- var namedPaths: Option[NamedPaths] = None
+ var namedPaths: Seq[NamedPath] = Seq()
var tail: Option[Query] = None
var columns: Seq[ReturnColumn] => List[String] = (returnItems) => returnItems.map(_.name).toList
def matches(patterns: Pattern*): QueryBuilder = store {
- matching = Some(Match(patterns: _*))
+ matching = patterns
}
def updates(cmds: UpdateAction*): QueryBuilder = store {
@@ -46,11 +46,11 @@ class QueryBuilder(startItems: Seq[StartItem]) {
}
def aggregation(aggregationItems: AggregationExpression*): QueryBuilder = store {
- aggregation = Some(Aggregation(aggregationItems: _*))
+ aggregation = Some(aggregationItems)
}
def orderBy(sortItems: SortItem*): QueryBuilder = store {
- orderBy = Some(Sort(sortItems: _*))
+ orderBy = sortItems
}
def skip(skipTo: Int): QueryBuilder = store {
@@ -70,7 +70,7 @@ class QueryBuilder(startItems: Seq[StartItem]) {
}
def namedPaths(paths: NamedPath*): QueryBuilder = store {
- namedPaths = Some(NamedPaths(paths: _*))
+ namedPaths = paths
}
def columns(columnList: String*): QueryBuilder = store {
@@ -92,5 +92,5 @@ class QueryBuilder(startItems: Seq[StartItem]) {
}
def returns(returnItems: ReturnColumn*): Query =
- Query(Return(columns(returnItems), returnItems: _*), Start(startItems: _*), updates, matching, where, aggregation, orderBy, slice, namedPaths, tail)
+ Query(Return(columns(returnItems), returnItems: _*), startItems, updates, matching, where, aggregation, orderBy, slice, namedPaths, tail)
}
@@ -31,19 +31,19 @@ object PartiallySolvedQuery {
// Creates a fully unsolved query
def apply(q: Query): PartiallySolvedQuery = {
- val patterns = q.matching.toSeq.flatMap(_.patterns.map(Unsolved(_))) ++
- q.namedPaths.toSeq.flatMap(_.paths.flatMap(_.pathPattern.map(Unsolved(_))))
+ val patterns = q.matching.map(Unsolved(_)) ++
+ q.namedPaths.flatMap(_.pathPattern.map(Unsolved(_)))
new PartiallySolvedQuery(
returns = q.returns.returnItems.map(Unsolved(_)),
- start = q.start.startItems.map(Unsolved(_)),
+ start = q.start.map(Unsolved(_)),
updates = q.updatedCommands.map(Unsolved(_)),
patterns = patterns,
where = q.where.toSeq.flatMap(_.atoms.map(Unsolved(_))),
- aggregation = q.aggregation.toSeq.flatMap(_.aggregationItems.map(Unsolved(_))),
- sort = q.sort.toSeq.flatMap(_.sortItems.map(Unsolved(_))),
+ aggregation = q.aggregation.toSeq.flatten.map(Unsolved(_)),
+ sort = q.sort.map(Unsolved(_)),
slice = q.slice.toSeq.map(Unsolved(_)),
- namedPaths = q.namedPaths.toSeq.flatMap(_.paths.map(Unsolved(_))),
+ namedPaths = q.namedPaths.map(Unsolved(_)),
aggregateQuery = if (q.aggregation.isDefined)
Unsolved(true)
else
@@ -44,14 +44,12 @@ with ActualParser {
case (s, l) => Some(Slice(s, l))
}
- val (pattern: Option[Match], namedPaths: Option[NamedPaths]) = matching match {
- case Some((p, NamedPaths())) => (Some(p), None)
- case Some((Match(), nP)) => (None, Some(nP))
- case Some((p, nP)) => (Some(p), Some(nP))
- case None => (None, None)
+ val (pattern: Seq[Pattern], namedPaths: Seq[NamedPath]) = matching match {
+ case Some((a,b)) => (a,b)
+ case None => (Seq(), Seq())
}
- (queryText: String) => Query(returns._1, start, Seq(), pattern, where, returns._2, order, slice, namedPaths, None, queryText)
+ (queryText: String) => Query(returns._1, start, Seq(), pattern, where, returns._2, order.toSeq.flatten, slice, namedPaths, None, queryText)
}
}
@@ -26,16 +26,16 @@ import org.neo4j.cypher.internal.commands._
trait MatchClause extends Base {
val namer = new NodeNamer
- def matching: Parser[(Match, NamedPaths)] =
+ def matching: Parser[(Seq[Pattern], Seq[NamedPath])] =
correctMatch |
ignoreCase("match") ~> failure("invalid pattern")
def correctMatch = ignoreCase("match") ~> comaList(path) ^^ {
case matching => {
- val unamedPaths: List[Pattern] = matching.filter(_.isInstanceOf[List[Pattern]]).map(_.asInstanceOf[List[Pattern]]).flatten ++ matching.filter(_.isInstanceOf[Pattern]).map(_.asInstanceOf[Pattern])
- val namedPaths: List[NamedPath] = matching.filter(_.isInstanceOf[NamedPath]).map(_.asInstanceOf[NamedPath])
+ val unamedPaths: Seq[Pattern] = matching.filter(_.isInstanceOf[List[Pattern]]).map(_.asInstanceOf[List[Pattern]]).flatten ++ matching.filter(_.isInstanceOf[Pattern]).map(_.asInstanceOf[Pattern])
+ val namedPaths: Seq[NamedPath] = matching.filter(_.isInstanceOf[NamedPath]).map(_.asInstanceOf[NamedPath])
- (Match(unamedPaths: _*), NamedPaths(namedPaths: _*))
+ (unamedPaths, namedPaths)
}
}
@@ -19,7 +19,7 @@
*/
package org.neo4j.cypher.internal.parser.v1_6
-import org.neo4j.cypher.internal.commands.{SortItem, Sort}
+import org.neo4j.cypher.internal.commands.SortItem
trait OrderByClause extends Base with ReturnItems {
@@ -34,8 +34,8 @@ trait OrderByClause extends Base with ReturnItems {
def sortItem :Parser[SortItem] = (aggregateExpression | expression) ~ ascOrDesc ^^ { case expression ~ ascDesc => SortItem(expression, ascDesc) }
- def order: Parser[Sort] =
- (ignoreCase("order by") ~> comaList(sortItem) ^^ { case items => Sort(items:_*) }
+ def order: Parser[Seq[SortItem]] =
+ (ignoreCase("order by") ~> comaList(sortItem)
| ignoreCase("order") ~> failure("expected by"))
}
@@ -44,12 +44,12 @@ trait ReturnClause extends Base with ReturnItems {
}
- def returnsClause: Parser[(Return, Option[Aggregation])] = ignoreCase("return") ~> opt(ignoreCase("distinct")) ~ comaList(column) ^^ {
+ def returnsClause: Parser[(Return, Option[Seq[AggregationExpression]])] = ignoreCase("return") ~> opt(ignoreCase("distinct")) ~ comaList(column) ^^ {
case distinct ~ returnItems => {
val columnName = returnItems.map(_.columnName).toList
- val none: Option[Aggregation] = distinct match {
- case Some(x) => Some(Aggregation())
+ val none: Option[Seq[AggregationExpression]] = distinct match {
+ case Some(x) => Some(Seq())
case None => None
}
@@ -59,10 +59,9 @@ trait ReturnClause extends Base with ReturnItems {
val aggregation = aggregationExpressions match {
case List() => none
- case _ => Some(Aggregation(aggregationExpressions: _*))
+ case _ => Some(aggregationExpressions)
}
-
(Return(columnName, returnItems: _*), aggregation)
}
}
@@ -23,7 +23,7 @@ import org.neo4j.cypher.internal.commands._
trait StartClause extends Base {
- def start: Parser[Start] = ignoreCase("start") ~> comaList(startBit) ^^ (x => Start(x: _*)) | failure("expected 'START'")
+ def start: Parser[Seq[StartItem]] = ignoreCase("start") ~> comaList(startBit) | failure("expected 'START'")
def startBit =
(identity ~ "=" ~ lookup ^^ { case id ~ "=" ~ l => l(id) }
@@ -41,18 +41,16 @@ with ActualParser {
case (s, l) => Some(Slice(s, l))
}
- val (pattern: Option[Match], namedPaths: Option[NamedPaths]) = matching match {
- case Some((p, NamedPaths())) => (Some(p), None)
- case Some((Match(), nP)) => (None, Some(nP))
- case Some((p, nP)) => (Some(p), Some(nP))
- case None => (None, None)
+ val (pattern: Seq[Pattern], namedPaths: Seq[NamedPath]) = matching match {
+ case Some((a,b)) => (a,b)
+ case None => (Seq(),Seq())
}
where match {
case Some(w) => if(w.exists(_.isInstanceOf[AggregationExpression])) throw new SyntaxException("Can't use aggregate functions in the WHERE clause. Use WITH to aggregate and then filter on it.")
case _ =>
}
- (queryText: String) => Query(returns._1, start, Seq(), pattern, where, returns._2, order, slice, namedPaths, None, queryText)
+ (queryText: String) => Query(returns._1, start, Seq(), pattern, where, returns._2, order.toSeq.flatten, slice, namedPaths, None, queryText)
}
}
@@ -26,17 +26,17 @@ import org.neo4j.cypher.internal.commands._
trait MatchClause extends Base with Expressions {
val namer = new NodeNamer
- def matching: Parser[(Match, NamedPaths)] =
+ def matching: Parser[(Seq[Pattern], Seq[NamedPath])] =
correctMatch |
ignoreCase("match") ~> failure("invalid pattern")
def correctMatch = ignoreCase("match") ~> comaList(path) ^^ {
- case matching => {
- val unamedPaths: List[Pattern] = matching.filter(_.isInstanceOf[List[Pattern]]).map(_.asInstanceOf[List[Pattern]]).flatten ++ matching.filter(_.isInstanceOf[Pattern]).map(_.asInstanceOf[Pattern])
- val namedPaths: List[NamedPath] = matching.filter(_.isInstanceOf[NamedPath]).map(_.asInstanceOf[NamedPath])
+ case matching =>
+ val unamedPaths: Seq[Pattern] = matching.filter(_.isInstanceOf[List[Pattern]]).map(_.asInstanceOf[List[Pattern]]).flatten ++ matching.filter(_.isInstanceOf[Pattern]).map(_.asInstanceOf[Pattern])
+ val namedPaths: Seq[NamedPath] = matching.filter(_.isInstanceOf[NamedPath]).map(_.asInstanceOf[NamedPath])
+
+ (unamedPaths, namedPaths)
- (Match(unamedPaths: _*), NamedPaths(namedPaths: _*))
- }
}
def path: Parser[Any] =
@@ -19,7 +19,7 @@
*/
package org.neo4j.cypher.internal.parser.v1_7
-import org.neo4j.cypher.internal.commands.{Sort, SortItem}
+import org.neo4j.cypher.internal.commands.SortItem
trait OrderByClause extends Base with Expressions {
@@ -34,8 +34,8 @@ trait OrderByClause extends Base with Expressions {
def sortItem :Parser[SortItem] = expression ~ ascOrDesc ^^ { case expression ~ reverse => SortItem(expression, reverse) }
- def order: Parser[Sort] =
- (ignoreCase("order by") ~> comaList(sortItem) ^^ { case items => Sort(items:_*) }
+ def order: Parser[Seq[SortItem]] =
+ (ignoreCase("order by") ~> comaList(sortItem)
| ignoreCase("order") ~> failure("expected by"))
}
@@ -42,12 +42,12 @@ trait ReturnClause extends Base with Expressions {
case col ~ None => col
}
- def returnsClause: Parser[(Return, Option[Aggregation])] = ignoreCase("return") ~> opt(ignoreCase("distinct")) ~ comaList(column) ^^ {
+ def returnsClause: Parser[(Return, Option[Seq[AggregationExpression]])] = ignoreCase("return") ~> opt(ignoreCase("distinct")) ~ comaList(column) ^^ {
case distinct ~ returnItems => {
val columnName = returnItems.map(_.columnName).toList
- val none: Option[Aggregation] = distinct match {
- case Some(x) => Some(Aggregation())
+ val none = distinct match {
+ case Some(x) => Some(Seq())
case None => None
}
@@ -57,10 +57,9 @@ trait ReturnClause extends Base with Expressions {
val aggregation = aggregationExpressions match {
case List() => none
- case _ => Some(Aggregation(aggregationExpressions: _*))
+ case _ => Some(aggregationExpressions)
}
-
(Return(columnName, returnItems: _*), aggregation)
}
}
@@ -23,7 +23,7 @@ import org.neo4j.cypher.internal.commands._
trait StartClause extends Base {
- def start: Parser[Start] = ignoreCase("start") ~> comaList(startBit) ^^ (x => Start(x: _*)) | failure("expected 'START'")
+ def start: Parser[Seq[StartItem]] = ignoreCase("start") ~> comaList(startBit) | failure("expected 'START'")
def startBit =
(identity ~ "=" ~ lookup ^^ { case id ~ "=" ~ l => l(id) }
Oops, something went wrong.

0 comments on commit 676299d

Please sign in to comment.