Repository: incubator-s2graph Updated Branches: refs/heads/master 2083d136e -> 558264490
Refactor WhereParser to accept GraphElement, not Edge only. Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/3b692fbe Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/3b692fbe Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/3b692fbe Branch: refs/heads/master Commit: 3b692fbead9accd6f9d0d9764800e15e945c90bb Parents: 32eb344 Author: DO YUNG YOON <steams...@apache.org> Authored: Fri Jun 15 14:59:13 2018 +0900 Committer: DO YUNG YOON <steams...@apache.org> Committed: Fri Jun 15 14:59:13 2018 +0900 ---------------------------------------------------------------------- .../s2graph/core/S2EdgePropertyHelper.scala | 2 +- .../s2graph/core/parsers/WhereParser.scala | 102 +++++++++++-------- .../s2graph/core/parsers/WhereParserTest.scala | 22 +++- 3 files changed, 81 insertions(+), 45 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/3b692fbe/s2core/src/main/scala/org/apache/s2graph/core/S2EdgePropertyHelper.scala ---------------------------------------------------------------------- diff --git a/s2core/src/main/scala/org/apache/s2graph/core/S2EdgePropertyHelper.scala b/s2core/src/main/scala/org/apache/s2graph/core/S2EdgePropertyHelper.scala index 8c609a0..03d9d4c 100644 --- a/s2core/src/main/scala/org/apache/s2graph/core/S2EdgePropertyHelper.scala +++ b/s2core/src/main/scala/org/apache/s2graph/core/S2EdgePropertyHelper.scala @@ -55,7 +55,7 @@ object S2EdgePropertyHelper { case "label" => Option(InnerValLikeWithTs(InnerVal.withStr(e.innerLabel.label, e.innerLabel.schemaVersion), e.ts)) case "direction" => Option(InnerValLikeWithTs(InnerVal.withStr(e.getDirection(), e.innerLabel.schemaVersion), e.ts)) case _ => - e.innerLabel.metaPropsInvMap.get(key).map(labelMeta => e.propertyValueInner(labelMeta)) + e.innerLabel.metaPropsInvMap.get(key).map(labelMeta => propertyValueInner(e, labelMeta)) } } http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/3b692fbe/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala ---------------------------------------------------------------------- diff --git a/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala b/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala index 75e9657..f0d42b2 100644 --- a/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala +++ b/s2core/src/main/scala/org/apache/s2graph/core/parsers/WhereParser.scala @@ -19,11 +19,10 @@ package org.apache.s2graph.core.parsers -import org.apache.s2graph.core.GraphExceptions.{LabelNotExistException, WhereParserException} -import org.apache.s2graph.core.schema.{Label, LabelMeta} -import org.apache.s2graph.core.types.InnerValLike -import org.apache.s2graph.core.{S2EdgeLike} +import org.apache.s2graph.core.GraphExceptions.WhereParserException import org.apache.s2graph.core.JSONParser._ +import org.apache.s2graph.core._ +import org.apache.s2graph.core.types.InnerValLike import scala.annotation.tailrec import scala.util.Try @@ -32,21 +31,40 @@ import scala.util.parsing.combinator.JavaTokenParsers trait ExtractValue { val parent = "_parent." - def propToInnerVal(edge: S2EdgeLike, key: String) = { - val (propKey, parentEdge) = findParentEdge(edge, key) + private def throwEx(key: String) = { + throw WhereParserException(s"Where clause contains not existing property name: $key") + } - val label = parentEdge.innerLabel - val metaPropInvMap = label.metaPropsInvMap - val labelMeta = metaPropInvMap.getOrElse(propKey, throw WhereParserException(s"Where clause contains not existing property name: $propKey")) + def propToInnerVal(element: GraphElement, key: String): InnerValLike = { + element match { + case e: S2EdgeLike => edgePropToInnerVal(e, key) + case v: S2VertexLike => vertexPropToInnerVal(v, key) + case _ => throw new IllegalArgumentException("only S2EdgeLike/S2VertexLike supported.") + } + } - labelMeta match { - case LabelMeta.from => parentEdge.srcVertex.innerId - case LabelMeta.to => parentEdge.tgtVertex.innerId - case _ => parentEdge.propertyValueInner(labelMeta).innerVal + def valueToCompare(element: GraphElement, key: String, value: String): InnerValLike = { + element match { + case e: S2EdgeLike => edgeValueToCompare(e, key, value) + case v: S2VertexLike => vertexValueToCompare(v, key, value) + case _ => throw new IllegalArgumentException("only S2EdgeLike/S2VertexLike supported.") } } - def valueToCompare(edge: S2EdgeLike, key: String, value: String) = { + private def edgePropToInnerVal(edge: S2EdgeLike, key: String): InnerValLike = { + val (propKey, parentEdge) = findParentEdge(edge, key) + + val innerValLikeWithTs = + S2EdgePropertyHelper.propertyValue(parentEdge, propKey).getOrElse(throwEx(propKey)) + + innerValLikeWithTs.innerVal + } + + private def vertexPropToInnerVal(vertex: S2VertexLike, key: String): InnerValLike = { + S2VertexPropertyHelper.propertyValue(vertex, key).getOrElse(throwEx(key)) + } + + private def edgeValueToCompare(edge: S2EdgeLike, key: String, value: String): InnerValLike = { val label = edge.innerLabel if (value.startsWith(parent) || label.metaPropsInvMap.contains(value)) propToInnerVal(edge, value) else { @@ -63,6 +81,12 @@ trait ExtractValue { } } + private def vertexValueToCompare(vertex: S2VertexLike, key: String, value: String): InnerValLike = { + val columnMeta = vertex.serviceColumn.metasInvMap.getOrElse(key, throw WhereParserException(s"Where clause contains not existing property name: $key")) + + toInnerVal(value, columnMeta.dataType, vertex.serviceColumn.schemaVersion) + } + @tailrec private def findParent(edge: S2EdgeLike, depth: Int): S2EdgeLike = if (depth > 0) findParent(edge.getParentEdges().head.edge, depth - 1) @@ -87,11 +111,11 @@ trait Clause extends ExtractValue { def or(otherField: Clause): Clause = Or(this, otherField) - def filter(edge: S2EdgeLike): Boolean + def filter(element: GraphElement): Boolean - def binaryOp(binOp: (InnerValLike, InnerValLike) => Boolean)(propKey: String, value: String)(edge: S2EdgeLike): Boolean = { - val propValue = propToInnerVal(edge, propKey) - val compValue = valueToCompare(edge, propKey, value) + def binaryOp(binOp: (InnerValLike, InnerValLike) => Boolean)(propKey: String, value: String)(element: GraphElement): Boolean = { + val propValue = propToInnerVal(element, propKey) + val compValue = valueToCompare(element, propKey, value) binOp(propValue, compValue) } @@ -106,29 +130,27 @@ object Where { } case class Where(clauses: Seq[Clause] = Seq.empty[Clause]) { - def filter(edge: S2EdgeLike) = - if (clauses.isEmpty) true else clauses.map(_.filter(edge)).forall(identity) + def filter(element: GraphElement) = + if (clauses.isEmpty) true else clauses.map(_.filter(element)).forall(identity) } case class Gt(propKey: String, value: String) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = binaryOp(_ > _)(propKey, value)(edge) + override def filter(element: GraphElement): Boolean = binaryOp(_ > _)(propKey, value)(element) } case class Lt(propKey: String, value: String) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = binaryOp(_ < _)(propKey, value)(edge) + override def filter(element: GraphElement): Boolean = binaryOp(_ < _)(propKey, value)(element) } case class Eq(propKey: String, value: String) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = binaryOp(_ == _)(propKey, value)(edge) + override def filter(element: GraphElement): Boolean = binaryOp(_ == _)(propKey, value)(element) } case class InWithoutParent(propKey: String, values: Set[String]) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = { - val label = edge.innerLabel - - val propVal = propToInnerVal(edge, propKey) + override def filter(element: GraphElement): Boolean = { + val propVal = propToInnerVal(element, propKey) val innerVaLs = values.map { value => - toInnerVal(value, label.metaPropsInvMap(propKey).dataType, label.schemaVersion) + valueToCompare(element, propKey, value) } innerVaLs(propVal) @@ -136,41 +158,41 @@ case class InWithoutParent(propKey: String, values: Set[String]) extends Clause } case class Contains(propKey: String, value: String) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = { - val propVal = propToInnerVal(edge, propKey) + override def filter(element: GraphElement): Boolean = { + val propVal = propToInnerVal(element, propKey) propVal.value.toString.contains(value) } } case class IN(propKey: String, values: Set[String]) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = { - val propVal = propToInnerVal(edge, propKey) + override def filter(element: GraphElement): Boolean = { + val propVal = propToInnerVal(element, propKey) values.exists { value => - valueToCompare(edge, propKey, value) == propVal + valueToCompare(element, propKey, value) == propVal } } } case class Between(propKey: String, minValue: String, maxValue: String) extends Clause { - override def filter(edge: S2EdgeLike): Boolean = { - val propVal = propToInnerVal(edge, propKey) - val minVal = valueToCompare(edge, propKey, minValue) - val maxVal = valueToCompare(edge, propKey, maxValue) + override def filter(element: GraphElement): Boolean = { + val propVal = propToInnerVal(element, propKey) + val minVal = valueToCompare(element, propKey, minValue) + val maxVal = valueToCompare(element, propKey, maxValue) minVal <= propVal && propVal <= maxVal } } case class Not(self: Clause) extends Clause { - override def filter(edge: S2EdgeLike) = !self.filter(edge) + override def filter(element: GraphElement) = !self.filter(element) } case class And(left: Clause, right: Clause) extends Clause { - override def filter(edge: S2EdgeLike) = left.filter(edge) && right.filter(edge) + override def filter(element: GraphElement) = left.filter(element) && right.filter(element) } case class Or(left: Clause, right: Clause) extends Clause { - override def filter(edge: S2EdgeLike) = left.filter(edge) || right.filter(edge) + override def filter(element: GraphElement) = left.filter(element) || right.filter(element) } object WhereParser { http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/3b692fbe/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala ---------------------------------------------------------------------- diff --git a/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala b/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala index 342d9c6..0859d9c 100644 --- a/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala +++ b/s2core/src/test/scala/org/apache/s2graph/core/parsers/WhereParserTest.scala @@ -20,7 +20,7 @@ package org.apache.s2graph.core.parsers import org.apache.s2graph.core._ -import org.apache.s2graph.core.schema.{ServiceColumn, Label, LabelMeta} +import org.apache.s2graph.core.schema._ import org.apache.s2graph.core.rest.TemplateHelper import org.apache.s2graph.core.types._ import org.apache.s2graph.core.utils.logger @@ -37,11 +37,11 @@ class WhereParserTest extends FunSuite with Matchers with TestCommonWithModels { val ts = System.currentTimeMillis() val dummyTs = LabelMeta.timestamp -> InnerValLikeWithTs.withLong(ts, ts, label.schemaVersion) - def validate(label: Label)(edge: S2EdgeLike)(sql: String)(expected: Boolean) = { + def validate(label: Label)(element: GraphElement)(sql: String)(expected: Boolean) = { def debug(whereOpt: Try[Where]) = { println("==================") println(s"$whereOpt") - println(s"$edge") + println(s"$element") println("==================") } @@ -50,7 +50,7 @@ class WhereParserTest extends FunSuite with Matchers with TestCommonWithModels { debug(whereOpt) whereOpt.get // touch exception } else { - val ret = whereOpt.get.filter(edge) + val ret = whereOpt.get.filter(element) if (ret != expected) { debug(whereOpt) } @@ -294,4 +294,18 @@ class WhereParserTest extends FunSuite with Matchers with TestCommonWithModels { println(whereOpt) } + test("test vertex with WhereParser.") { + val service = Service.findByName(serviceName).getOrElse(throw new IllegalStateException(s"$serviceName is not found.")) + val column = ServiceColumn.find(service.id.get, columnName).getOrElse(throw new IllegalStateException(s"$columnName is not found.")) + + val vertexId = builder.newVertexId(service, column, 1) + val states = Map(ColumnMeta.lastModifiedAtColumn -> InnerVal.withLong(10, column.schemaVersion)) + val vertex = builder.newVertex(vertexId) + S2Vertex.fillPropsWithTs(vertex, states) + + val f = validate(label)(vertex) _ + f(s"lastModifiedAt < 1")(false) + f(s"lastModifiedAt > 1")(true) + f(s"lastModifiedAt = 10")(true) + } }