You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@s2graph.apache.org by st...@apache.org on 2018/06/18 07:04:22 UTC
[1/5] incubator-s2graph git commit: add Not logical operator on
WhereParser.
Repository: incubator-s2graph
Updated Branches:
refs/heads/master 1881df05c -> 2083d136e
add Not logical operator on WhereParser.
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/f288680c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/f288680c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/f288680c
Branch: refs/heads/master
Commit: f288680c46c23ac90fba1741baf494c061921277
Parents: 32eb344
Author: DO YUNG YOON <st...@apache.org>
Authored: Fri Jun 15 11:21:17 2018 +0900
Committer: DO YUNG YOON <st...@apache.org>
Committed: Fri Jun 15 11:21:17 2018 +0900
----------------------------------------------------------------------
.../apache/s2graph/core/parsers/WhereParser.scala | 16 ++++++++--------
.../s2graph/core/parsers/WhereParserTest.scala | 4 ++++
2 files changed, 12 insertions(+), 8 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f288680c/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..d6e176b 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
@@ -198,10 +198,14 @@ case class WhereParser() extends JavaTokenParsers {
def paren: Parser[Clause] = "(" ~> clause <~ ")"
- def clause: Parser[Clause] = (predicate | paren) * (and ^^^ { (a: Clause, b: Clause) => And(a, b) } | or ^^^ { (a: Clause, b: Clause) => Or(a, b) })
+ def clause: Parser[Clause] = (_not | predicate | paren) * (and ^^^ { (a: Clause, b: Clause) => And(a, b) } | or ^^^ { (a: Clause, b: Clause) => Or(a, b) })
def identWithDot: Parser[String] = repsep(ident, ".") ^^ { case values => values.mkString(".") }
+ val _not = "not|NOT".r ~ (predicate | paren) ^^ {
+ case op ~ p => Not(p)
+ }
+
val _eq = identWithDot ~ ("!=" | "=") ~ stringLiteral ^^ {
case f ~ op ~ s => if (op == "=") Eq(f, s) else Not(Eq(f, s))
}
@@ -219,14 +223,10 @@ case class WhereParser() extends JavaTokenParsers {
case f ~ minV ~ maxV => Between(f, minV, maxV)
}
- val _in = identWithDot ~ (notIn | in) ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
+ val _in = identWithDot ~ (in) ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
case f ~ op ~ values =>
- val inClause =
- if (f.startsWith("_parent")) IN(f, values.toSet)
- else InWithoutParent(f, values.toSet)
-
- if (op.toLowerCase == "in") inClause
- else Not(inClause)
+ if (f.startsWith("_parent")) IN(f, values.toSet)
+ else InWithoutParent(f, values.toSet)
}
val _contains = identWithDot ~ contains ~ stringLiteral ^^ {
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/f288680c/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..0ff4db1 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
@@ -46,6 +46,7 @@ class WhereParserTest extends FunSuite with Matchers with TestCommonWithModels {
}
val whereOpt = WhereParser().parse(sql)
+
if (whereOpt.isFailure) {
debug(whereOpt)
whereOpt.get // touch exception
@@ -138,6 +139,7 @@ class WhereParserTest extends FunSuite with Matchers with TestCommonWithModels {
f("time > 2")(true)
f("time <= 3")(true)
f("time < 2")(false)
+ f("NOT time >= 3")(false)
f("(time in (1, 2, 3) and is_blocked = true) or is_hidden = false")(false)
f("(time in (1, 2, 3) or is_blocked = true) or is_hidden = false")(true)
@@ -169,6 +171,8 @@ class WhereParserTest extends FunSuite with Matchers with TestCommonWithModels {
f(s"_from = ${tgtVertex.innerId.value} and _to = 102934")(false)
f(s"_from = -1")(false)
f(s"_from in (-1, -0.1)")(false)
+ f(s"NOT (_from = -1)")(true)
+ f(s"NOT _from contains 'a'")(true)
}
}
[4/5] incubator-s2graph git commit: run apache-rat on S2GRAPH-219
Posted by st...@apache.org.
run apache-rat on S2GRAPH-219
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/73624153
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/73624153
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/73624153
Branch: refs/heads/master
Commit: 73624153278edcee70769304a755956e22ac8bd8
Parents: 1881df0 a7ed4e8
Author: DO YUNG YOON <st...@apache.org>
Authored: Mon Jun 18 16:02:49 2018 +0900
Committer: DO YUNG YOON <st...@apache.org>
Committed: Mon Jun 18 16:02:49 2018 +0900
----------------------------------------------------------------------
.../s2graph/core/parsers/WhereParser.scala | 10 +++++++---
.../s2graph/core/parsers/WhereParserTest.scala | 4 ++++
.../graphql/middleware/GraphFormatWriter.scala | 19 +++++++++++++++++++
.../graphql/types/PlayJsonScalarType.scala | 19 +++++++++++++++++++
4 files changed, 49 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/73624153/s2graphql/src/main/scala/org/apache/s2graph/graphql/middleware/GraphFormatWriter.scala
----------------------------------------------------------------------
diff --cc s2graphql/src/main/scala/org/apache/s2graph/graphql/middleware/GraphFormatWriter.scala
index 91fea62,0000000..6dcc368
mode 100644,000000..100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/middleware/GraphFormatWriter.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/middleware/GraphFormatWriter.scala
@@@ -1,101 -1,0 +1,120 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++
+package org.apache.s2graph.graphql.middleware
+
+import org.apache.s2graph.core.schema.ServiceColumn
+import org.apache.s2graph.core.{GraphElement, S2EdgeLike, S2VertexLike}
+import org.apache.s2graph.graphql.types.PlayJsonScalarType
+import org.slf4s.LoggerFactory
+import play.api.libs.json._
+import sangria.execution._
+import sangria.schema.Context
+
+
+object GraphFormatted extends Middleware[Any] with MiddlewareAfterField[Any] with MiddlewareExtension[Any] {
+ implicit val logger = LoggerFactory.getLogger(this.getClass)
+
+ type QueryVal = java.util.concurrent.ConcurrentHashMap[GraphElement, Unit]
+
+ type FieldVal = Long
+
+
+ def beforeQuery(context: MiddlewareQueryContext[Any, _, _]) = {
+ new java.util.concurrent.ConcurrentHashMap[GraphElement, Unit]()
+ }
+
+ def afterQuery(queryVal: QueryVal, context: MiddlewareQueryContext[Any, _, _]) = ()
+
+ def toVertexId(v: S2VertexLike, c: ServiceColumn): String = {
+ val innerId = v.innerId.toIdString()
+
+ s"${c.service.serviceName}.${c.columnName}.${innerId}"
+ }
+
+ def toVertexJson(v: S2VertexLike, c: ServiceColumn): JsValue = {
+ Json.obj(
+ "id" -> toVertexId(v, c),
+ "label" -> v.innerId.toIdString()
+ )
+ }
+
+ def toEdgeJson(e: S2EdgeLike): JsValue = {
+ Json.obj(
+ "source" -> toVertexId(e.srcVertex, e.innerLabel.srcColumn),
+ "target" -> toVertexId(e.tgtVertex, e.innerLabel.tgtColumn),
+ "id" -> s"${toVertexId(e.srcVertex, e.innerLabel.srcColumn)}.${e.label()}.${toVertexId(e.tgtVertex, e.innerLabel.tgtColumn)}",
+ "label" -> e.label()
+ )
+ }
+
+ def afterQueryExtensions(queryVal: QueryVal,
+ context: MiddlewareQueryContext[Any, _, _]
+ ): Vector[Extension[_]] = {
+
+ import scala.collection.JavaConverters._
+ val elements = queryVal.keys().asScala.toVector
+
+ val edges = elements.collect { case e: S2EdgeLike => e }
+ val vertices = elements.collect { case v: S2VertexLike => v -> v.serviceColumn }
+ val verticesFromEdges = edges.flatMap { e =>
+ val label = e.innerLabel
+ Vector((e.srcVertex, label.srcColumn), (e.tgtVertex, label.srcColumn))
+ }
+
+ val verticesJson = (vertices ++ verticesFromEdges).map { case (v, c) => toVertexJson(v, c) }.distinct
+ val edgeJson = edges.map(toEdgeJson).distinct
+
+ val jsElements = Json.obj(
+ "nodes" -> verticesJson,
+ "edges" -> edgeJson
+ )
+
+ val graph = Json.obj("graph" -> jsElements)
+
+ /**
+ * nodes: [{id, label, x, y, size}, ..],
+ * edges: [{id, source, target, label}]
+ */
+ implicit val iu = PlayJsonScalarType.PlayJsonInputUnmarshaller
+ Vector(Extension[JsValue](graph))
+ }
+
+ def beforeField(queryVal: QueryVal, mctx: MiddlewareQueryContext[Any, _, _], ctx: Context[Any, _]) = {
+ continue(System.currentTimeMillis())
+ }
+
+ def afterField(queryVal: QueryVal, fieldVal: FieldVal, value: Any, mctx: MiddlewareQueryContext[Any, _, _], ctx: Context[Any, _]) = {
+ // logger.info(s"${ctx.parentType.name}.${ctx.field.name} = ${value.getClass.getName}")
+
+ value match {
+ case ls: Seq[_] => ls.foreach {
+ case e: GraphElement => queryVal.put(e, ())
+ case _ =>
+ }
+ case e: GraphElement => queryVal.put(e, ())
+ case _ =>
+ }
+
+ None
+ }
+}
+
+
+
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/73624153/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/PlayJsonScalarType.scala
----------------------------------------------------------------------
diff --cc s2graphql/src/main/scala/org/apache/s2graph/graphql/types/PlayJsonScalarType.scala
index 5149d36,0000000..fc7f1ce
mode 100644,000000..100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/PlayJsonScalarType.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/PlayJsonScalarType.scala
@@@ -1,112 -1,0 +1,131 @@@
++/*
++ * Licensed to the Apache Software Foundation (ASF) under one
++ * or more contributor license agreements. See the NOTICE file
++ * distributed with this work for additional information
++ * regarding copyright ownership. The ASF licenses this file
++ * to you under the Apache License, Version 2.0 (the
++ * "License"); you may not use this file except in compliance
++ * with the License. You may obtain a copy of the License at
++ *
++ * http://www.apache.org/licenses/LICENSE-2.0
++ *
++ * Unless required by applicable law or agreed to in writing,
++ * software distributed under the License is distributed on an
++ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
++ * KIND, either express or implied. See the License for the
++ * specific language governing permissions and limitations
++ * under the License.
++ */
++
+package org.apache.s2graph.graphql.types
+
+import play.api.libs.json._
+import sangria.ast
+import sangria.execution.Executor
+import sangria.marshalling.{ArrayMapBuilder, InputUnmarshaller, ResultMarshaller, ScalarValueInfo}
+import sangria.schema._
+import sangria.validation.{BigIntCoercionViolation, IntCoercionViolation, ValueCoercionViolation}
+import sangria.macros._
+
+import scala.concurrent.ExecutionContext.Implicits.global
+
+object PlayJsonScalarType {
+
+ implicit object CustomPlayJsonResultMarshaller extends ResultMarshaller {
+ type Node = JsValue
+ type MapBuilder = ArrayMapBuilder[Node]
+
+ def emptyMapNode(keys: Seq[String]) = new ArrayMapBuilder[Node](keys)
+
+ def addMapNodeElem(builder: MapBuilder, key: String, value: Node, optional: Boolean) = builder.add(key, value)
+
+ def mapNode(builder: MapBuilder) = JsObject(builder.toMap)
+
+ def mapNode(keyValues: Seq[(String, JsValue)]) = Json.toJson(keyValues.toMap)
+
+ def arrayNode(values: Vector[JsValue]) = JsArray(values)
+
+ def optionalArrayNodeValue(value: Option[JsValue]) = value match {
+ case Some(v) ⇒ v
+ case None ⇒ nullNode
+ }
+
+ def scalarNode(value: Any, typeName: String, info: Set[ScalarValueInfo]) = value match {
+ case v: String ⇒ JsString(v)
+ case v: Boolean ⇒ JsBoolean(v)
+ case v: Int ⇒ JsNumber(v)
+ case v: Long ⇒ JsNumber(v)
+ case v: Float ⇒ JsNumber(BigDecimal(v))
+ case v: Double ⇒ JsNumber(v)
+ case v: BigInt ⇒ JsNumber(BigDecimal(v))
+ case v: BigDecimal ⇒ JsNumber(v)
+ case v: JsValue ⇒ v
+ case v ⇒ throw new IllegalArgumentException("Unsupported scalar value: " + v)
+ }
+
+ def enumNode(value: String, typeName: String) = JsString(value)
+
+ def nullNode = JsNull
+
+ def renderCompact(node: JsValue) = Json.stringify(node)
+
+ def renderPretty(node: JsValue) = Json.prettyPrint(node)
+ }
+
+ implicit object PlayJsonInputUnmarshaller extends InputUnmarshaller[JsValue] {
+ def getRootMapValue(node: JsValue, key: String) = node.asInstanceOf[JsObject].value get key
+
+ def isListNode(node: JsValue) = node.isInstanceOf[JsArray]
+
+ def getListValue(node: JsValue) = node.asInstanceOf[JsArray].value
+
+ def isMapNode(node: JsValue) = node.isInstanceOf[JsObject]
+
+ def getMapValue(node: JsValue, key: String) = node.asInstanceOf[JsObject].value get key
+
+ def getMapKeys(node: JsValue) = node.asInstanceOf[JsObject].fields.map(_._1)
+
+ def isDefined(node: JsValue) = node != JsNull
+
+ def getScalarValue(node: JsValue) = node match {
+ case JsBoolean(b) ⇒ b
+ case JsNumber(d) ⇒ d.toBigIntExact getOrElse d
+ case JsString(s) ⇒ s
+ case n ⇒ n
+ }
+
+ def getScalaScalarValue(node: JsValue) = getScalarValue(node)
+
+ def isEnumNode(node: JsValue) = node.isInstanceOf[JsString]
+
+ def isScalarNode(node: JsValue) = true
+
+ def isVariableNode(node: JsValue) = false
+
+ def getVariableName(node: JsValue) = throw new IllegalArgumentException("variables are not supported")
+
+ def render(node: JsValue) = Json.stringify(node)
+ }
+
+ case object JsonCoercionViolation extends ValueCoercionViolation("Not valid JSON")
+
+ implicit val JsonType = ScalarType[JsValue]("Json",
+ description = Some("Raw PlayJson value"),
+ coerceOutput = (value, _) ⇒ value,
+ coerceUserInput = {
+ case v: String ⇒ Right(JsString(v))
+ case v: Boolean ⇒ Right(JsBoolean(v))
+ case v: Int ⇒ Right(JsNumber(v))
+ case v: Long ⇒ Right(JsNumber(v))
+ case v: Float ⇒ Right(JsNumber(BigDecimal(v)))
+ case v: Double ⇒ Right(JsNumber(v))
+ case v: BigInt ⇒ Right(JsNumber(BigDecimal(v)))
+ case v: BigDecimal ⇒ Right(JsNumber(v))
+ case v: JsValue ⇒ Right(v)
+ },
+ coerceInput = {
+ case sv: ast.StringValue => Right(Json.parse(sv.value))
+ case _ ⇒
+ Left(JsonCoercionViolation)
+ })
+}
[5/5] incubator-s2graph git commit: [S2GRAPH-222]: Support Not
logical operator in WhereParser.
Posted by st...@apache.org.
[S2GRAPH-222]: Support Not logical operator in WhereParser.
JIRA:
[S2GRAPH-222] https://issues.apache.org/jira/browse/S2GRAPH-222
Pull Request:
Closes #174
Author
DO YUNG YOON <st...@apache.org>
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/2083d136
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/2083d136
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/2083d136
Branch: refs/heads/master
Commit: 2083d136e058cbfdd762c11c3292418a75b5d2a4
Parents: 7362415
Author: DO YUNG YOON <st...@apache.org>
Authored: Mon Jun 18 16:04:03 2018 +0900
Committer: DO YUNG YOON <st...@apache.org>
Committed: Mon Jun 18 16:04:03 2018 +0900
----------------------------------------------------------------------
CHANGES | 1 +
1 file changed, 1 insertion(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/2083d136/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index a68ecef..b6bc0cd 100644
--- a/CHANGES
+++ b/CHANGES
@@ -95,6 +95,7 @@ Release Notes - S2Graph - Version 0.2.0
* [S2GRAPH-206] - Generalize machine learning model serving.
* [S2GRAPH-215] - Implement a Storage Backend for JDBC driver, such as H2, MySql using the Mutator and Fetcher interfaces.
* [S2GRAPH-219] - Added query that includes all vertices and associated edges for GraphVisualize.
+ * [S2GRAPH-222] - Support Not logical operator in WhereParser.
** Task
* [S2GRAPH-162] - Update year in the NOTICE file.
[2/5] incubator-s2graph git commit: remove not in.
Posted by st...@apache.org.
remove not in.
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/428c4535
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/428c4535
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/428c4535
Branch: refs/heads/master
Commit: 428c453506d3f89d22135f2518dc2a601f5070f8
Parents: f288680
Author: DO YUNG YOON <st...@apache.org>
Authored: Fri Jun 15 11:45:55 2018 +0900
Committer: DO YUNG YOON <st...@apache.org>
Committed: Fri Jun 15 11:45:55 2018 +0900
----------------------------------------------------------------------
.../main/scala/org/apache/s2graph/core/parsers/WhereParser.scala | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/428c4535/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 d6e176b..a212dbc 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
@@ -192,8 +192,6 @@ case class WhereParser() extends JavaTokenParsers {
val contains = "contains|CONTAINS".r
- val notIn = "not in|NOT IN".r
-
def where: Parser[Where] = rep(clause) ^^ (Where(_))
def paren: Parser[Clause] = "(" ~> clause <~ ")"
@@ -223,7 +221,7 @@ case class WhereParser() extends JavaTokenParsers {
case f ~ minV ~ maxV => Between(f, minV, maxV)
}
- val _in = identWithDot ~ (in) ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
+ val _in = identWithDot ~ in ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
case f ~ op ~ values =>
if (f.startsWith("_parent")) IN(f, values.toSet)
else InWithoutParent(f, values.toSet)
[3/5] incubator-s2graph git commit: revert removing 'not in' clause.
Posted by st...@apache.org.
revert removing 'not in' clause.
Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/a7ed4e8c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/a7ed4e8c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/a7ed4e8c
Branch: refs/heads/master
Commit: a7ed4e8c56d6ba9f629466f4c2128834881f7f6a
Parents: 428c453
Author: DO YUNG YOON <st...@apache.org>
Authored: Mon Jun 18 12:38:03 2018 +0900
Committer: DO YUNG YOON <st...@apache.org>
Committed: Mon Jun 18 12:38:03 2018 +0900
----------------------------------------------------------------------
.../org/apache/s2graph/core/parsers/WhereParser.scala | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/a7ed4e8c/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 a212dbc..4b9725e 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
@@ -190,8 +190,10 @@ case class WhereParser() extends JavaTokenParsers {
val in = "in|IN".r
- val contains = "contains|CONTAINS".r
+ val notIn = "not in|NOT IN".r
+ val contains = "contains|CONTAINS".r
+
def where: Parser[Where] = rep(clause) ^^ (Where(_))
def paren: Parser[Clause] = "(" ~> clause <~ ")"
@@ -221,10 +223,14 @@ case class WhereParser() extends JavaTokenParsers {
case f ~ minV ~ maxV => Between(f, minV, maxV)
}
- val _in = identWithDot ~ in ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
+ val _in = identWithDot ~ (notIn | in) ~ ("(" ~> repsep(stringLiteral, ",") <~ ")") ^^ {
case f ~ op ~ values =>
- if (f.startsWith("_parent")) IN(f, values.toSet)
- else InWithoutParent(f, values.toSet)
+ val inClause =
+ if (f.startsWith("_parent")) IN(f, values.toSet)
+ else InWithoutParent(f, values.toSet)
+
+ if (op.toLowerCase == "in") inClause
+ else Not(inClause)
}
val _contains = identWithDot ~ contains ~ stringLiteral ^^ {