Permalink
Browse files

Neat new arrow notation for creating relationships

  • Loading branch information...
1 parent 910d00f commit 0ddbe09d6f25741604cca49530d6de4b864cbf4c Martin Kleppmann committed Jun 14, 2009
@@ -0,0 +1,50 @@
+package com.eptcomputing.neo4j
+
+import org.neo4j.api.core._
+
+/**
+ * Extend your class with this trait to get really neat new notation for creating
+ * new relationships. For example, ugly Java-esque code like:
+ * <pre>
+ * val knows = DynamicRelationshipType.withName("KNOWS")
+ * start.createRelationshipTo(intermediary, knows)
+ * intermediary.createRelationshipTo(end, knows)
+ * </pre>
+ *
+ * can be replaced with a beautiful Scala one-liner:
+ * <pre>start --| "KNOWS" --> intermediary --| "KNOWS" --> end</pre>
+ *
+ * Feel free to use this example to tell all your friends how awesome scala is :)
+ */
+trait NeoConverters {
+
+ class NodeRelationshipMethods(node: Node) {
+ // Create outgoing relationship
+ def --|(relType: String) = new OutgoingRelationshipBuilder(node, DynamicRelationshipType.withName(relType))
+
+ def --|(relType: RelationshipType) = new OutgoingRelationshipBuilder(node, relType)
+
+ // Create incoming relationship
+ def <--(relType: String) = new IncomingRelationshipBuilder(node, DynamicRelationshipType.withName(relType))
+
+ def <--(relType: RelationshipType) = new IncomingRelationshipBuilder(node, relType)
+ }
+
+ // Half-way through building an outgoing relationship
+ class OutgoingRelationshipBuilder(fromNode: Node, relType: RelationshipType) {
+ def -->(toNode: Node) = {
+ fromNode.createRelationshipTo(toNode, relType)
+ new NodeRelationshipMethods(toNode)
+ }
+ }
+
+ // Half-way through building an incoming relationship
+ class IncomingRelationshipBuilder(toNode: Node, relType: RelationshipType) {
+ def |--(fromNode: Node) = {
+ fromNode.createRelationshipTo(toNode, relType)
+ new NodeRelationshipMethods(fromNode)
+ }
+ }
+
+ implicit def node2relationshipBuilder(node: Node) = new NodeRelationshipMethods(node)
+}
@@ -0,0 +1,89 @@
+package com.eptcomputing.neo4j
+
+import org.scalatest.Spec
+import org.scalatest.matchers.ShouldMatchers
+import org.junit.runner.RunWith
+import com.jteigen.scalatest.JUnit4Runner
+
+import org.neo4j.api.core._
+
+@RunWith(classOf[JUnit4Runner])
+class NeoConvertersSpec extends Spec with ShouldMatchers with NeoConverters {
+ describe("NeoConverters") {
+ it("should create a new relationship in --| relType --> notation") {
+ NeoServer.exec { neo =>
+ val start = neo.createNode
+ val end = neo.createNode
+ val relType = DynamicRelationshipType.withName("foo")
+ start --| relType --> end
+ start.getSingleRelationship(relType, Direction.OUTGOING).
+ getOtherNode(start) should equal(end)
+ }
+ }
+
+ it("should create a new relationship in --| \"relName\" --> notation") {
+ NeoServer.exec { neo =>
+ val start = neo.createNode
+ val end = neo.createNode
+ start --| "foo" --> end
+ start.getSingleRelationship(DynamicRelationshipType.withName("foo"), Direction.OUTGOING).
+ getOtherNode(start) should equal(end)
+ }
+ }
+
+ it("should create a new relationship in <-- relType |-- notation") {
+ NeoServer.exec { neo =>
+ val start = neo.createNode
+ val end = neo.createNode
+ val relType = DynamicRelationshipType.withName("foo")
+ end <-- relType |-- start
+ start.getSingleRelationship(relType, Direction.OUTGOING).
+ getOtherNode(start) should equal(end)
+ }
+ }
+
+ it("should create a new relationship in <-- \"relName\" |-- notation") {
+ NeoServer.exec { neo =>
+ val start = neo.createNode
+ val end = neo.createNode
+ end <-- "foo" |-- start
+ start.getSingleRelationship(DynamicRelationshipType.withName("foo"), Direction.OUTGOING).
+ getOtherNode(start) should equal(end)
+ }
+ }
+
+ it("should allow relationships of the same direction to be chained") {
+ NeoServer.exec { neo =>
+ val start = neo.createNode
+ val middle = neo.createNode
+ val end = neo.createNode
+ (((start --| "foo") --> middle) --| "bar") --> end
+ start.getSingleRelationship(DynamicRelationshipType.withName("foo"), Direction.OUTGOING).
+ getOtherNode(start) should equal(middle)
+ middle.getSingleRelationship(DynamicRelationshipType.withName("bar"), Direction.OUTGOING).
+ getOtherNode(middle) should equal(end)
+ }
+ }
+
+ it("should allow relationships of different directions to be chained") {
+ NeoServer.exec { neo =>
+ val left = neo.createNode
+ val middle = neo.createNode
+ val right = neo.createNode
+ left --| "foo" --> middle <-- "bar" |-- right
+ left.getSingleRelationship(DynamicRelationshipType.withName("foo"), Direction.OUTGOING).
+ getOtherNode(left) should equal(middle)
+ right.getSingleRelationship(DynamicRelationshipType.withName("bar"), Direction.OUTGOING).
+ getOtherNode(right) should equal(middle)
+ }
+ }
+
+ it("should ignore a relationshipBuilder with no end node") {
+ NeoServer.exec { neo =>
+ val start = neo.createNode
+ start --| "foo"
+ start.getRelationships.iterator.hasNext should equal(false)
+ }
+ }
+ }
+}

0 comments on commit 0ddbe09

Please sign in to comment.