Permalink
Browse files

Renamed RELATE to CREATE UNIQUE

  • Loading branch information...
1 parent 1728938 commit c7dbbb929abfef600266a20f065d760e7a1fff2e @systay committed Jul 19, 2012
Showing with 273 additions and 225 deletions.
  1. +1 −0 cypher/CHANGES.txt
  2. +2 −2 cypher/src/docs/dev/index.txt
  3. +21 −0 cypher/src/docs/dev/ql/create-unique/index.txt
  4. +2 −1 cypher/src/docs/dev/ql/foreach/index.txt
  5. +0 −20 cypher/src/docs/dev/ql/relate/index.txt
  6. +1 −1 cypher/src/main/scala/org/neo4j/cypher/CypherException.scala
  7. +2 −3 cypher/src/main/scala/org/neo4j/cypher/internal/commands/Query.scala
  8. +11 −13 cypher/src/main/scala/org/neo4j/cypher/internal/commands/StartItem.scala
  9. +2 −0 cypher/src/main/scala/org/neo4j/cypher/internal/executionplan/builders/QueryToken.scala
  10. +27 −4 cypher/src/main/scala/org/neo4j/cypher/internal/executionplan/builders/UpdateActionBuilder.scala
  11. +17 −17 ...src/main/scala/org/neo4j/cypher/internal/mutation/{RelateAction.scala → CreateUniqueAction.scala}
  12. +12 −12 cypher/src/main/scala/org/neo4j/cypher/internal/mutation/{RelateLink.scala → UniqueLink.scala}
  13. +1 −1 cypher/src/main/scala/org/neo4j/cypher/internal/mutation/UpdateAction.scala
  14. +2 −0 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Base.scala
  15. +69 −0 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/CreateUnique.scala
  16. +6 −4 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/StartClause.scala
  17. +1 −42 cypher/src/main/scala/org/neo4j/cypher/internal/parser/v1_8/Updates.scala
  18. +24 −32 ...src/test/scala/org/neo4j/cypher/{RelateAcceptanceTests.scala → CreateUniqueAcceptanceTests.scala}
  19. +24 −24 cypher/src/test/scala/org/neo4j/cypher/CypherParserTest.scala
  20. +2 −2 cypher/src/test/scala/org/neo4j/cypher/ErrorMessagesTest.scala
  21. +9 −9 cypher/src/test/scala/org/neo4j/cypher/MutatingIntegrationTests.scala
  22. +1 −1 cypher/src/test/scala/org/neo4j/cypher/docgen/CreateTest.scala
  23. +9 −9 cypher/src/test/scala/org/neo4j/cypher/docgen/{RelateTest.scala → CreateUniqueTest.scala}
  24. +19 −20 cypher/src/test/scala/org/neo4j/cypher/docgen/PatternTest.scala
  25. +2 −2 cypher/src/test/scala/org/neo4j/cypher/docgen/cookbook/CoFavoritedPlacesTest.scala
  26. +6 −6 ...a/org/neo4j/cypher/internal/mutation/{RelateUniqueTest.scala → DoubleCheckCreateUniqueTest.scala}
