Permalink
Browse files

apa

  • Loading branch information...
1 parent 99c4cb0 commit 5338fa7ded06a9711ef877eb5161e02719c76f98 @systay committed Aug 2, 2012
@@ -66,7 +66,9 @@ class CreateNodesAndRelationshipsBuilder(db: GraphDatabaseService) extends PlanB
case CreateNodeStartItem(key, props)
if createdNodes.contains(key) && props.nonEmpty =>
throw new SyntaxException("Node `%s` has already been created. Can't assign properties to it again.".format(key))
+
case CreateNodeStartItem(key, _) if createdNodes.contains(key) => None
+
case x@CreateNodeStartItem(key, _) =>
createdNodes += key
Some(x)
@@ -39,7 +39,6 @@ class UpdateActionBuilder(db: GraphDatabaseService) extends PlanBuilder {
val startCmds = startItems.map(_.map(_.asInstanceOf[UpdateAction]))
val commands = updateCmds ++ startCmds
-
val resultPipe = new ExecuteUpdateCommandsPipe(p, db, commands.map(_.token))
plan.copy(
@@ -109,13 +109,15 @@ case class UniqueLink(start: NamedExpectation, end: NamedExpectation, rel: Named
}).toList
rels match {
- case List() =>
+ case List() =>
val tx = state.transaction.getOrElse(throw new RuntimeException("I need a transaction!"))
- Some(this ->Update(createUpdateActions(dir, startNode, end), () => {
+ Some(this -> Update(createUpdateActions(dir, startNode, end), () => {
Seq(tx.acquireWriteLock(startNode))
}))
- case List(r) => Some(this->Traverse(rel.name -> r, end.name -> r.getOtherNode(startNode)))
- case _ => throw new UniquePathNotUniqueException("The pattern " + this + " produced multiple possible paths, and that is not allowed")
+
+ case List(r) => Some(this -> Traverse(rel.name -> r, end.name -> r.getOtherNode(startNode)))
+
+ case _ => throw new UniquePathNotUniqueException("The pattern " + this + " produced multiple possible paths, and that is not allowed")
}
}
@@ -19,63 +19,67 @@
*/
package org.neo4j.cypher.internal.pipes
-import collection.mutable.{HashSet => MutableHashSet}
-import org.neo4j.cypher.internal.mutation.{DeleteEntityAction, UpdateAction}
-import org.neo4j.graphdb.{Relationship, Node, GraphDatabaseService, NotInTransactionException}
-import org.neo4j.cypher.{ParameterWrongTypeException, InternalException}
+import org.neo4j.cypher.internal.mutation.{NamedExpectation, CreateUniqueAction, UpdateAction}
+import org.neo4j.graphdb.{GraphDatabaseService, NotInTransactionException}
+import org.neo4j.cypher.{SyntaxException, CypherTypeException, ParameterWrongTypeException, InternalException}
+import org.neo4j.cypher.internal.commands.{Expression, Entity, CreateRelationshipStartItem, CreateNodeStartItem}
+import collection.Map
-class ExecuteUpdateCommandsPipe(source: Pipe, db: GraphDatabaseService, commands: Seq[UpdateAction]) extends PipeWithSource(source) {
+class ExecuteUpdateCommandsPipe(source: Pipe, db: GraphDatabaseService, commands: Seq[UpdateAction])
+ extends PipeWithSource(source) {
+ assertNothingIsCreatedWhenItShouldNot()
def createResults(state: QueryState) = {
- val deletedNodes = MutableHashSet[Long]()
- val deletedRelationships = MutableHashSet[Long]()
-
- if (commands.size == 1) {
- source.createResults(state).flatMap {
- case ctx => executeMutationCommands(ctx, state, deletedNodes, deletedRelationships)
- }
- } else {
- source.createResults(state).flatMap {
- case ctx => executeMutationCommands(ctx, state, deletedNodes, deletedRelationships, ctx => if (ctx.size > 1) throw new ParameterWrongTypeException("If you create multiple elements, you can only create one of each."))
- }
+ source.createResults(state).flatMap {
+ case ctx => executeMutationCommands(ctx, state, commands.size == 1)
}
}
- // TODO: Make it better
- private def executeMutationCommands(ctx: ExecutionContext, state: QueryState, deletedNodes: MutableHashSet[Long], deletedRelationships: MutableHashSet[Long], f: Traversable[ExecutionContext] => Unit = x=>{}): Traversable[ExecutionContext] =
+ private def executeMutationCommands(ctx: ExecutionContext,
+ state: QueryState,
+ singleCommand: Boolean): Traversable[ExecutionContext] =
try {
- commands.foldLeft(Traversable(ctx))((context, cmd) => context.flatMap( c => exec(cmd, c, state, deletedNodes, deletedRelationships, f)))
+ commands.foldLeft(Traversable(ctx))((context, cmd) => context.flatMap(c => exec(cmd, c, state, singleCommand)))
} catch {
case e: NotInTransactionException => throw new InternalException("Expected to be in a transaction at this point", e)
}
- private def exec(cmd: UpdateAction, ctx: ExecutionContext, state: QueryState, deletedNodes: MutableHashSet[Long], deletedRelationships: MutableHashSet[Long], f: Traversable[ExecutionContext] => Unit): Traversable[ExecutionContext] = {
- val result = cmd match {
- case cmd@DeleteEntityAction(expression) => {
- expression(ctx) match {
- case n: Node => {
- if (!deletedNodes.contains(n.getId)) {
- deletedNodes.add(n.getId)
- cmd.exec(ctx, state)
- } else Stream(ctx)
- }
- case r: Relationship => {
- if (!deletedRelationships.contains(r.getId)) {
- deletedRelationships.add(r.getId)
- cmd.exec(ctx, state)
- } else Stream(ctx)
- }
- case _ => cmd.exec(ctx, state)
- }
- }
- case cmd => cmd.exec(ctx, state)
- }
- f(result)
+ private def exec(cmd: UpdateAction,
+ ctx: ExecutionContext,
+ state: QueryState,
+ singleCommand: Boolean): Traversable[ExecutionContext] = {
+ val result = cmd.exec(ctx, state)
+ if (result.size > 1 && !singleCommand)
+ throw new ParameterWrongTypeException("If you create multiple elements, you can only create one of each.")
result
}
+ private def extractEntitiesWithProperties(action: UpdateAction): Seq[NamedExpectation] = action match {
+ case CreateNodeStartItem(key, props) => Seq(NamedExpectation(key, props))
+ case CreateRelationshipStartItem(key, from, to, _, props) => Seq(NamedExpectation(key, props)) ++ extractIfEntity(from) ++ extractIfEntity(to)
+ case CreateUniqueAction(links@_*) => links.flatMap(l => Seq(l.start, l.end, l.rel))
+ case _ => Seq()
+ }
+
+
+ def extractIfEntity(from: (Expression, Map[String, Expression])): Option[NamedExpectation] = {
+ from match {
+ case (Entity(key), props) => Some(NamedExpectation(key, props))
+ case _ => None
+ }
+ }
+
+ private def assertNothingIsCreatedWhenItShouldNot() {
+ val entitiesAndProps: Seq[NamedExpectation] = commands.flatMap(cmd => extractEntitiesWithProperties(cmd))
+ val entitiesWithProps = entitiesAndProps.filter(_.properties.nonEmpty)
+
+ entitiesWithProps.foreach(l => if (source.symbols.keys.contains(l.name))
+ throw new SyntaxException("Can't create `%s` with properties here. It already exists in this context".format(l.name))
+ )
+ }
+
def executionPlan() = source.executionPlan() + "\nUpdateGraph(" + commands.mkString + ")"
def symbols = source.symbols.add(commands.flatMap(_.identifier): _*)
@@ -492,6 +492,11 @@ return distinct center""")
intercept[SyntaxException](parseAndExecute("create a-[:test]->b, (a {name:'a'})-[:test2]->c"))
}
+ @Test
+ def cant_set_properties_after_node_is_already_created2() {
+ intercept[SyntaxException](parseAndExecute("create a-[:test]->b create unique (a {name:'a'})-[:test2]->c"))
+ }
+
}
trait StatisticsChecker extends Assertions {
def assertStats(result: ExecutionResult,

0 comments on commit 5338fa7

Please sign in to comment.