Permalink
Browse files

Started Pattern-documentation

  • Loading branch information...
systay committed Jun 5, 2012
1 parent c5be29f commit 92acd1fce35035590612e7fabd616d6583a688ed
@@ -20,6 +20,8 @@ include::updating.txt[]
include::transactions.txt[]
+include::ql/pattern/patterns.txt[]
+
:leveloffset: 2
include::ql/start/index.txt[]
@@ -17,5 +17,5 @@ include::property-exists.txt[]
include::default-true-if-property-is-missing.txt[]
include::default-false-if-property-is-missing.txt[]
include::filter-on-null-values.txt[]
-include::filter-on-relationships.txt[]
+include::filter-on-patterns.txt[]
include::in-operator.txt[]
@@ -159,11 +159,17 @@ case class IdFunction(inner: Expression) extends NullInNullOutExpression(inner)
case class HeadFunction(collection: Expression) extends NullInNullOutExpression(collection) with IterableSupport {
def compute(value: Any, m: Map[String, Any]) = makeTraversable(value).head
- private def myType = collection.identifier.typ match {
- case x: IterableType => x.iteratedType
- case _ => ScalarType()
+ private def myType = {
+ println(collection.identifier.typ)
+
+ collection.identifier.typ match {
+ case x: IterableType => x.iteratedType
+ case _ => ScalarType()
+ }
}
+ override def dependencies(extectedType: AnyType): Seq[Identifier] = declareDependencies(extectedType)
+
val identifier = Identifier("head(" + collection.identifier.name + ")", myType)
def declareDependencies(extectedType: AnyType): Seq[Identifier] = collection.dependencies(AnyIterableType())
@@ -30,18 +30,25 @@ class ColumnFilterBuilder extends PlanBuilder {
val p = plan.pipe
val isLastPipe = q.tail.isEmpty
- val returnItems = getReturnItems(q.returns, p.symbols)
- val filterPipe = new ColumnFilterPipe(p, returnItems, isLastPipe)
+ if (!isLastPipe && q.returns == Seq(Unsolved(AllIdentifiers()))) {
+ val resultQ = q.copy(returns = q.returns.map(_.solve))
- val resultPipe = if (filterPipe.symbols != p.symbols || isLastPipe) {
- filterPipe
+ plan.copy(query = resultQ)
} else {
- p
- }
- val resultQ = q.copy(returns = q.returns.map(_.solve))
+ val returnItems = getReturnItems(q.returns, p.symbols)
+ val filterPipe = new ColumnFilterPipe(p, returnItems, isLastPipe)
+
+ val resultPipe = if (filterPipe.symbols != p.symbols || isLastPipe) {
+ filterPipe
+ } else {
+ p
+ }
- plan.copy(pipe = resultPipe, query = resultQ)
+ val resultQ = q.copy(returns = q.returns.map(_.solve))
+
+ plan.copy(pipe = resultPipe, query = resultQ)
+ }
}
def canWorkWith(plan: ExecutionPlanInProgress) = {
@@ -57,6 +64,9 @@ class ColumnFilterBuilder extends PlanBuilder {
private def getReturnItems(q: Seq[QueryToken[ReturnColumn]], symbols: SymbolTable): Seq[ReturnItem] = q.map(_.token).flatMap {
case x: ReturnItem => Seq(x)
- case x: AllIdentifiers => x.expressions(symbols).map(e => ReturnItem(e, e.identifier.name))
+ case x: AllIdentifiers =>
+ val expressions = x.expressions(symbols)
+ val map = expressions.map(e => ReturnItem(e, e.identifier.name))
+ map
}
}
@@ -38,23 +38,15 @@ trait ParserPattern extends Base {
}
def usePattern[T](translator: AbstractPattern => Maybe[T]): Parser[Seq[T]] = Parser {
- case in =>
- pattern(in) match {
- case Success(abstractPattern, rest) =>
- val concretePattern = abstractPattern.map(p => translator(p))
-
- concretePattern.find(!_.success) match {
- case Some(No(msg)) => Failure(msg, rest)
- case None => Success(concretePattern.map(_.value), rest)
- }
-
- case Failure(msg, rest) => Failure(msg, rest)
- case Error(msg, rest) => Error(msg, rest)
- }
+ case in => translate(in, translator, pattern(in))
}
def usePath[T](translator: AbstractPattern => Maybe[T]):Parser[Seq[T]] = Parser {
- case in => path(in) match {
+ case in => translate(in, translator, path(in))
+ }
+
+ private def translate[T](in: Input, translator: (AbstractPattern) => Maybe[T], pattern1: ParseResult[Seq[AbstractPattern]]): ParseResult[Seq[T]] with Product with Serializable = {
+ pattern1 match {
case Success(abstractPattern, rest) =>
val concretePattern = abstractPattern.map(p => translator(p))
@@ -85,10 +77,11 @@ trait ParserPattern extends Base {
}
private def node: Parser[ParsedEntity] =
- parens(nodeFromExpression) | // whatever // CREATE (last(p))-[:KNOWS]->me
+ parens(nodeFromExpression) | // whatever expression, but inside parenthesis
singleNodeEqualsMap | // x = {}
nodeIdentifier | // x
- nodeInParenthesis | failure("expected an expression that is a node")
+ nodeInParenthesis | // (x {})
+ failure("expected an expression that is a node")
private def singleNodeEqualsMap = identity ~ "=" ~ properties ^^ {
@@ -78,6 +78,19 @@ class CreateTest extends DocumentingTestBase {
)
}
+ @Test def using_expressions_as_nodes() {
+ val (aId, bId) = createTwoNodes
+
+ testQuery(
+ title = "Using expressions for nodes end points",
+ text = "You can use any expression as a node, as long as it returns a node. Just make sure to encase your " +
+ "expression in parenthesis.",
+ queryText = "start a=node(" + aId + ") with collect(a) as nodes start b=node(" +bId + ") create (head(nodes))-[r:REL]->b return r",
+ returns = "The created relationship is returned.",
+ assertions = (p) => assert(p.size === 1)
+ )
+ }
+
@Test def set_property_to_an_iterable() {
val (aId, bId) = db.inTx(() => {
val a = db.createNode()
@@ -113,10 +113,9 @@ _Graph_
}
def testQuery(title: String, text: String, queryText: String, returns: String, assertions: (ExecutionResult => Unit)*) {
- var query = queryText
- nodes.keySet.foreach((key) => query = query.replace("%" + key + "%", node(key).getId.toString))
- val result = engine.execute(query)
- assertions.foreach(_.apply(result))
+ val r = testWithoutDocs(queryText, assertions:_*)
+ val result: ExecutionResult = r._1
+ var query: String = r._2
val dir = new File(path + nicefy(section))
if (!dir.exists()) {
@@ -131,6 +130,15 @@ _Graph_
dumpGraphViz(graphViz, graphFileName)
}
+
+ def testWithoutDocs(queryText: String, assertions: (ExecutionResult => Unit)*): (ExecutionResult, String) = {
+ var query = queryText
+ nodes.keySet.foreach((key) => query = query.replace("%" + key + "%", node(key).getId.toString))
+ val result = engine.execute(query)
+ assertions.foreach(_.apply(result))
+ (result, query)
+ }
+
def indexProperties[T <: PropertyContainer](n: T, index: Index[T]) {
indexProps.foreach((property) => {
if (n.hasProperty(property)) {
@@ -297,23 +297,11 @@ RETURN p"""
@Test def intro() {
testQuery(
- title = "introduction",
+ title = "Introduction",
text = """Pattern matching is one of the pillars of Cypher. The pattern is used to describe the shape of the data that we are
looking for. Cypher will then try to find patterns in the graph -- these are called matching subgraphs.
-The description of the pattern is made up of one or more paths, separated by commas. A path is a sequence of nodes and
-relationships that always start and end in nodes. An example path would be:
-+`(a)-->(b)`+
-Paths can be of arbitrary length, and the same node may appear in multiple places in the path. Node identifiers can be
-used with or without surrounding parenthesis. The following two match clauses are semantically identical -- the difference is
-purely aesthetic.
-
-+`MATCH (a)-->(b)`+
-
-and
-
-+`MATCH a-->b`+
Patterns have bound points, or start points. They are the parts of the pattern that are already ``bound'' to a set of
@@ -385,42 +373,11 @@ As a simple example, let's take the following query, executed on the graph pictu
)
}
- @Test def introQ2() {
- testQuery(
- title = "q2",
- text = "",
- queryText = intro_q2,
- returns = "",
- assertions = p => assertTrue(true)
- )
- }
-
- @Test def introQ3() {
- testQuery(
- title = "q3",
- text = "",
- queryText = intro_q3,
- returns = "",
- assertions = p => assertTrue(true)
- )
- }
- @Test def introQ4() {
- testQuery(
- title = "q4",
- text = "",
- queryText = intro_q4,
- returns = "",
- assertions = p => assertTrue(true)
- )
- }
- @Test def introQ5() {
- testQuery(
- title = "q5",
- text = "",
- queryText = intro_q5,
- returns = "",
- assertions = p => assertTrue(true)
- )
+ @Test def runQueries() {
+ testWithoutDocs(intro_q2)
+ testWithoutDocs(intro_q3)
+ testWithoutDocs(intro_q4)
+ testWithoutDocs(intro_q5)
}
}
Oops, something went wrong.

0 comments on commit 92acd1f

Please sign in to comment.