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/04/05 08:41:29 UTC

[2/6] incubator-s2graph git commit: Changing query more intuitively by using `columnName` instead of `from/to` in label field name

Changing query more intuitively by using `columnName` instead of `from/to` in label field name


Project: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/commit/da15232c
Tree: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/tree/da15232c
Diff: http://git-wip-us.apache.org/repos/asf/incubator-s2graph/diff/da15232c

Branch: refs/heads/master
Commit: da15232cf151a89184f9be498db31e2f3877edf8
Parents: afc22d7
Author: daewon <da...@apache.org>
Authored: Tue Apr 3 15:27:58 2018 +0900
Committer: daewon <da...@apache.org>
Committed: Wed Apr 4 14:43:05 2018 +0900

----------------------------------------------------------------------
 .../apache/s2graph/graphql/GraphQLServer.scala  |   1 +
 .../apache/s2graph/graphql/bind/AstHelper.scala |   9 +
 .../s2graph/graphql/bind/Unmarshaller.scala     | 159 +++++++++
 .../s2graph/graphql/marshaller/package.scala    | 124 -------
 .../graphql/repository/GraphRepository.scala    |   5 -
 .../s2graph/graphql/resolver/Resolver.scala     |  28 --
 .../s2graph/graphql/types/ManagementType.scala  | 312 +++++++++++++++++
 .../graphql/types/S2ManagementType.scala        | 339 -------------------
 .../apache/s2graph/graphql/types/S2Type.scala   | 143 ++++----
 .../types/SangriaPlayJsonScalarType.scala       |  76 -----
 .../s2graph/graphql/types/SchemaDef.scala       |   4 +-
 .../s2graph/graphql/types/StaticType.scala      | 149 ++++++++
 .../apache/s2graph/graphql/types/package.scala  | 137 +-------
 .../apache/s2graph/graphql/ScenarioTest.scala   |  52 +--
 .../org/apache/s2graph/graphql/SchemaTest.scala |  12 +-
 .../org/apache/s2graph/graphql/TestGraph.scala  |   1 +
 16 files changed, 735 insertions(+), 816 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
index e4b43cc..dcddd01 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
@@ -29,6 +29,7 @@ import com.typesafe.config.ConfigFactory
 import org.apache.s2graph.core.S2Graph
 import org.apache.s2graph.core.utils.SafeUpdateCache
 import org.apache.s2graph.graphql.repository.GraphRepository
