Skip to content

Commit

Permalink
PatternGraph can now extract the optional patterns
Browse files Browse the repository at this point in the history
  • Loading branch information
systay committed Jun 18, 2012
1 parent 0195ce6 commit 535e1bb
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,29 @@ class PatternGraph(val patternNodes: Map[String, PatternNode],

val (patternGraph, optionalElements, containsLoops, doubleOptionalPaths) = validatePattern(patternNodes, patternRels)

def doubleOptionalPatterns(): Seq[PatternGraph] = {
val mandatory = mandatoryGraph()

if (mandatory == this)
return Seq()

null
}

lazy val hasBoundRelationships:Boolean = boundElements.exists(patternRels.keys.toSeq.contains)
lazy val hasVarLengthPaths:Boolean = patternRels.values.exists(_.isInstanceOf[VariableLengthPatternRelationship])

def mandatoryGraph(): PatternGraph = {
def doubleOptionalPatterns(): Seq[PatternGraph] =
doubleOptionalPaths.map(
dop => {
println(dop.rel1)
println(dop.rel2)
extractGraphFromPaths(Seq(patternRels(dop.rel1), patternRels(dop.rel2)), (mandatoryGraph.patternNodes.keys ++ mandatoryGraph.patternRels.keys).toSeq)
}
)

lazy val hasBoundRelationships: Boolean = boundElements.exists(patternRels.keys.toSeq.contains)
lazy val hasVarLengthPaths: Boolean = patternRels.values.exists(_.isInstanceOf[VariableLengthPatternRelationship])

lazy val mandatoryGraph: PatternGraph = {
val relationshipsNotInDoubleOptionalPaths = patternRels.values.filterNot(p => doubleOptionalPaths.exists(dop => dop.rel1 == p.key || dop.rel2 == p.key))

if (relationshipsNotInDoubleOptionalPaths.size == patternRels.size)
return this

extractGraphFromPaths(relationshipsNotInDoubleOptionalPaths)
this
else
extractGraphFromPaths(relationshipsNotInDoubleOptionalPaths, boundElements)
}


def extractGraphFromPaths(relationshipsNotInDoubleOptionalPaths: Iterable[PatternRelationship]): PatternGraph = {
def extractGraphFromPaths(relationshipsNotInDoubleOptionalPaths: Iterable[PatternRelationship], boundPoints: Seq[String]): PatternGraph = {
val oldNodes = relationshipsNotInDoubleOptionalPaths.flatMap(p => Seq(p.startNode, p.endNode)).toSeq.distinct

val newNodes = oldNodes.map(patternNode => patternNode.key -> new PatternNode(patternNode.key)).toMap
Expand All @@ -62,7 +62,7 @@ class PatternGraph(val patternNodes: Map[String, PatternNode],
pr.key -> s.relateTo(pr.key, e, pr.relTypes, pr.dir, pr.optional, pr.predicate)
}.toMap

new PatternGraph(newNodes, newRelationships, boundElements)
new PatternGraph(newNodes, newRelationships, boundPoints)
}

def apply(key: String) = patternGraph(key)
Expand Down Expand Up @@ -130,10 +130,10 @@ class PatternGraph(val patternNodes: Map[String, PatternNode],
val leftRel = numberOfOptionals(0)
val rightRel = numberOfOptionals(1)
val leftNode = data(data.indexOf(leftRel) - 1)
val leftSide: Seq[PatternElement] = data.dropWhile(_ != leftNode)
val idxOfRightNode = leftSide.indexOf(rightRel) + 1
val leftIdx = data.indexOf(leftNode)
val rightIdx = data.indexOf(rightRel) + 2

val path: Seq[PatternElement] = if (idxOfRightNode == data.size) leftSide :+ e else leftSide.slice(0, idxOfRightNode + 1)
val path: Seq[PatternElement] = result.slice(leftIdx, rightIdx)

val correctSidedPath = if (path.head.key < path.last.key) {
path
Expand Down Expand Up @@ -215,6 +215,23 @@ class PatternGraph(val patternNodes: Map[String, PatternNode],
case class Relationships(closestRel: String, oppositeRel: String)

case class DoubleOptionalPath(path: Seq[PatternElement]) {

assert(isProperPath, "The DoubleOptionalPath created is not valid: " + path.mkString(","))

def isProperPath: Boolean = {
var x = true
val (nodes, rels) = path.partition(e => {
x = !x
!x
})

val nodesContainOnlyNodes = nodes.forall(_.isInstanceOf[PatternNode])
val relsAreAllRels = rels.forall(_.isInstanceOf[PatternRelationship])
val atLeastOneNode = nodes.length > 0
val relsLengthEqualsToNodesLengthMinusOne = rels.length == nodes.length - 1
nodesContainOnlyNodes && relsAreAllRels && atLeastOneNode && relsLengthEqualsToNodesLengthMinusOne
}

val startNode = path.head.key
val endNode = path.last.key
val rel1 = path.tail.head.key
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ package org.neo4j.cypher.internal.pipes.matching
import org.scalatest.Assertions
import org.neo4j.graphdb.Direction
import org.neo4j.cypher.internal.commands.True
import org.neo4j.cypher.internal.symbols.{NodeType, Identifier, SymbolTable}
import org.junit.{Ignore, Test}
import org.junit.Test

class PatternGraphTest extends Assertions {

Expand Down Expand Up @@ -103,10 +102,10 @@ class PatternGraphTest extends Assertions {
assert(graph.doubleOptionalPaths === Seq())
}

@Ignore @Test def mandatory_graph_is_extracted_correctly() {
@Test def mandatory_graph_is_extracted_correctly() {
//given a-[r1]->z-[r2?]->x<-[r3?]-b, where a and b are bound
val a = createNode("a")
val z = createNode("a")
val z = createNode("z")
val x = createNode("x")
val b = createNode("b")
val r1 = relate(a, z, "r1", optional = false)
Expand All @@ -116,13 +115,14 @@ class PatternGraphTest extends Assertions {
val graph = new PatternGraph(nodes, rels, Seq("a", "b"))

//when
val mandatory: PatternGraph = graph.mandatoryGraph()
val mandatory: PatternGraph = graph.mandatoryGraph
val optionals: Seq[PatternGraph] = graph.doubleOptionalPatterns()


//then
assert(mandatory.patternRels === Map("r1" -> r1))
assert(optionals.size === 1)
assert(optionals.head.patternRels.keys.toSeq === Seq("r2", "r3"))
assert(optionals.head.patternRels.keys.toSet === Set("r2", "r3"))
}

private def createNode(name: String): PatternNode = {
Expand All @@ -138,10 +138,4 @@ class PatternGraphTest extends Assertions {
rels = rels + (key -> r)
r
}

private def bind(boundSymbols: String*): SymbolTable = {
val identifiersToCreate = boundSymbols.map(x => Identifier(x, NodeType()))
new SymbolTable(identifiersToCreate: _*)
}

}

0 comments on commit 535e1bb

Please sign in to comment.