View
@@ -1,6 +1,7 @@
1.8
--------------------
o Added escape characters to string literals
+o Renamed `RELATE` to `CREATE UNIQUE`
1.8.M06 (2012-07-06)
--------------------
@@ -66,15 +66,15 @@ include::ql/create/index.txt[]
:leveloffset: 2
-include::ql/delete/index.txt[]
+include::ql/create-unique/index.txt[]
:leveloffset: 2
include::ql/set/index.txt[]
:leveloffset: 2
-include::ql/relate/index.txt[]
+include::ql/delete/index.txt[]
:leveloffset: 2
@@ -0,0 +1,21 @@
+[[query-create-unique]]
+Create Unique
+=============
++CREATE UNIQUE+ is in the middle of +MATCH+ and +CREATE+ -- it will match what it can, and create what is missing.
++CREATE UNIQUE+ will always make the least change possible to the graph -- if it can use parts of the existing graph,
+it will.
+
+Another difference to +MATCH+ is that +CREATE UNIQUE+ assumes the pattern to be unique. If multiple matching subgraphs
+are found an exception will be thrown.
+
+[TIP]
+In the +CREATE UNIQUE+ clause, patterns are used a lot.
+Read <<introduction-pattern>> for an introduction.
+
+:leveloffset: 2
+
+include::create-relationship-if-it-is-missing.txt[]
+include::create-node-if-missing.txt[]
+include::create-nodes-with-values.txt[]
+include::create-relationship-with-values.txt[]
+include::describe-complex-pattern.txt[]
@@ -8,7 +8,8 @@ The identifier context inside of the foreach parenthesis is separate from the on
node identifier inside of a `FOREACH`, you will not be able to use it outside of the foreach statement, unless you
match to find it.
-Inside of the `FOREACH` parenthesis, you can do any updating commands -- `CREATE`, `DELETE`, `RELATE`, and `FOREACH`.
+Inside of the `FOREACH` parenthesis, you can do any updating commands -- `CREATE`, `CREATE UNIQUE`, `DELETE`,
+and `FOREACH`.
:leveloffset: 2
@@ -1,20 +0,0 @@
-[[query-relate]]
-Relate
-======
-+RELATE+ is in the middle of +MATCH+ and +CREATE+ -- it will match what it can, and create what is missing. +RELATE+
-will always make the least change possible to the graph -- if it can use parts of the existing graph, it will.
-
-Another difference to +MATCH+ is that +RELATE+ assumes the pattern to be unique. If multiple matching subgraphs are
-found an exception will be thrown.
-
-[TIP]
-In the `RELATE` clause, patterns are used a lot.
-Read <<introduction-pattern>> for an introduction.
-
-:leveloffset: 2
-
-include::create-relationship-if-it-is-missing.txt[]
-include::create-node-if-missing.txt[]
-include::create-nodes-with-values.txt[]
-include::create-relationship-with-values.txt[]
-include::describe-complex-pattern.txt[]
@@ -25,7 +25,7 @@ abstract class CypherException(message: String, cause: Throwable) extends Runtim
def this(message:String) = this(message, null)
}
-class RelatePathNotUnique(message:String) extends CypherException(message)
+class UniquePathNotUniqueException(message:String) extends CypherException(message)
class EntityNotFoundException(message:String, cause:Throwable=null) extends CypherException(message, cause)
@@ -19,13 +19,12 @@
*/
package org.neo4j.cypher.internal.commands
-import org.neo4j.cypher.internal.mutation.{RelateAction, RelateLink, UpdateAction}
-
+import org.neo4j.cypher.internal.mutation.{CreateUniqueAction, UniqueLink, UpdateAction}
object Query {
def start(startItems: StartItem*) = new QueryBuilder(startItems)
def updates(cmds:UpdateAction*) = new QueryBuilder(Seq()).updates(cmds:_*)
- def relate(cmds:RelateLink*) = new QueryBuilder(Seq()).updates(RelateAction(cmds:_*))
+ def unique(cmds:UniqueLink*) = new QueryBuilder(Seq(CreateUniqueAction(cmds:_*)))
}
case class Query(returns: Return,
@@ -27,32 +27,30 @@ import org.neo4j.graphdb.{DynamicRelationshipType, Node}
import org.neo4j.cypher.internal.symbols._
-abstract sealed class StartItem(val identifierName: String) {
+abstract class StartItem(val identifierName: String) {
def mutating = false
}
-abstract class RelationshipStartItem(id: String) extends StartItem(id)
+case class RelationshipById(varName: String, expression: Expression) extends StartItem(varName)
-abstract class NodeStartItem(id: String) extends StartItem(id)
+case class RelationshipByIndex(varName: String, idxName: String, key: Expression, expression: Expression) extends StartItem(varName)
-case class RelationshipById(varName: String, expression: Expression) extends RelationshipStartItem(varName)
+case class RelationshipByIndexQuery(varName: String, idxName: String, query: Expression) extends StartItem(varName)
-case class RelationshipByIndex(varName: String, idxName: String, key: Expression, expression: Expression) extends RelationshipStartItem(varName)
+case class NodeByIndex(varName: String, idxName: String, key: Expression, expression: Expression) extends StartItem(varName)
-case class RelationshipByIndexQuery(varName: String, idxName: String, query: Expression) extends RelationshipStartItem(varName)
+case class NodeByIndexQuery(varName: String, idxName: String, query: Expression) extends StartItem(varName)
-case class NodeByIndex(varName: String, idxName: String, key: Expression, expression: Expression) extends NodeStartItem(varName)
+case class NodeById(varName: String, expression: Expression) extends StartItem(varName)
-case class NodeByIndexQuery(varName: String, idxName: String, query: Expression) extends NodeStartItem(varName)
+case class AllNodes(columnName: String) extends StartItem(columnName)
-case class NodeById(varName: String, expression: Expression) extends NodeStartItem(varName)
+case class AllRelationships(columnName: String) extends StartItem(columnName)
-case class AllNodes(columnName: String) extends NodeStartItem(columnName)
-case class AllRelationships(columnName: String) extends RelationshipStartItem(columnName)
case class CreateNodeStartItem(key: String, props: Map[String, Expression])
- extends NodeStartItem(key)
+ extends StartItem(key)
with Mutator
with UpdateAction
with GraphElementPropertyFunctions
@@ -88,7 +86,7 @@ case class CreateNodeStartItem(key: String, props: Map[String, Expression])
}
case class CreateRelationshipStartItem(key: String, from: (Expression, Map[String, Expression]), to: (Expression, Map[String, Expression]), typ: String, props: Map[String, Expression])
- extends NodeStartItem(key)
+ extends StartItem(key)
with Mutator
with UpdateAction
with GraphElementPropertyFunctions {
@@ -25,6 +25,8 @@ abstract sealed class QueryToken[T](val token: T) {
def unsolved = !solved
def solve: QueryToken[T] = Solved(token)
+
+ def map[B](f : T => B):QueryToken[B] = if (solved) Solved(f(token)) else Unsolved(f(token))
}
case class Solved[T](t: T) extends QueryToken[T](t) {
@@ -21,7 +21,9 @@ package org.neo4j.cypher.internal.executionplan.builders
import org.neo4j.cypher.internal.executionplan.{ExecutionPlanInProgress, PlanBuilder}
import org.neo4j.graphdb.GraphDatabaseService
-import org.neo4j.cypher.internal.pipes.{ExecuteUpdateCommandsPipe, TransactionStartPipe}
+import org.neo4j.cypher.internal.pipes.{Pipe, ExecuteUpdateCommandsPipe, TransactionStartPipe}
+import org.neo4j.cypher.internal.mutation.{CreateUniqueAction, UpdateAction}
+import org.neo4j.cypher.internal.commands.StartItem
class UpdateActionBuilder(db: GraphDatabaseService) extends PlanBuilder {
def apply(plan: ExecutionPlanInProgress) = {
@@ -32,22 +34,43 @@ class UpdateActionBuilder(db: GraphDatabaseService) extends PlanBuilder {
new TransactionStartPipe(plan.pipe, db)
}
- val commands = plan.query.updates.filter(cmd => cmd.unsolved && p.symbols.satisfies(cmd.token.dependencies))
+ val updateCmds: Seq[QueryToken[UpdateAction]] = extractValidUpdateActions(plan, p)
+ val startItems: Seq[QueryToken[StartItem]] = extractValidStartItems(plan, p)
+ val startCmds = startItems.map(_.map(_.asInstanceOf[UpdateAction]))
+ val commands = updateCmds ++ startCmds
+
+
val resultPipe = new ExecuteUpdateCommandsPipe(p, db, commands.map(_.token))
plan.copy(
containsTransaction = true,
- query = plan.query.copy(updates = plan.query.updates.filterNot(commands.contains) ++ commands.map(_.solve)),
+ query = plan.query.copy(
+ updates = plan.query.updates.filterNot(updateCmds.contains) ++ updateCmds.map(_.solve),
+ start = plan.query.start.filterNot(startItems.contains) ++ startItems.map(_.solve)),
pipe = resultPipe
)
}
- def canWorkWith(plan: ExecutionPlanInProgress) = plan.query.updates.exists(cmd => cmd.unsolved && plan.pipe.symbols.satisfies(cmd.token.dependencies))
+
+ private def extractValidStartItems(plan: ExecutionPlanInProgress, p: Pipe): Seq[QueryToken[StartItem]] = {
+ plan.query.start.filter(cmd => cmd.unsolved && cmd.token.isInstanceOf[UpdateAction] && p.symbols.satisfies(cmd.token.asInstanceOf[UpdateAction].dependencies))
+ }
+
+ private def extractValidUpdateActions(plan: ExecutionPlanInProgress, p: Pipe): Seq[QueryToken[UpdateAction]] = {
+ plan.query.updates.filter(cmd => cmd.unsolved && p.symbols.satisfies(cmd.token.dependencies))
+ }
+
+ def canWorkWith(plan: ExecutionPlanInProgress) =
+ extractValidUpdateActions(plan, plan.pipe).nonEmpty ||
+ extractValidStartItems(plan, plan.pipe).nonEmpty
def priority = PlanBuilder.Mutation
override def missingDependencies(plan: ExecutionPlanInProgress): Seq[String] = plan.query.updates.flatMap {
case Unsolved(cmd) => plan.pipe.symbols.missingDependencies(cmd.dependencies).map(_.name)
case _ => None
+ } ++ plan.query.start.flatMap {
+ case Unsolved(cmd) if cmd.isInstanceOf[UpdateAction] => plan.pipe.symbols.missingDependencies(cmd.asInstanceOf[UpdateAction].dependencies).map(_.name)
+ case _ => None
}
}
@@ -23,17 +23,17 @@ import org.neo4j.cypher.internal.symbols.Identifier
import org.neo4j.cypher.internal.pipes.{QueryState, ExecutionContext}
import org.neo4j.helpers.ThisShouldNotHappenError
import org.neo4j.cypher.internal.commands.{StartItem, Expression}
-import org.neo4j.cypher.RelatePathNotUnique
+import org.neo4j.cypher.UniquePathNotUniqueException
import org.neo4j.graphdb.{Lock, PropertyContainer}
-case class RelateAction(links: RelateLink*) extends UpdateAction {
+case class CreateUniqueAction(links: UniqueLink*) extends StartItem("noooes") with UpdateAction {
def dependencies: Seq[Identifier] = links.flatMap(_.dependencies)
def exec(context: ExecutionContext, state: QueryState): Traversable[ExecutionContext] = {
- var linksToDo: Seq[RelateLink] = links
+ var linksToDo: Seq[UniqueLink] = links
var ctx = context
while (linksToDo.nonEmpty) {
- val results: Seq[(RelateLink, RelateResult)] = executeAllRemainingPatterns(linksToDo, ctx, state)
+ val results: Seq[(UniqueLink, CreateUniqueResult)] = executeAllRemainingPatterns(linksToDo, ctx, state)
linksToDo = results.map(_._1)
val updateCommands = extractUpdateCommands(results)
val traversals = extractTraversals(results)
@@ -59,8 +59,8 @@ case class RelateAction(links: RelateLink*) extends UpdateAction {
Stream(ctx)
}
- private def tryAgain(linksToDo: Seq[RelateLink], context: ExecutionContext, state: QueryState): ExecutionContext = {
- val results: Seq[(RelateLink, RelateResult)] = executeAllRemainingPatterns(linksToDo, context, state)
+ private def tryAgain(linksToDo: Seq[UniqueLink], context: ExecutionContext, state: QueryState): ExecutionContext = {
+ val results: Seq[(UniqueLink, CreateUniqueResult)] = executeAllRemainingPatterns(linksToDo, context, state)
val updateCommands = extractUpdateCommands(results)
val traversals = extractTraversals(results)
@@ -84,7 +84,7 @@ case class RelateAction(links: RelateLink*) extends UpdateAction {
if (uniqueKeys.size != uniqueKVPs.size) {
//We can only go forward following a unique path. Fail.
- throw new RelatePathNotUnique("The pattern " + this + " produced multiple possible paths, and that is not allowed")
+ throw new UniquePathNotUniqueException("The pattern " + this + " produced multiple possible paths, and that is not allowed")
} else {
oldContext.newWith(uniqueKeys)
}
@@ -106,7 +106,7 @@ case class RelateAction(links: RelateLink*) extends UpdateAction {
case (currentContext, updateCommand) => {
val result = updateCommand.cmd.exec(currentContext, state)
if (result.size != 1) {
- throw new RelatePathNotUnique("The pattern " + this + " produced multiple possible paths, and that is not allowed")
+ throw new UniquePathNotUniqueException("The pattern " + this + " produced multiple possible paths, and that is not allowed")
} else {
result.head
}
@@ -118,36 +118,36 @@ case class RelateAction(links: RelateLink*) extends UpdateAction {
context
}
- private def extractUpdateCommands(results: scala.Seq[(RelateLink, RelateResult)]): Seq[Update] =
+ private def extractUpdateCommands(results: scala.Seq[(UniqueLink, CreateUniqueResult)]): Seq[Update] =
results.flatMap {
case (_, u: Update) => Some(u)
case _ => None
}
- private def extractTraversals(results: scala.Seq[(RelateLink, RelateResult)]): Seq[(String, PropertyContainer)] =
+ private def extractTraversals(results: scala.Seq[(UniqueLink, CreateUniqueResult)]): Seq[(String, PropertyContainer)] =
results.flatMap {
case (_, Traverse(ctx@_*)) => ctx
case _ => None
}
- private def executeAllRemainingPatterns(linksToDo: Seq[RelateLink], ctx: ExecutionContext, state: QueryState): Seq[(RelateLink, RelateResult)] = linksToDo.flatMap(link => link.exec(ctx, state))
+ private def executeAllRemainingPatterns(linksToDo: Seq[UniqueLink], ctx: ExecutionContext, state: QueryState): Seq[(UniqueLink, CreateUniqueResult)] = linksToDo.flatMap(link => link.exec(ctx, state))
- private def canNotAdvanced(results: scala.Seq[(RelateLink, RelateResult)]) = results.forall(_._2 == CanNotAdvance())
+ private def canNotAdvanced(results: scala.Seq[(UniqueLink, CreateUniqueResult)]) = results.forall(_._2 == CanNotAdvance())
def filter(f: (Expression) => Boolean): Seq[Expression] = links.flatMap(_.filter(f)).distinct
def identifier: Seq[Identifier] = links.flatMap(_.identifier).distinct
- def rewrite(f: (Expression) => Expression): UpdateAction = RelateAction(links.map(_.rewrite(f)): _*)
+ def rewrite(f: (Expression) => Expression): CreateUniqueAction = CreateUniqueAction(links.map(_.rewrite(f)): _*)
}
-sealed abstract class RelateResult
+sealed abstract class CreateUniqueResult
-case class CanNotAdvance() extends RelateResult
+case class CanNotAdvance() extends CreateUniqueResult
-case class Traverse(result: (String, PropertyContainer)*) extends RelateResult
+case class Traverse(result: (String, PropertyContainer)*) extends CreateUniqueResult
-case class Update(cmds: Seq[UpdateWrapper], locker: () => Seq[Lock]) extends RelateResult {
+case class Update(cmds: Seq[UpdateWrapper], locker: () => Seq[Lock]) extends CreateUniqueResult {
def lock(): Seq[Lock] = locker()
}
Oops, something went wrong.

0 comments on commit c7dbbb9

Please sign in to comment.