+import org.apache.s2graph.graphql.types.SchemaDef
 import org.slf4j.LoggerFactory
 import sangria.ast.Document
 import sangria.execution._

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/AstHelper.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/AstHelper.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/AstHelper.scala
new file mode 100644
index 0000000..ec1c04c
--- /dev/null
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/AstHelper.scala
@@ -0,0 +1,9 @@
+package org.apache.s2graph.graphql.bind
+
+object AstHelper {
+  def selectedFields(astFields: Seq[sangria.ast.Field]): Vector[String] = {
+    astFields.flatMap { f =>
+      f.selections.map(s => s.asInstanceOf[sangria.ast.Field].name)
+    }.toVector
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/Unmarshaller.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/Unmarshaller.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/Unmarshaller.scala
new file mode 100644
index 0000000..f7a360a
--- /dev/null
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/bind/Unmarshaller.scala
@@ -0,0 +1,159 @@
+/*
+ * 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.bind
+
+import org.apache.s2graph.core.Management.JsonModel._
+import org.apache.s2graph.core.mysqls.ServiceColumn
+import org.apache.s2graph.core.{S2EdgeLike, S2VertexLike}
+import org.apache.s2graph.graphql.repository.GraphRepository
+import org.apache.s2graph.graphql.types.S2Type._
+import sangria.marshalling._
+import sangria.schema.Context
+
+object Unmarshaller {
+  type RawNode = Map[String, Any]
+
+  def unwrap(any: Any): Any = any match {
+    case s: Some[_] => unwrap(s.get)
+    case v: Seq[_] => v.map(unwrap)
+    case m: Map[_, _] => m.mapValues(unwrap)
+    case _ => any
+  }
+
+  implicit object AddVertexParamFromInput extends FromInput[List[AddVertexParam]] {
+    val marshaller = CoercedScalaResultMarshaller.default
+
+    def fromResult(node: marshaller.Node) = {
+      val now = System.currentTimeMillis()
+      val map = unwrap(node).asInstanceOf[RawNode]
+
+      val params = map.flatMap { case (columnName, vls: Vector[_]) =>
+        vls.map { _m =>
+          val m = _m.asInstanceOf[RawNode]
+          val id = m("id")
+          val ts = m.getOrElse("timestamp", now).asInstanceOf[Long]
+
+          AddVertexParam(ts, id, columnName, props = m)
+        }
+      }
+
+      params.toList
+    }
+  }
+
+  implicit object AddEdgeParamFromInput extends FromInput[AddEdgeParam] {
+    val marshaller = CoercedScalaResultMarshaller.default
+
+    def fromResult(node: marshaller.Node) = {
+      val inputMap = unwrap(node).asInstanceOf[RawNode]
+      val now = System.currentTimeMillis()
+
+      val from = inputMap("from")
+      val to = inputMap("to")
+      val ts = inputMap.get("timestamp").map(_.asInstanceOf[Long]).getOrElse(now)
+      val dir = inputMap.get("direction").map(_.asInstanceOf[String]).getOrElse("out")
+      val props = inputMap
+
+      AddEdgeParam(ts, from, to, dir, props)
+    }
+  }
+
+  implicit object IndexFromInput extends FromInput[Index] {
+    val marshaller = CoercedScalaResultMarshaller.default
+
+    def fromResult(node: marshaller.Node) = {
+      val input = node.asInstanceOf[RawNode]
+      Index(input("name").asInstanceOf[String], input("propNames").asInstanceOf[Seq[String]])
+    }
+  }
+
+  implicit object PropFromInput extends FromInput[Prop] {
+    val marshaller = CoercedScalaResultMarshaller.default
+
+    def fromResult(node: marshaller.Node) = {
+      val input = node.asInstanceOf[RawNode]
+
+      val name = input("name").asInstanceOf[String]
+      val defaultValue = input("defaultValue").asInstanceOf[String]
+      val dataType = input("dataType").asInstanceOf[String]
+      val storeInGlobalIndex = input("storeInGlobalIndex").asInstanceOf[Boolean]
+
+      Prop(name, defaultValue, dataType, storeInGlobalIndex)
+    }
+  }
+
+  implicit object ServiceColumnParamFromInput extends FromInput[ServiceColumnParam] {
+    val marshaller = CoercedScalaResultMarshaller.default
+
+    def fromResult(node: marshaller.Node) = ServiceColumnParamsFromInput.fromResult(node).head
+  }
+
+  implicit object ServiceColumnParamsFromInput extends FromInput[Vector[ServiceColumnParam]] {
+    val marshaller = CoercedScalaResultMarshaller.default
+
+    def fromResult(node: marshaller.Node) = {
+      val input = unwrap(node.asInstanceOf[Map[String, Any]]).asInstanceOf[Map[String, Any]]
+
+      val partialServiceColumns = input.map { case (serviceName, serviceColumnMap) =>
+        val innerMap = serviceColumnMap.asInstanceOf[Map[String, Any]]
+        val columnName = innerMap("columnName").asInstanceOf[String]
+        val props = innerMap.get("props").toSeq.flatMap { case vs: Vector[_] =>
+          vs.map(PropFromInput.fromResult)
+        }
+
+        ServiceColumnParam(serviceName, columnName, props)
+      }
+
+      partialServiceColumns.toVector
+    }
+  }
+
+  def labelField(c: Context[GraphRepository, Any]): (S2VertexLike, String) = {
+    val vertex = c.value.asInstanceOf[S2VertexLike]
+    val dir = c.arg[String]("direction")
+
+    (vertex, dir)
+  }
+
+  def serviceColumnFieldOnService(column: ServiceColumn, c: Context[GraphRepository, Any]): (Seq[S2VertexLike], Boolean) = {
+    val ids = c.argOpt[Any]("id").toSeq ++ c.argOpt[List[Any]]("ids").toList.flatten
+    val vertices = ids.map(vid => c.ctx.toS2VertexLike(vid, column))
+
+    val columnFields = column.metasInvMap.keySet
+    val selectedFields = AstHelper.selectedFields(c.astFields)
+
+    val canSkipFetch = selectedFields.forall(f => f == "id" || !columnFields(f))
+
+    (vertices, canSkipFetch)
+  }
+
+  def serviceColumnFieldOnLabel(column: ServiceColumn, c: Context[GraphRepository, Any]): (S2VertexLike, Boolean) = {
+    val edge = c.value.asInstanceOf[S2EdgeLike]
+    val vertex = if (edge.getDirection() == "in") edge.srcForVertex else edge.tgtForVertex
+
+    val selectedFields = AstHelper.selectedFields(c.astFields)
+    val columnFields = column.metasInvMap.keySet
+
+    val canSkipFetch = selectedFields.forall(f => f == "id" || !columnFields(f))
+
+    (vertex, canSkipFetch)
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/marshaller/package.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/marshaller/package.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/marshaller/package.scala
deleted file mode 100644
index 3b675b3..0000000
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/marshaller/package.scala
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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
-
-import org.apache.s2graph.core.Management.JsonModel._
-import org.apache.s2graph.graphql.types.S2Type._
-import sangria.marshalling._
-import sangria.schema.Args
-
-package object marshaller {
-  type RawNode = Map[String, Any]
-
-  def unwrap(any: Any): Any = any match {
-    case s: Some[_] => unwrap(s.get)
-    case v: Seq[_] => v.map(unwrap)
-    case m: Map[_, _] => m.mapValues(unwrap)
-    case _ => any
-  }
-
-  implicit object AddVertexParamFromInput extends FromInput[List[AddVertexParam]] {
-    val marshaller = CoercedScalaResultMarshaller.default
-
-    def fromResult(node: marshaller.Node) = {
-      val now = System.currentTimeMillis()
-      val map = unwrap(node).asInstanceOf[RawNode]
-
-      val params = map.flatMap { case (columnName, vls: Vector[_]) =>
-        vls.map { _m =>
-          val m = _m.asInstanceOf[RawNode]
-          val id = m("id")
-          val ts = m.getOrElse("timestamp", now).asInstanceOf[Long]
-
-          AddVertexParam(ts, id, columnName, props = m)
-        }
-      }
-
-      params.toList
-    }
-  }
-
-  implicit object AddEdgeParamFromInput extends FromInput[AddEdgeParam] {
-    val marshaller = CoercedScalaResultMarshaller.default
-
-    def fromResult(node: marshaller.Node) = {
-      val inputMap = unwrap(node).asInstanceOf[RawNode]
-      val now = System.currentTimeMillis()
-
-      val from = inputMap("from")
-      val to = inputMap("to")
-      val ts = inputMap.get("timestamp").map(_.asInstanceOf[Long]).getOrElse(now)
-      val dir = inputMap.get("direction").map(_.asInstanceOf[String]).getOrElse("out")
-      val props = inputMap
-
-      AddEdgeParam(ts, from, to, dir, props)
-    }
-  }
-
-  implicit object IndexFromInput extends FromInput[Index] {
-    val marshaller = CoercedScalaResultMarshaller.default
-
-    def fromResult(node: marshaller.Node) = {
-      val input = node.asInstanceOf[RawNode]
-      Index(input("name").asInstanceOf[String], input("propNames").asInstanceOf[Seq[String]])
-    }
-  }
-
-  implicit object PropFromInput extends FromInput[Prop] {
-    val marshaller = CoercedScalaResultMarshaller.default
-
-    def fromResult(node: marshaller.Node) = {
-      val input = node.asInstanceOf[RawNode]
-
-      val name = input("name").asInstanceOf[String]
-      val defaultValue = input("defaultValue").asInstanceOf[String]
-      val dataType = input("dataType").asInstanceOf[String]
-      val storeInGlobalIndex = input("storeInGlobalIndex").asInstanceOf[Boolean]
-
-      Prop(name, defaultValue, dataType, storeInGlobalIndex)
-    }
-  }
-
-  implicit object ServiceColumnParamFromInput extends FromInput[ServiceColumnParam] {
-    val marshaller = CoercedScalaResultMarshaller.default
-
-    def fromResult(node: marshaller.Node) = ServiceColumnParamsFromInput.fromResult(node).head
-  }
-
-  implicit object ServiceColumnParamsFromInput extends FromInput[Vector[ServiceColumnParam]] {
-    val marshaller = CoercedScalaResultMarshaller.default
-
-    def fromResult(node: marshaller.Node) = {
-      val input = unwrap(node.asInstanceOf[Map[String, Any]]).asInstanceOf[Map[String, Any]]
-
-      val partialServiceColumns = input.map { case (serviceName, serviceColumnMap) =>
-        val innerMap = serviceColumnMap.asInstanceOf[Map[String, Any]]
-        val columnName = innerMap("columnName").asInstanceOf[String]
-        val props = innerMap.get("props").toSeq.flatMap { case vs: Vector[_] =>
-          vs.map(PropFromInput.fromResult)
-        }
-
-        ServiceColumnParam(serviceName, columnName, props)
-      }
-
-      partialServiceColumns.toVector
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
index a29d0fb..ca06bc8 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/repository/GraphRepository.scala
@@ -42,13 +42,8 @@ object GraphRepository {
 
     tryObj
   }
-
 }
 
-/**
-  *
-  * @param graph
-  */
 class GraphRepository(val graph: S2GraphLike) {
   implicit val logger = LoggerFactory.getLogger(this.getClass)
 

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/resolver/Resolver.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/resolver/Resolver.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/resolver/Resolver.scala
deleted file mode 100644
index 1a96d84..0000000
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/resolver/Resolver.scala
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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.resolver
-
-import org.apache.s2graph.core.S2VertexLike
-import org.apache.s2graph.graphql.repository.GraphRepository
-
-object Resolver {
-  def vertexResolver(v: S2VertexLike)(implicit repo: GraphRepository) {
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
new file mode 100644
index 0000000..d07feeb
--- /dev/null
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
@@ -0,0 +1,312 @@
+/*
+ * 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 org.apache.s2graph.core.mysqls._
+import org.apache.s2graph.graphql.repository.GraphRepository
+import sangria.schema._
+
+import scala.language.existentials
+import scala.util.{Failure, Success, Try}
+import org.apache.s2graph.graphql.types.S2Type.{ServiceColumnParam}
+
+object ManagementType {
+
+  import sangria.schema._
+
+  case class MutationResponse[T](result: Try[T])
+
+  def makeMutationResponseType[T](name: String, desc: String, tpe: ObjectType[_, T]): ObjectType[Unit, MutationResponse[T]] = {
+    val retType = ObjectType(
+      name,
+      desc,
+      () => fields[Unit, MutationResponse[T]](
+        Field("isSuccess",
+          BooleanType,
+          resolve = _.value.result.isSuccess
+        ),
+        Field("message",
+          StringType,
+          resolve = _.value.result match {
+            case Success(_) => s"Mutation successful"
+            case Failure(ex) => ex.getMessage
+          }
+        ),
+        Field("object",
+          OptionType(tpe),
+          resolve = _.value.result.toOption
+        )
+      )
+    )
+
+    retType
+  }
+}
+
+class ManagementType(repo: GraphRepository) {
+
+  import ManagementType._
+  import sangria.macros.derive._
+  import org.apache.s2graph.graphql.bind.Unmarshaller._
+  import org.apache.s2graph.graphql.types.StaticTypes._
+
+  lazy val serviceColumnOnServiceWithPropInputObjectFields = repo.allServices.map { service =>
+    InputField(service.serviceName, OptionInputType(InputObjectType(
+      s"Input_${service.serviceName}_ServiceColumn_Props",
+      description = "desc here",
+      fields = List(
+        InputField("columnName", makeServiceColumnEnumTypeOnService(service)),
+        InputField("props", ListInputType(InputPropType))
+      )
+    )))
+  }
+
+  lazy val serviceColumnOnServiceInputObjectFields = repo.allServices.map { service =>
+    InputField(service.serviceName, OptionInputType(InputObjectType(
+      s"Input_${service.serviceName}_ServiceColumn",
+      description = "desc here",
+      fields = List(
+        InputField("columnName", makeServiceColumnEnumTypeOnService(service))
+      )
+    )))
+  }
+
+  def makeServiceColumnEnumTypeOnService(service: Service): EnumType[String] = {
+    val columns = service.serviceColumns(false).toList
+    EnumType(
+      s"Enum_${service.serviceName}_ServiceColumn",
+      description = Option("desc here"),
+      values = dummyEnum +: columns.map { column =>
+        EnumValue(column.columnName, value = column.columnName)
+      }
+    )
+  }
+
+  lazy val labelPropsInputFields = repo.allLabels().map { label =>
+    InputField(label.label, OptionInputType(InputObjectType(
+      s"Input_${label.label}_props",
+      description = "desc here",
+      fields = List(
+        InputField("props", ListInputType(InputPropType))
+      )
+    )))
+  }
+
+  lazy val ServiceType = deriveObjectType[GraphRepository, Service](
+    ObjectTypeName("Service"),
+    ObjectTypeDescription("desc here"),
+    RenameField("serviceName", "name"),
+    AddFields(
+      Field("serviceColumns", ListType(ServiceColumnType), resolve = c => c.value.serviceColumns(false).toList)
+    )
+  )
+
+  lazy val ServiceColumnType = deriveObjectType[GraphRepository, ServiceColumn](
+    ObjectTypeName("ServiceColumn"),
+    ObjectTypeDescription("desc here"),
+    RenameField("columnName", "name"),
+    AddFields(
+      Field("props", ListType(ColumnMetaType),
+        resolve = c => c.value.metasWithoutCache.filter(ColumnMeta.isValid)
+      )
+    )
+  )
+
+  val dummyEnum = EnumValue("_", value = "_")
+
+  lazy val ServiceListType = EnumType(
+    s"Enum_Service",
+    description = Option("desc here"),
+    values =
+      dummyEnum +: repo.allServices.map { service =>
+        EnumValue(service.serviceName, value = service.serviceName)
+      }
+  )
+
+  lazy val ServiceColumnListType = EnumType(
+    s"Enum_ServiceColumn",
+    description = Option("desc here"),
+    values =
+      dummyEnum +: repo.allServiceColumns.map { serviceColumn =>
+        EnumValue(serviceColumn.columnName, value = serviceColumn.columnName)
+      }
+  )
+
+  lazy val EnumLabelsType = EnumType(
+    s"Enum_Label",
+    description = Option("desc here"),
+    values =
+      dummyEnum +: repo.allLabels().map { label =>
+        EnumValue(label.label, value = label.label)
+      }
+  )
+
+  lazy val ServiceMutationResponseType = makeMutationResponseType[Service](
+    "MutateService",
+    "desc here",
+    ServiceType
+  )
+
+  lazy val ServiceColumnMutationResponseType = makeMutationResponseType[ServiceColumn](
+    "MutateServiceColumn",
+    "desc here",
+    ServiceColumnType
+  )
+
+  lazy val LabelMutationResponseType = makeMutationResponseType[Label](
+    "MutateLabel",
+    "desc here",
+    LabelType
+  )
+
+  lazy val labelsField: Field[GraphRepository, Any] = Field(
+    "Labels",
+    ListType(LabelType),
+    description = Option("desc here"),
+    arguments = List(LabelNameArg),
+    resolve = { c =>
+      c.argOpt[String]("name") match {
+        case Some(name) => c.ctx.allLabels().filter(_.label == name)
+        case None => c.ctx.allLabels()
+      }
+    }
+  )
+
+  val serviceOptArgs = List(
+    "compressionAlgorithm" -> CompressionAlgorithmType,
+    "cluster" -> StringType,
+    "hTableName" -> StringType,
+    "preSplitSize" -> IntType,
+    "hTableTTL" -> IntType
+  ).map { case (name, _type) => Argument(name, OptionInputType(_type)) }
+
+  val AddPropServiceType = InputObjectType[ServiceColumnParam](
+    "Input_Service_ServiceColumn_Props",
+    description = "desc",
+    fields = DummyInputField +: serviceColumnOnServiceWithPropInputObjectFields
+  )
+
+  val ServiceColumnSelectType = InputObjectType[ServiceColumnParam](
+    "Input_Service_ServiceColumn",
+    description = "desc",
+    fields = DummyInputField +: serviceColumnOnServiceInputObjectFields
+  )
+
+  val InputServiceType = InputObjectType[ServiceColumnParam](
+    "Input_Service",
+    description = "desc",
+    fields = DummyInputField +: serviceColumnOnServiceInputObjectFields
+  )
+
+  lazy val servicesField: Field[GraphRepository, Any] = Field(
+    "Services",
+    ListType(ServiceType),
+    description = Option("desc here"),
+    arguments = List(ServiceNameArg),
+    resolve = { c =>
+      c.argOpt[String]("name") match {
+        case Some(name) => c.ctx.allServices.filter(_.serviceName == name)
+        case None => c.ctx.allServices
+      }
+    }
+  )
+
+  /**
+    * Query Fields
+    * Provide s2graph management query API
+    */
+  lazy val queryFields: List[Field[GraphRepository, Any]] = List(servicesField, labelsField)
+
+  /**
+    * Mutation fields
+    * Provide s2graph management mutate API
+    *
+    * - createService
+    * - createLabel
+    * - ...
+    */
+
+  lazy val labelRequiredArg = List(
+    Argument("sourceService", InputServiceType),
+    Argument("targetService", InputServiceType)
+  )
+
+  val labelOptsArgs = List(
+    Argument("serviceName", OptionInputType(ServiceListType)),
+    Argument("consistencyLevel", OptionInputType(ConsistencyLevelType)),
+    Argument("isDirected", OptionInputType(BooleanType)),
+    Argument("isAsync", OptionInputType(BooleanType)),
+    Argument("schemaVersion", OptionInputType(StringType))
+  )
+
+  val NameArg = Argument("name", StringType, description = "desc here")
+
+  lazy val ServiceNameArg = Argument("name", OptionInputType(ServiceListType), description = "desc here")
+
+  lazy val ServiceNameRawArg = Argument("serviceName", ServiceListType, description = "desc here")
+
+  lazy val ColumnNameArg = Argument("columnName", OptionInputType(ServiceColumnListType), description = "desc here")
+
+  lazy val ColumnTypeArg = Argument("columnType", DataTypeType, description = "desc here")
+
+  lazy val LabelNameArg = Argument("name", OptionInputType(EnumLabelsType), description = "desc here")
+
+  lazy val PropArg = Argument("props", OptionInputType(ListInputType(InputPropType)), description = "desc here")
+
+  lazy val IndicesArg = Argument("indices", OptionInputType(ListInputType(InputIndexType)), description = "desc here")
+
+  lazy val mutationFields: List[Field[GraphRepository, Any]] = List(
+    Field("createService",
+      ServiceMutationResponseType,
+      arguments = NameArg :: serviceOptArgs,
+      resolve = c => MutationResponse(c.ctx.createService(c.args))
+    ),
+    Field("createLabel",
+      LabelMutationResponseType,
+      arguments = NameArg :: PropArg :: IndicesArg :: labelRequiredArg ::: labelOptsArgs,
+      resolve = c => MutationResponse(c.ctx.createLabel(c.args))
+    ),
+    Field("deleteLabel",
+      LabelMutationResponseType,
+      arguments = LabelNameArg :: Nil,
+      resolve = c => MutationResponse(c.ctx.deleteLabel(c.args))
+    ),
+    Field("createServiceColumn",
+      ServiceColumnMutationResponseType,
+      arguments = List(ServiceNameRawArg, Argument("columnName", StringType), ColumnTypeArg, PropArg),
+      resolve = c => MutationResponse(c.ctx.createServiceColumn(c.args))
+    ),
+    Field("deleteServiceColumn",
+      ServiceColumnMutationResponseType,
+      arguments = Argument("service", ServiceColumnSelectType) :: Nil,
+      resolve = c => MutationResponse(c.ctx.deleteServiceColumn(c.args))
+    ),
+    Field("addPropsToServiceColumn",
+      ServiceColumnMutationResponseType,
+      arguments = Argument("service", AddPropServiceType) :: Nil,
+      resolve = c => MutationResponse(c.ctx.addPropsToServiceColumn(c.args))
+    ),
+    Field("addPropsToLabel",
+      LabelMutationResponseType,
+      arguments = Argument("labelName", EnumLabelsType) :: PropArg :: Nil,
+      resolve = c => MutationResponse(c.ctx.addPropsToLabel(c.args))
+    )
+  )
+}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2ManagementType.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2ManagementType.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2ManagementType.scala
deleted file mode 100644
index 18df00b..0000000
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2ManagementType.scala
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- * 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 org.apache.s2graph.core.Management.JsonModel._
-import org.apache.s2graph.core._
-import org.apache.s2graph.core.mysqls._
-import org.apache.s2graph.core.storage.MutateResponse
-import org.apache.s2graph.graphql._
-import org.apache.s2graph.graphql.repository.GraphRepository
-import play.api.libs.json.JsValue
-import sangria.marshalling._
-import sangria.schema._
-
-import scala.language.existentials
-import scala.util.{Failure, Success, Try}
-import org.apache.s2graph.graphql.marshaller._
-import org.apache.s2graph.graphql.types.S2Type.{ServiceColumnParam}
-
-object S2ManagementType {
-
-  import sangria.schema._
-
-  case class MutationResponse[T](result: Try[T])
-
-  def makeMutationResponseType[T](name: String, desc: String, tpe: ObjectType[_, T]): ObjectType[Unit, MutationResponse[T]] = {
-    val retType = ObjectType(
-      name,
-      desc,
-      () => fields[Unit, MutationResponse[T]](
-        Field("isSuccess",
-          BooleanType,
-          resolve = _.value.result.isSuccess
-        ),
-        Field("message",
-          StringType,
-          resolve = _.value.result match {
-            case Success(_) => s"Mutation successful"
-            case Failure(ex) => ex.getMessage
-          }
-        ),
-        Field("object",
-          OptionType(tpe),
-          resolve = _.value.result.toOption
-        )
-      )
-    )
-
-    retType
-  }
-}
-
-class S2ManagementType(repo: GraphRepository) {
-
-  import S2ManagementType._
-
-  import sangria.macros.derive._
-
-  lazy val serviceColumnOnServiceWithPropInputObjectFields = repo.allServices.map { service =>
-    InputField(service.serviceName, OptionInputType(InputObjectType(
-      s"Input_${service.serviceName}_ServiceColumn_Props",
-      description = "desc here",
-      fields = List(
-        InputField("columnName", makeServiceColumnEnumTypeOnService(service)),
-        InputField("props", ListInputType(InputPropType))
-      )
-    )))
-  }
-
-  lazy val serviceColumnOnServiceInputObjectFields = repo.allServices.map { service =>
-    InputField(service.serviceName, OptionInputType(InputObjectType(
-      s"Input_${service.serviceName}_ServiceColumn",
-      description = "desc here",
-      fields = List(
-        InputField("columnName", makeServiceColumnEnumTypeOnService(service))
-      )
-    )))
-  }
-
-  def makeServiceColumnEnumTypeOnService(service: Service): EnumType[String] = {
-    val columns = service.serviceColumns(false).toList
-    EnumType(
-      s"Enum_${service.serviceName}_ServiceColumn",
-      description = Option("desc here"),
-      values = dummyEnum +: columns.map { column =>
-        EnumValue(column.columnName, value = column.columnName)
-      }
-    )
-  }
-
-  lazy val labelPropsInputFields = repo.allLabels().map { label =>
-    InputField(label.label, OptionInputType(InputObjectType(
-      s"Input_${label.label}_props",
-      description = "desc here",
-      fields = List(
-        InputField("props", ListInputType(InputPropType))
-      )
-    )))
-  }
-
-  lazy val ServiceType = deriveObjectType[GraphRepository, Service](
-    ObjectTypeName("Service"),
-    ObjectTypeDescription("desc here"),
-    RenameField("serviceName", "name"),
-    AddFields(
-      Field("serviceColumns", ListType(ServiceColumnType), resolve = c => c.value.serviceColumns(false).toList)
-    )
-  )
-
-  lazy val ServiceColumnType = deriveObjectType[GraphRepository, ServiceColumn](
-    ObjectTypeName("ServiceColumn"),
-    ObjectTypeDescription("desc here"),
-    RenameField("columnName", "name"),
-    AddFields(
-      Field("props", ListType(ColumnMetaType),
-        resolve = c => c.value.metasWithoutCache.filter(ColumnMeta.isValid)
-      )
-    )
-  )
-
-  val dummyEnum = EnumValue("_", value = "_")
-
-  lazy val ServiceListType = EnumType(
-    s"Enum_Service",
-    description = Option("desc here"),
-    values =
-      dummyEnum +: repo.allServices.map { service =>
-        EnumValue(service.serviceName, value = service.serviceName)
-      }
-  )
-
-  lazy val ServiceColumnListType = EnumType(
-    s"Enum_ServiceColumn",
-    description = Option("desc here"),
-    values =
-      dummyEnum +: repo.allServiceColumns.map { serviceColumn =>
-        EnumValue(serviceColumn.columnName, value = serviceColumn.columnName)
-      }
-  )
-
-  lazy val EnumLabelsType = EnumType(
-    s"Enum_Label",
-    description = Option("desc here"),
-    values =
-      dummyEnum +: repo.allLabels().map { label =>
-        EnumValue(label.label, value = label.label)
-      }
-  )
-
-  lazy val ServiceMutationResponseType = makeMutationResponseType[Service](
-    "MutateService",
-    "desc here",
-    ServiceType
-  )
-
-  lazy val ServiceColumnMutationResponseType = makeMutationResponseType[ServiceColumn](
-    "MutateServiceColumn",
-    "desc here",
-    ServiceColumnType
-  )
-
-  lazy val LabelMutationResponseType = makeMutationResponseType[Label](
-    "MutateLabel",
-    "desc here",
-    LabelType
-  )
-
-  lazy val labelField: Field[GraphRepository, Any] = Field(
-    "Label",
-    OptionType(LabelType),
-    description = Option("desc here"),
-    arguments = Argument("name", EnumLabelsType, description = "desc here") :: Nil,
-    resolve = { c =>
-      val labelName = c.arg[String]("name")
-      c.ctx.allLabels().find(_.label == labelName)
-    }
-  )
-
-  lazy val labelsField: Field[GraphRepository, Any] = Field(
-    "Labels",
-    ListType(LabelType),
-    description = Option("desc here"),
-    arguments = List(LabelNameArg),
-    resolve = { c =>
-      c.argOpt[String]("name") match {
-        case Some(name) => c.ctx.allLabels().filter(_.label == name)
-        case None => c.ctx.allLabels()
-      }
-    }
-  )
-
-  val serviceOptArgs = List(
-    "compressionAlgorithm" -> CompressionAlgorithmType,
-    "cluster" -> StringType,
-    "hTableName" -> StringType,
-    "preSplitSize" -> IntType,
-    "hTableTTL" -> IntType
-  ).map { case (name, _type) => Argument(name, OptionInputType(_type)) }
-
-  val AddPropServiceType = InputObjectType[ServiceColumnParam](
-    "Input_Service_ServiceColumn_Props",
-    description = "desc",
-    fields = DummyInputField +: serviceColumnOnServiceWithPropInputObjectFields
-  )
-
-  val ServiceColumnSelectType = InputObjectType[ServiceColumnParam](
-    "Input_Service_ServiceColumn",
-    description = "desc",
-    fields = DummyInputField +: serviceColumnOnServiceInputObjectFields
-  )
-
-  val InputServiceType = InputObjectType[ServiceColumnParam](
-    "Input_Service",
-    description = "desc",
-    fields = DummyInputField +: serviceColumnOnServiceInputObjectFields
-  )
-
-  lazy val serviceField: Field[GraphRepository, Any] = Field(
-    "Service",
-    OptionType(ServiceType),
-    description = Option("desc here"),
-    arguments = Argument("name", ServiceListType, description = "desc here") :: Nil,
-    resolve = { c =>
-      val serviceName = c.arg[String]("name")
-      c.ctx.allServices.find(_.serviceName == serviceName)
-    }
-  )
-
-  lazy val servicesField: Field[GraphRepository, Any] = Field(
-    "Services",
-    ListType(ServiceType),
-    description = Option("desc here"),
-    arguments = List(ServiceNameArg),
-    resolve = { c =>
-      c.argOpt[String]("name") match {
-        case Some(name) => c.ctx.allServices.filter(_.serviceName == name)
-        case None => c.ctx.allServices
-      }
-    }
-  )
-  /**
-    * Query Fields
-    * Provide s2graph management query API
-    */
-  lazy val queryFields: List[Field[GraphRepository, Any]] = List(serviceField, servicesField, labelField, labelsField)
-
-  /**
-    * Mutation fields
-    * Provide s2graph management mutate API
-    *
-    * - createService
-    * - createLabel
-    * - ...
-    */
-
-  lazy val labelRequiredArg = List(
-    Argument("sourceService", InputServiceType),
-    Argument("targetService", InputServiceType)
-  )
-
-  val labelOptsArgs = List(
-    Argument("serviceName", OptionInputType(ServiceListType)),
-    Argument("consistencyLevel", OptionInputType(ConsistencyLevelType)),
-    Argument("isDirected", OptionInputType(BooleanType)),
-    Argument("isAsync", OptionInputType(BooleanType)),
-    Argument("schemaVersion", OptionInputType(StringType))
-  )
-
-  val NameArg = Argument("name", StringType, description = "desc here")
-
-  lazy val ServiceNameArg = Argument("name", OptionInputType(ServiceListType), description = "desc here")
-
-  lazy val ServiceNameRawArg = Argument("serviceName", ServiceListType, description = "desc here")
-
-  lazy val ColumnNameArg = Argument("columnName", OptionInputType(ServiceColumnListType), description = "desc here")
-
-  lazy val ColumnTypeArg = Argument("columnType", DataTypeType, description = "desc here")
-
-  lazy val LabelNameArg = Argument("name", OptionInputType(EnumLabelsType), description = "desc here")
-
-  lazy val PropArg = Argument("props", OptionInputType(ListInputType(InputPropType)), description = "desc here")
-
-  lazy val IndicesArg = Argument("indices", OptionInputType(ListInputType(InputIndexType)), description = "desc here")
-
-  lazy val mutationFields: List[Field[GraphRepository, Any]] = List(
-    Field("createService",
-      ServiceMutationResponseType,
-      arguments = NameArg :: serviceOptArgs,
-      resolve = c => MutationResponse(c.ctx.createService(c.args))
-    ),
-    Field("createLabel",
-      LabelMutationResponseType,
-      arguments = NameArg :: PropArg :: IndicesArg :: labelRequiredArg ::: labelOptsArgs,
-      resolve = c => MutationResponse(c.ctx.createLabel(c.args))
-    ),
-    Field("deleteLabel",
-      LabelMutationResponseType,
-      arguments = LabelNameArg :: Nil,
-      resolve = c => MutationResponse(c.ctx.deleteLabel(c.args))
-    ),
-    Field("createServiceColumn",
-      ServiceColumnMutationResponseType,
-      arguments = List(ServiceNameRawArg, Argument("columnName", StringType), ColumnTypeArg, PropArg),
-      resolve = c => MutationResponse(c.ctx.createServiceColumn(c.args))
-    ),
-    Field("deleteServiceColumn",
-      ServiceColumnMutationResponseType,
-      arguments = Argument("service", ServiceColumnSelectType) :: Nil,
-      resolve = c => MutationResponse(c.ctx.deleteServiceColumn(c.args))
-    ),
-    Field("addPropsToServiceColumn",
-      ServiceColumnMutationResponseType,
-      arguments = Argument("service", AddPropServiceType) :: Nil,
-      resolve = c => MutationResponse(c.ctx.addPropsToServiceColumn(c.args))
-    ),
-    Field("addPropsToLabel",
-      LabelMutationResponseType,
-      arguments = Argument("labelName", EnumLabelsType) :: PropArg :: Nil,
-      resolve = c => MutationResponse(c.ctx.addPropsToLabel(c.args))
-    )
-  )
-}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
index dc00ce2..eff0350 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/S2Type.scala
@@ -19,14 +19,16 @@
 
 package org.apache.s2graph.graphql.types
 
+import scala.concurrent._
 import org.apache.s2graph.core.Management.JsonModel.{Index, Prop}
 import org.apache.s2graph.core._
 import org.apache.s2graph.core.mysqls._
 import org.apache.s2graph.graphql.repository.GraphRepository
 import sangria.schema._
+import org.apache.s2graph.graphql.bind.{AstHelper, Unmarshaller}
+import org.apache.s2graph.graphql.types.StaticTypes._
 
 import scala.language.existentials
-import org.apache.s2graph.graphql.marshaller._
 
 object S2Type {
 
@@ -81,9 +83,9 @@ object S2Type {
 
   def makeInputFieldsOnService(service: Service): Seq[InputField[Any]] = {
     val inputFields = service.serviceColumns(false).map { serviceColumn =>
-      val idField = InputField("id", s2TypeToScalarType(serviceColumn.columnType))
+      val idField = InputField("id", toScalarType(serviceColumn.columnType))
       val propFields = serviceColumn.metasWithoutCache.filter(ColumnMeta.isValid).map { lm =>
-        InputField(lm.name, OptionInputType(s2TypeToScalarType(lm.dataType)))
+        InputField(lm.name, OptionInputType(toScalarType(lm.dataType)))
       }
 
       val vertexMutateType = InputObjectType[Map[String, Any]](
@@ -100,68 +102,62 @@ object S2Type {
 
   def makeInputFieldsOnLabel(label: Label): Seq[InputField[Any]] = {
     val propFields = label.labelMetaSet.toList.map { lm =>
-      InputField(lm.name, OptionInputType(s2TypeToScalarType(lm.dataType)))
+      InputField(lm.name, OptionInputType(toScalarType(lm.dataType)))
     }
 
     val labelFields = List(
       InputField("timestamp", OptionInputType(LongType)),
-      InputField("from", s2TypeToScalarType(label.srcColumnType)),
-      InputField("to", s2TypeToScalarType(label.srcColumnType)),
-      InputField("direction", OptionInputType(DirectionType))
+      InputField("from", toScalarType(label.srcColumnType)),
+      InputField("to", toScalarType(label.srcColumnType)),
+      InputField("direction", OptionInputType(BothDirectionType))
     )
 
     labelFields.asInstanceOf[Seq[InputField[Any]]] ++ propFields.asInstanceOf[Seq[InputField[Any]]]
   }
 
-  def makeServiceColumnFields(column: ServiceColumn): List[Field[GraphRepository, Any]] = {
+  def makeServiceColumnFields(column: ServiceColumn, allLabels: Seq[Label]): List[Field[GraphRepository, Any]] = {
     val reservedFields = List("id" -> column.columnType, "timestamp" -> "long")
     val columnMetasKv = column.metasWithoutCache.filter(ColumnMeta.isValid).map { columnMeta => columnMeta.name -> columnMeta.dataType }
 
-    (reservedFields ++ columnMetasKv).map { case (k, v) => makePropField(k, v) }
-  }
+    val (sameLabel, diffLabel) = allLabels.toList.partition(l => l.srcColumn == l.tgtColumn)
 
-  def makeServiceField(service: Service, allLabels: List[Label])(implicit repo: GraphRepository): List[Field[GraphRepository, Any]] = {
-    lazy val columnsOnService = service.serviceColumns(false).toList.map { column =>
+    val outLabels = diffLabel.filter(l => column == l.srcColumn).distinct.toList
+    val inLabels = diffLabel.filter(l => column == l.tgtColumn).distinct.toList
+    val inOutLabels = sameLabel.filter(l => l.srcColumn == column && l.tgtColumn == column)
 
-      val outLabels = allLabels.filter { lb => column.id.get == lb.srcColumn.id.get }.distinct
-      val inLabels = allLabels.filter { lb => column.id.get == lb.tgtColumn.id.get }.distinct
+    lazy val columnFields = (reservedFields ++ columnMetasKv).map { case (k, v) => makePropField(k, v) }
 
-      lazy val vertexPropFields = makeServiceColumnFields(column)
+    lazy val outLabelFields: List[Field[GraphRepository, Any]] = outLabels.map(l => makeLabelField("out", l, allLabels))
+    lazy val inLabelFields: List[Field[GraphRepository, Any]] = inLabels.map(l => makeLabelField("in", l, allLabels))
+    lazy val inOutLabelFields: List[Field[GraphRepository, Any]] = inOutLabels.map(l => makeLabelField("both", l, allLabels))
+    lazy val propsType = wrapField(s"ServiceColumn_${column.service.serviceName}_${column.columnName}_props", "props", columnFields)
 
-      lazy val outLabelFields: List[Field[GraphRepository, Any]] =
-        outLabels.map(l => makeLabelField("out", l, allLabels))
+    lazy val labelFieldNameSet = (outLabels ++ inLabels ++ inOutLabels).map(_.label).toSet
 
-      lazy val inLabelFields: List[Field[GraphRepository, Any]] =
-        inLabels.map(l => makeLabelField("in", l, allLabels))
+    propsType :: inLabelFields ++ outLabelFields ++ inOutLabelFields ++ columnFields.filterNot(cf => labelFieldNameSet(cf.name))
+  }
 
-      lazy val connectedLabelType = ObjectType(
-        s"Input_${service.serviceName}_${column.columnName}",
-        () => fields[GraphRepository, Any](vertexPropFields ++ (inLabelFields ++ outLabelFields): _*)
+  def makeServiceField(service: Service, allLabels: List[Label])(implicit repo: GraphRepository): List[Field[GraphRepository, Any]] = {
+    lazy val columnsOnService = service.serviceColumns(false).toList.map { column =>
+      lazy val serviceColumnFields = makeServiceColumnFields(column, allLabels)
+      lazy val ColumnType = ObjectType(
+        s"ServiceColumn_${service.serviceName}_${column.columnName}",
+        () => fields[GraphRepository, Any](serviceColumnFields: _*)
       )
 
       val v = Field(column.columnName,
-        ListType(connectedLabelType),
+        ListType(ColumnType),
         arguments = List(
-          Argument("id", OptionInputType(s2TypeToScalarType(column.columnType))),
-          Argument("ids", OptionInputType(ListInputType(s2TypeToScalarType(column.columnType)))),
-          Argument("search", OptionInputType(StringType))
+          Argument("id", OptionInputType(toScalarType(column.columnType))),
+          Argument("ids", OptionInputType(ListInputType(toScalarType(column.columnType))))
         ),
         description = Option("desc here"),
         resolve = c => {
           implicit val ec = c.ctx.ec
+          val (vertices, canSkipFetchVertex) = Unmarshaller.serviceColumnFieldOnService(column, c)
 
-          val ids = c.argOpt[Any]("id").toSeq ++ c.argOpt[List[Any]]("ids").toList.flatten
-          val vertices = ids.map(vid => c.ctx.toS2VertexLike(vid, column))
-
-          val columnFields = column.metasInvMap.keySet
-          val selectedFields = c.astFields.flatMap { f =>
-            f.selections.map(s => s.asInstanceOf[sangria.ast.Field].name)
-          }
-
-          val passFetchVertex = selectedFields.forall(f => f == "id" || !columnFields(f))
-
-          if (passFetchVertex) scala.concurrent.Future.successful(vertices)
-          else repo.getVertices(vertices) // fill props
+          if (canSkipFetchVertex) Future.successful(vertices)
+          else c.ctx.getVertices(vertices)
         }
       ): Field[GraphRepository, Any]
 
@@ -171,72 +167,48 @@ object S2Type {
     columnsOnService
   }
 
-  def fillPartialVertex(vertex: S2VertexLike,
-                        column: ServiceColumn,
-                        c: Context[GraphRepository, Any]): scala.concurrent.Future[S2VertexLike] = {
-    implicit val ec = c.ctx.ec
-
-    val columnFields = column.metasInvMap.keySet
-    val selectedFields = c.astFields.flatMap { f =>
-      f.selections.map(s => s.asInstanceOf[sangria.ast.Field].name)
-    }
-
-    // Vertex on edge has invalid `serviceColumn` info
-    lazy val newVertex = c.ctx.toS2VertexLike(vertex.innerId, column)
-
-    val passFetchVertex = selectedFields.forall(f => f == "id" || !columnFields(f))
-
-    if (passFetchVertex) scala.concurrent.Future.successful(vertex)
-    else c.ctx.getVertices(Seq(newVertex)).map(_.head) // fill props
-  }
-
-  def makeLabelField(dir: String, label: Label, allLabels: List[Label]): Field[GraphRepository, Any] = {
+  def makeLabelField(dir: String, label: Label, allLabels: Seq[Label]): Field[GraphRepository, Any] = {
     val labelReserved = List("direction" -> "string", "timestamp" -> "long")
     val labelProps = label.labelMetas.map { lm => lm.name -> lm.dataType }
 
-    lazy val edgeFields: List[Field[GraphRepository, Any]] =
-      (labelReserved ++ labelProps).map { case (k, v) => makePropField(k, v) }
-
     val column = if (dir == "out") label.tgtColumn else label.srcColumn
 
-    lazy val toType = ObjectType(s"Label_${label.label}_${column.columnName}", () => {
-      lazy val linked = if (dir == "out") {
-        val inLabels = allLabels.filter { lb => column.id.get == lb.tgtColumn.id.get }.distinct
-        inLabels.map(l => makeLabelField("in", l, allLabels))
-      } else {
-        val outLabels = allLabels.filter { lb => column.id.get == lb.srcColumn.id.get }.distinct
-        outLabels.map(l => makeLabelField("out", l, allLabels))
-      }
+    lazy val labelFields: List[Field[GraphRepository, Any]] =
+      (labelReserved ++ labelProps).map { case (k, v) => makePropField(k, v) }
 
-      makeServiceColumnFields(column) ++ linked
-    })
+    lazy val labelPropField = wrapField(s"Label_${label.label}_props", "props", labelFields)
 
-    lazy val toField: Field[GraphRepository, Any] = Field(column.columnName, toType, resolve = c => {
-      val vertex = if (dir == "out") {
-        c.value.asInstanceOf[S2EdgeLike].tgtVertex
-      } else {
-        c.value.asInstanceOf[S2EdgeLike].srcVertex
-      }
+    lazy val labelColumnType = ObjectType(s"Label_${label.label}_${column.columnName}",
+      () => makeServiceColumnFields(column, allLabels)
+    )
 
-      fillPartialVertex(vertex, column, c)
+    lazy val serviceColumnField: Field[GraphRepository, Any] = Field(column.columnName, labelColumnType, resolve = c => {
+      implicit val ec = c.ctx.ec
+      val (vertex, canSkipFetchVertex) = Unmarshaller.serviceColumnFieldOnLabel(column, c)
+
+      if (canSkipFetchVertex) Future.successful(vertex)
+      else c.ctx.getVertices(Seq(vertex)).map(_.head) // fill props
     })
 
     lazy val EdgeType = ObjectType(
       s"Label_${label.label}_${column.columnName}_${dir}",
-      () => fields[GraphRepository, Any](List(toField) ++ edgeFields: _*)
+      () => fields[GraphRepository, Any](
+        List(serviceColumnField, labelPropField) ++ labelFields.filterNot(_.name == column.columnName): _*)
     )
 
+    val dirArgs = dir match {
+      case "in" => Argument("direction", OptionInputType(InDirectionType), "desc here", defaultValue = "in") :: Nil
+      case "out" => Argument("direction", OptionInputType(OutDirectionType), "desc here", defaultValue = "out") :: Nil
+      case "both" => Argument("direction", OptionInputType(BothDirectionType), "desc here", defaultValue = "out") :: Nil
+    }
+
     lazy val edgeTypeField: Field[GraphRepository, Any] = Field(
       s"${label.label}",
       ListType(EdgeType),
-      arguments = Argument("direction", OptionInputType(DirectionType), "desc here", defaultValue = "out") :: Nil,
+      arguments = dirArgs,
       description = Some("fetch edges"),
       resolve = { c =>
-        val vertex: S2VertexLike = c.value match {
-          case v: S2VertexLike => v
-          case _ => throw new IllegalArgumentException(s"ERROR: ${c.value.getClass}")
-        }
-
+        val (vertex, dir) = Unmarshaller.labelField(c)
         c.ctx.getEdges(vertex, label, dir)
       }
     )
@@ -249,6 +221,7 @@ object S2Type {
 class S2Type(repo: GraphRepository) {
 
   import S2Type._
+  import org.apache.s2graph.graphql.bind.Unmarshaller._
 
   implicit val graphRepository = repo
 

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SangriaPlayJsonScalarType.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SangriaPlayJsonScalarType.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SangriaPlayJsonScalarType.scala
deleted file mode 100644
index 723392c..0000000
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SangriaPlayJsonScalarType.scala
+++ /dev/null
@@ -1,76 +0,0 @@
-///*
-// * 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 sangria.ast._
-//import sangria.validation.ValueCoercionViolation
-//
-//// https://gist.github.com/OlegIlyenko/5b96f4b54f656aac226d3c4bc33fd2a6
-//
-//object PlayJsonPolyType {
-//
-//  import play.api.libs.json._
-//  import sangria.ast
-//  import sangria.schema._
-//
-//  case object JsonCoercionViolation extends ValueCoercionViolation("Not valid JSON")
-//
-//  def scalarTypeToJsValue(v: sangria.ast.Value): JsValue = v match {
-//    case v: IntValue => JsNumber(v.value)
-//    case v: BigIntValue => JsNumber(BigDecimal(v.value.bigInteger))
-//    case v: FloatValue => JsNumber(v.value)
-//    case v: BigDecimalValue => JsNumber(v.value)
-//    case v: StringValue => JsString(v.value)
-//    case v: BooleanValue => JsBoolean(v.value)
-//    case v: ListValue => JsNull
-//    case v: VariableValue => JsNull
-//    case v: NullValue => JsNull
-//    case v: ObjectValue => JsNull
-//    case _ => throw new RuntimeException("Error!")
-//  }
-//
-//  implicit val PolyType = ScalarType[JsValue]("Poly",
-//    description = Some("Type Poly = String | Number | Boolean"),
-//    coerceOutput = (value, _) ⇒ value match {
-//      case JsString(s) => s
-//      case JsNumber(n) => n
-//      case JsBoolean(b) => b
-//      case JsNull => null
-//      case _ => 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(v.toDouble))
-//      case v: Double => Right(JsNumber(v))
-//      case v: BigInt => Right(JsNumber(BigDecimal(v)))
-//      case v: BigDecimal => Right(JsNumber(v))
-//      case _ => Left(JsonCoercionViolation)
-//    },
-//    coerceInput = {
-//      case value: ast.StringValue => Right(JsString(value.value))
-//      case value: ast.IntValue => Right(JsNumber(value.value))
-//      case value: ast.FloatValue => Right(JsNumber(value.value))
-//      case value: ast.BigIntValue => Right(JsNumber(BigDecimal(value.value.bigInteger)))
-//      case _ => Left(JsonCoercionViolation)
-//    })
-//}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
index 6fa1bd1..27b0c50 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/SchemaDef.scala
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.s2graph.graphql
+package org.apache.s2graph.graphql.types
 
 import org.apache.s2graph.graphql.repository.GraphRepository
 import org.apache.s2graph.graphql.types._
@@ -33,7 +33,7 @@ class SchemaDef(g: GraphRepository) {
   import sangria.schema._
 
   val s2Type = new S2Type(g)
-  val s2ManagementType = new S2ManagementType(g)
+  val s2ManagementType = new ManagementType(g)
 
   val queryManagementFields = List(wrapField("QueryManagement", "Management", s2ManagementType.queryFields))
   val S2QueryType = ObjectType[GraphRepository, Any](

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/StaticType.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/StaticType.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/StaticType.scala
new file mode 100644
index 0000000..aca832c
--- /dev/null
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/StaticType.scala
@@ -0,0 +1,149 @@
+/*
+ * 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 org.apache.s2graph.core.Management.JsonModel._
+import org.apache.s2graph.core.{JSONParser, S2EdgeLike, S2VertexLike}
+import org.apache.s2graph.core.mysqls._
+import org.apache.s2graph.core.storage.MutateResponse
+import org.apache.s2graph.graphql.repository.GraphRepository
+import sangria.macros.derive._
+import sangria.schema._
+
+import scala.util.{Failure, Random, Success, Try}
+
+object StaticTypes {
+  val MutateResponseType = deriveObjectType[GraphRepository, MutateResponse](
+    ObjectTypeName("MutateGraphElement"),
+    ObjectTypeDescription("desc here"),
+    AddFields(
+      Field("isSuccess", BooleanType, resolve = c => c.value.isSuccess)
+    )
+  )
+
+  val DataTypeType = EnumType(
+    "Enum_DataType",
+    description = Option("desc here"),
+    values = List(
+      EnumValue("string", value = "string"),
+      EnumValue("int", value = "int"),
+      EnumValue("long", value = "long"),
+      EnumValue("double", value = "double"),
+      EnumValue("boolean", value = "boolean")
+    )
+  )
+
+  val InDirectionType = EnumType(
+    "Enum_Direction_In",
+    description = Option("desc here"),
+    values = List(
+      EnumValue("in", value = "in")
+    )
+  )
+
+  val OutDirectionType = EnumType(
+    "Enum_Direction_Out",
+    description = Option("desc here"),
+    values = List(
+      EnumValue("out", value = "out")
+    )
+  )
+  val BothDirectionType = EnumType(
+    "Enum_Direction_Both",
+    description = Option("desc here"),
+    values = List(
+      EnumValue("out", value = "out"),
+      EnumValue("in", value = "in")
+    )
+  )
+
+  val LabelMetaType = deriveObjectType[GraphRepository, LabelMeta](
+    ObjectTypeName("LabelMeta"),
+    ExcludeFields("seq", "labelId")
+  )
+
+  val ColumnMetaType = deriveObjectType[GraphRepository, ColumnMeta](
+    ObjectTypeName("ColumnMeta"),
+    ExcludeFields("seq", "columnId")
+  )
+
+  val InputIndexType = InputObjectType[Index](
+    "Input_Index",
+    description = "desc here",
+    fields = List(
+      InputField("name", StringType),
+      InputField("propNames", ListInputType(StringType))
+    )
+  )
+
+  val InputPropType = InputObjectType[Prop](
+    "Input_Prop",
+    description = "desc here",
+    fields = List(
+      InputField("name", StringType),
+      InputField("dataType", DataTypeType),
+      InputField("defaultValue", StringType),
+      InputField("storeInGlobalIndex", BooleanType)
+    )
+  )
+
+  val CompressionAlgorithmType = EnumType(
+    "Enum_CompressionAlgorithm",
+    description = Option("desc here"),
+    values = List(
+      EnumValue("gz", description = Option("desc here"), value = "gz"),
+      EnumValue("lz4", description = Option("desc here"), value = "lz4")
+    )
+  )
+
+  val ConsistencyLevelType = EnumType(
+    "Enum_Consistency",
+    description = Option("desc here"),
+    values = List(
+      EnumValue("weak", description = Option("desc here"), value = "weak"),
+      EnumValue("strong", description = Option("desc here"), value = "strong")
+    )
+  )
+
+  val LabelIndexType = deriveObjectType[GraphRepository, LabelIndex](
+    ObjectTypeName("LabelIndex"),
+    ObjectTypeDescription("desc here"),
+    ExcludeFields("seq", "metaSeqs", "formulars", "labelId")
+  )
+
+  val LabelType = deriveObjectType[GraphRepository, Label](
+    ObjectTypeName("Label"),
+    ObjectTypeDescription("desc here"),
+    AddFields(
+      Field("indices", ListType(LabelIndexType), resolve = c => c.value.indices),
+      Field("props", ListType(LabelMetaType), resolve = c => c.value.labelMetas)
+    ),
+    RenameField("label", "name")
+  )
+
+  val DummyInputField = InputField("_", OptionInputType(LongType))
+
+  val DummyObjectTypeField: Field[GraphRepository, Any] = Field(
+    "_",
+    OptionType(LongType),
+    description = Some("dummy field"),
+    resolve = _ => None
+  )
+}

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/package.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/package.scala b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/package.scala
index 754f377..2b648e2 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/package.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/package.scala
@@ -1,43 +1,16 @@
-/*
- * 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
 
-import org.apache.s2graph.core.Management.JsonModel._
-import org.apache.s2graph.core.{JSONParser, S2EdgeLike, S2VertexLike}
-import org.apache.s2graph.core.mysqls._
-import org.apache.s2graph.core.storage.MutateResponse
 import org.apache.s2graph.graphql.repository.GraphRepository
-import sangria.macros.derive._
 import sangria.schema._
 
-import scala.util.{Failure, Random, Success, Try}
-
 package object types {
 
-  def wrapField(objectName: String, fieldName: String, fields: List[Field[GraphRepository, Any]]): Field[GraphRepository, Any] = {
-    val ManagementType = ObjectType(objectName, fields = fields)
-    val f: Field[GraphRepository, Any] = Field(fieldName, ManagementType, resolve = c => c.value)
-    f
+  def wrapField(objectName: String, fieldName: String, fields: Seq[Field[GraphRepository, Any]]): Field[GraphRepository, Any] = {
+    val tpe = ObjectType(objectName, fields = fields.toList)
+    Field(fieldName, tpe, resolve = c => c.value): Field[GraphRepository, Any]
   }
 
-  def s2TypeToScalarType(from: String): ScalarType[_] = from match {
+  def toScalarType(from: String): ScalarType[_] = from match {
     case "string" => StringType
     case "int" => IntType
     case "integer" => IntType
@@ -47,106 +20,4 @@ package object types {
     case "boolean" => BooleanType
     case "bool" => BooleanType
   }
-
-  val MutateResponseType = deriveObjectType[GraphRepository, MutateResponse](
-    ObjectTypeName("MutateGraphElement"),
-    ObjectTypeDescription("desc here"),
-    AddFields(
-      Field("isSuccess", BooleanType, resolve = c => c.value.isSuccess)
-    )
-  )
-
-  val DataTypeType = EnumType(
-    "Enum_DataType",
-    description = Option("desc here"),
-    values = List(
-      EnumValue("string", value = "string"),
-      EnumValue("int", value = "int"),
-      EnumValue("long", value = "long"),
-      EnumValue("double", value = "double"),
-      EnumValue("boolean", value = "boolean")
-    )
-  )
-
-  val DirectionType = EnumType(
-    "Enum_Direction",
-    description = Option("desc here"),
-    values = List(
-      EnumValue("out", value = "out"),
-      EnumValue("in", value = "in")
-    )
-  )
-
-  val LabelMetaType = deriveObjectType[GraphRepository, LabelMeta](
-    ObjectTypeName("LabelMeta"),
-    ExcludeFields("seq", "labelId")
-  )
-
-  val ColumnMetaType = deriveObjectType[GraphRepository, ColumnMeta](
-    ObjectTypeName("ColumnMeta"),
-    ExcludeFields("seq", "columnId")
-  )
-
-  val InputIndexType = InputObjectType[Index](
-    "Input_Index",
-    description = "desc here",
-    fields = List(
-      InputField("name", StringType),
-      InputField("propNames", ListInputType(StringType))
-    )
-  )
-
-  val InputPropType = InputObjectType[Prop](
-    "Input_Prop",
-    description = "desc here",
-    fields = List(
-      InputField("name", StringType),
-      InputField("dataType", DataTypeType),
-      InputField("defaultValue", StringType),
-      InputField("storeInGlobalIndex", BooleanType)
-    )
-  )
-
-  val CompressionAlgorithmType = EnumType(
-    "Enum_CompressionAlgorithm",
-    description = Option("desc here"),
-    values = List(
-      EnumValue("gz", description = Option("desc here"), value = "gz"),
-      EnumValue("lz4", description = Option("desc here"), value = "lz4")
-    )
-  )
-
-  val ConsistencyLevelType = EnumType(
-    "Enum_Consistency",
-    description = Option("desc here"),
-    values = List(
-      EnumValue("weak", description = Option("desc here"), value = "weak"),
-      EnumValue("strong", description = Option("desc here"), value = "strong")
-    )
-  )
-
-  val LabelIndexType = deriveObjectType[GraphRepository, LabelIndex](
-    ObjectTypeName("LabelIndex"),
-    ObjectTypeDescription("desc here"),
-    ExcludeFields("seq", "metaSeqs", "formulars", "labelId")
-  )
-
-  val LabelType = deriveObjectType[GraphRepository, Label](
-    ObjectTypeName("Label"),
-    ObjectTypeDescription("desc here"),
-    AddFields(
-      Field("indices", ListType(LabelIndexType), resolve = c => c.value.indices),
-      Field("props", ListType(LabelMetaType), resolve = c => c.value.labelMetas)
-    ),
-    RenameField("label", "name")
-  )
-
-  val DummyInputField = InputField("_", OptionInputType(LongType))
-
-  val DummyObjectTypeField: Field[GraphRepository, Any] = Field(
-    "_",
-    OptionType(LongType),
-    description = Some("dummy field"),
-    resolve = _ => None
-  )
 }

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/test/scala/org/apache/s2graph/graphql/ScenarioTest.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/test/scala/org/apache/s2graph/graphql/ScenarioTest.scala b/s2graphql/src/test/scala/org/apache/s2graph/graphql/ScenarioTest.scala
index 8cbff19..81bf884 100644
--- a/s2graphql/src/test/scala/org/apache/s2graph/graphql/ScenarioTest.scala
+++ b/s2graphql/src/test/scala/org/apache/s2graph/graphql/ScenarioTest.scala
@@ -179,7 +179,7 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
 
           query {
             Management {
-              Service(name: kakao) {
+              Services(name: kakao) {
                 name
                 serviceColumns {
                   name
@@ -200,7 +200,7 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
           {
             "data": {
               "Management": {
-                "Service": {
+                "Services": [{
                   "name": "kakao",
                   "serviceColumns": [{
                     "name": "user",
@@ -209,7 +209,7 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
                       { "name": "gender", "dataType": "string" }
                     ]
                   }]
-                }
+                }]
               }
             }
           }
@@ -307,7 +307,7 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
 
           query {
             Management {
-              Label(name: friends) {
+              Labels(name: friends) {
                 name
                 props {
                   name
@@ -325,13 +325,13 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
           {
           	"data": {
           		"Management": {
-          			"Label": {
+          			"Labels": [{
           				"name": "friends",
           				"props": [{
           					"name": "score",
           					"dataType": "double"
           				}]
-          			}
+          			}]
           		}
           	}
           }
@@ -392,6 +392,9 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
                 id
                 age
                 gender
+                props {
+                  age
+                }
               }
             }
           }
@@ -406,11 +409,17 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
           			"user": [{
           				"id": "daewon",
           				"age": 20,
-                  "gender": "M"
+                  "gender": "M",
+                  "props": {
+                    "age": 20
+                  }
           			}, {
           				"id": "shon",
           				"age": 19,
-                  "gender": "F"
+                  "gender": "F",
+                  "props": {
+                    "age": 19
+                  }
           			}]
           		}
           	}
@@ -464,13 +473,16 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
           kakao {
             user(id: "daewon") {
               id
-              friends {
-                score
-                to {
+              friends(direction: out) {
+                props {
+                  score
+                }
+                score # shorcut score props
+                user {
                   id
                   age
                   friends(direction: in) {
-                    to {
+                    user {
                       id
                       age
                     }
@@ -492,12 +504,15 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
               "user" : [ {
                 "id" : "daewon",
                 "friends" : [ {
+                  "props" : {
+                    "score" : 0.9
+                  },
                   "score" : 0.9,
-                  "to" : {
+                  "user" : {
                     "id" : "shon",
                     "age" : 19,
                     "friends" : [ {
-                      "to" : {
+                      "user" : {
                         "id" : "daewon",
                         "age" : 20
                       },
@@ -564,14 +579,13 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
 
           query {
             Management {
-              Label(name: friends) {
+              Labels(name: friends) {
                 name
                 props {
                   name
                   dataType
                 }
               }
-
             }
           }
           """
@@ -586,7 +600,7 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
 
           query {
             Management {
-             Service(name: kakao) {
+             Services(name: kakao) {
                 serviceColumns {
                   name
                 }
@@ -602,9 +616,9 @@ class ScenarioTest extends FunSpec with Matchers with BeforeAndAfterAll {
         {
         	"data": {
         		"Management": {
-        			"Service": {
+        			"Services": [{
         				"serviceColumns": []
-        			}
+        			}]
         		}
         	}
         }

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/test/scala/org/apache/s2graph/graphql/SchemaTest.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/test/scala/org/apache/s2graph/graphql/SchemaTest.scala b/s2graphql/src/test/scala/org/apache/s2graph/graphql/SchemaTest.scala
index fdedfe9..8b2b3fe 100644
--- a/s2graphql/src/test/scala/org/apache/s2graph/graphql/SchemaTest.scala
+++ b/s2graphql/src/test/scala/org/apache/s2graph/graphql/SchemaTest.scala
@@ -69,7 +69,7 @@ class SchemaTest extends FunSuite with Matchers with BeforeAndAfterAll {
             Map("name" -> "Enum_CompressionAlgorithm"),
             Map("name" -> "Enum_Consistency"),
             Map("name" -> "Enum_DataType"),
-            Map("name" -> "Enum_Direction"),
+            Map("name" -> "Enum_Direction_Both"),
             Map("name" -> "Enum_Service"),
             Map("name" -> "Enum_Label"),
             Map("name" -> "Enum_kakao_ServiceColumn"),
@@ -102,14 +102,16 @@ class SchemaTest extends FunSuite with Matchers with BeforeAndAfterAll {
             Map("name" -> "Input_kakao_ServiceColumn_Props"),
             Map("name" -> "Input_kakao_ServiceColumn"),
 
-            Map("name" -> "Input_kakao_user"),
             Map("name" -> "Input_kakao_user_vertex_mutate"),
 
             Map("name" -> "Service_kakao"),
 
-            Map("name" -> "Label_friends"),
-            Map("name" -> "Label_friends_from"),
-            Map("name" -> "Label_friends_to"),
+            Map("name" -> "Label_friends_user"),
+            Map("name" -> "Label_friends_user_both"),
+
+            Map("name" -> "ServiceColumn_kakao_user_props"),
+            Map("name" -> "ServiceColumn_kakao_user"),
+            Map("name" -> "Label_friends_props"),
 
             // root object type
             Map("name" -> "Query"),

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/da15232c/s2graphql/src/test/scala/org/apache/s2graph/graphql/TestGraph.scala
----------------------------------------------------------------------
diff --git a/s2graphql/src/test/scala/org/apache/s2graph/graphql/TestGraph.scala b/s2graphql/src/test/scala/org/apache/s2graph/graphql/TestGraph.scala
index 8b3c0ae..46db9fc 100644
--- a/s2graphql/src/test/scala/org/apache/s2graph/graphql/TestGraph.scala
+++ b/s2graphql/src/test/scala/org/apache/s2graph/graphql/TestGraph.scala
@@ -25,6 +25,7 @@ import org.apache.s2graph.core.mysqls.{Label, Model, Service}
 import org.apache.s2graph.core.rest.RequestParser
 import org.apache.s2graph.core.{Management, S2Graph}
 import org.apache.s2graph.graphql.repository.GraphRepository
+import org.apache.s2graph.graphql.types.SchemaDef
 import play.api.libs.json._
 import sangria.ast.Document
 import sangria.execution.Executor