increase schema create speed

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

Branch: refs/heads/master
Commit: 014768af4f783ff30cf73e4ac7f06d636dc36f66
Parents: c8d3005
Author: daewon <dae...@apache.org>
Authored: Wed Jul 11 19:24:33 2018 +0900
Committer: daewon <dae...@apache.org>
Committed: Wed Jul 11 19:24:33 2018 +0900

----------------------------------------------------------------------
 .../apache/s2graph/core/schema/ColumnMeta.scala |   2 +
 .../apache/s2graph/core/schema/LabelIndex.scala |   2 +
 .../apache/s2graph/graphql/GraphQLServer.scala  |  23 ++-
 .../graphql/repository/GraphRepository.scala    |  87 +++++---
 .../s2graph/graphql/types/ManagementType.scala  |  35 ++--
 .../apache/s2graph/graphql/types/S2Type.scala   | 198 +++++++++++--------
 .../s2graph/graphql/types/SchemaDef.scala       |   5 +-
 7 files changed, 217 insertions(+), 135 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/s2core/src/main/scala/org/apache/s2graph/core/schema/ColumnMeta.scala
----------------------------------------------------------------------
diff --git 
a/s2core/src/main/scala/org/apache/s2graph/core/schema/ColumnMeta.scala 
b/s2core/src/main/scala/org/apache/s2graph/core/schema/ColumnMeta.scala
index e850541..b1aba3e 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/schema/ColumnMeta.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/schema/ColumnMeta.scala
@@ -136,6 +136,8 @@ object ColumnMeta extends SQLSyntaxSupport[ColumnMeta] {
       val cacheKey = className + s"columnId=${columnId}"
       (cacheKey -> ls)
     }.toList)
+
+    ls
   }
 
   def updateStoreInGlobalIndex(id: Int, storeInGlobalIndex: Boolean)(implicit 
session: DBSession = AutoSession): Try[Long] = Try {

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/s2core/src/main/scala/org/apache/s2graph/core/schema/LabelIndex.scala
----------------------------------------------------------------------
diff --git 
a/s2core/src/main/scala/org/apache/s2graph/core/schema/LabelIndex.scala 
b/s2core/src/main/scala/org/apache/s2graph/core/schema/LabelIndex.scala
index bb8425f..4209ca5 100644
--- a/s2core/src/main/scala/org/apache/s2graph/core/schema/LabelIndex.scala
+++ b/s2core/src/main/scala/org/apache/s2graph/core/schema/LabelIndex.scala
@@ -166,6 +166,8 @@ object LabelIndex extends SQLSyntaxSupport[LabelIndex] {
       val cacheKey = s"labelId=${labelId}"
       (className + cacheKey -> ls)
     }.toList)
+
+    ls
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/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 a4a61ff..3b61085 100644
--- a/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
+++ b/s2graphql/src/main/scala/org/apache/s2graph/graphql/GraphQLServer.scala
@@ -57,13 +57,14 @@ class GraphQLServer() {
 
   val config = ConfigFactory.load()
   val s2graph = new S2Graph(config)
-  val schemaCacheTTL = Try(config.getInt("schemaCacheTTL")).getOrElse(-1)
+  val schemaCacheTTL = Try(config.getInt("schemaCacheTTL")).getOrElse(3000)
   val withAdmin = Try(config.getBoolean("schemaCacheTTL")).getOrElse(false)
-  val s2Repository = new GraphRepository(s2graph)
+
   val schemaConfig = ConfigFactory.parseMap(Map(
     SafeUpdateCache.MaxSizeKey -> 1, SafeUpdateCache.TtlKey -> schemaCacheTTL
   ).asJava)
 
+  // Manage schema instance lifecycle
   val schemaCache = new SafeUpdateCache(schemaConfig)
 
   def updateEdgeFetcher(requestJSON: spray.json.JsValue)(implicit e: 
ExecutionContext): Try[Unit] = {
@@ -78,26 +79,26 @@ class GraphQLServer() {
     ret
   }
 
-  logger.info(s"schemaCacheTTL: ${schemaCacheTTL}")
-
   val schemaCacheKey = className + "s2Schema"
 
   schemaCache.put(schemaCacheKey, createNewSchema(withAdmin))
 
   /**
-    * In development mode(schemaCacheTTL = -1),
+    * In development mode(schemaCacheTTL = 1),
     * a new schema is created for each request.
     */
 
-  private def createNewSchema(withAdmin: Boolean): Schema[GraphRepository, 
Any] = {
+  private def createNewSchema(withAdmin: Boolean): (SchemaDef, 
GraphRepository) = {
     logger.info(s"Schema update start")
 
     val ts = System.currentTimeMillis()
-    val newSchema = new SchemaDef(s2Repository, withAdmin).S2GraphSchema
+
+    val s2Repository = new GraphRepository(s2graph)
+    val newSchema = new SchemaDef(s2Repository, withAdmin)
 
     logger.info(s"Schema updated: ${(System.currentTimeMillis() - ts) / 1000} 
sec")
 
-    newSchema
+    newSchema -> s2Repository
   }
 
   def formatError(error: Throwable): JsValue = error match {
@@ -125,14 +126,16 @@ class GraphQLServer() {
   def executeGraphQLQuery(query: Document, op: Option[String], vars: 
JsObject)(implicit e: ExecutionContext) = {
     import GraphRepository._
 
-    val s2schema = schemaCache.withCache(schemaCacheKey, broadcast = false, 
onEvict = onEvictSchema)(createNewSchema(withAdmin))
+    val (schemaDef, s2Repository) =
+      schemaCache.withCache(schemaCacheKey, broadcast = false, onEvict = 
onEvictSchema)(createNewSchema(withAdmin))
+
     val resolver: DeferredResolver[GraphRepository] = 
DeferredResolver.fetchers(vertexFetcher, edgeFetcher)
 
     val includeGrpaph = 
vars.fields.get("includeGraph").contains(spray.json.JsBoolean(true))
     val middleWares = if (includeGrpaph) GraphFormatted :: TransformMiddleWare 
else TransformMiddleWare
 
     Executor.execute(
-      s2schema,
+      schemaDef.schema,
       query,
       s2Repository,
       variables = vars,

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/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 1bac416..d5212c8 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
@@ -79,17 +79,80 @@ object GraphRepository {
 
     tryObj
   }
+
+  def services(): List[Service] = {
+    Service.findAll().distinct
+  }
+
+  def serviceColumns(): List[ServiceColumn] = {
+    val allServices = services().toSet
+
+    ServiceColumn
+      .findAll()
+      .filter(sc => allServices(sc.service))
+      .distinct
+  }
+
+  def labels() = {
+    val allServiceColumns = serviceColumns().toSet
+
+    Label
+      .findAll()
+      .filter(l => allServiceColumns(l.srcColumn) || 
allServiceColumns(l.tgtColumn))
+      .distinct
+  }
+
+  def labelIndices() = {
+    LabelIndex.findAll()
+  }
+
+  def labelMetas() = {
+    LabelMeta.findAll()
+  }
+
+  def columnMetas() = {
+    ColumnMeta.findAll()
+  }
 }
 
 class GraphRepository(val graph: S2GraphLike) {
+
   implicit val logger = LoggerFactory.getLogger(this.getClass)
 
   import GraphRepository._
 
+  implicit val ec = graph.ec
+
   val management = graph.management
   val parser = new RequestParser(graph)
 
-  implicit val ec = graph.ec
+  val services = GraphRepository.services()
+  val serviceColumns = GraphRepository.serviceColumns()
+  val columnMetas = GraphRepository.columnMetas()
+
+  val labels = GraphRepository.labels
+  val labelMetas = GraphRepository.labelMetas()
+  val labelIndices = GraphRepository.labelIndices()
+
+  val serviceColumnMap = services.map { s =>
+    s -> serviceColumns.filter(s.id.get == _.serviceId)
+  }.toMap
+
+  val labelMetaMap = labels.map { l =>
+    l -> labelMetas.filter(l.id.get == _.labelId)
+  }.toMap
+
+  val labelIndiceMap = labels.map { l =>
+    l -> labelIndices.filter(l.id.get == _.labelId)
+  }.toMap
+
+  val columnMetaMap = serviceColumns.map { sc =>
+    sc -> columnMetas.filter(sc.id.get == _.columnId)
+  }.toMap
+
+  val columnLabelMap = serviceColumns.map { sc =>
+    sc -> labels.filter(l => l.srcColumn == sc || l.tgtColumn == sc)
+  }.toMap
 
   def toS2EdgeLike(labelName: String, param: AddEdgeParam): S2EdgeLike = {
     graph.toEdge(
@@ -277,26 +340,4 @@ class GraphRepository(val graph: S2GraphLike) {
 
     withLogTryResponse("deleteLabel", deleteLabelTry)
   }
-
-  def services(): List[Service] = {
-    Service.findAll().distinct
-  }
-
-  def serviceColumns(): List[ServiceColumn] = {
-    val allServices = services().toSet
-
-    ServiceColumn
-      .findAll()
-      .filter(sc => allServices(sc.service))
-      .distinct
-  }
-
-  def labels() = {
-    val allServiceColumns = serviceColumns().toSet
-
-    Label
-      .findAll()
-      .filter(l => allServiceColumns(l.srcColumn) || 
allServiceColumns(l.tgtColumn))
-      .distinct
-  }
 }

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/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
index 7b57059..dd1ee87 100644
--- 
a/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
+++ 
b/s2graphql/src/main/scala/org/apache/s2graph/graphql/types/ManagementType.scala
@@ -67,11 +67,7 @@ class ManagementType(repo: GraphRepository) {
   import org.apache.s2graph.graphql.bind.Unmarshaller._
   import org.apache.s2graph.graphql.types.StaticTypes._
 
-  val services = repo.services()
-  val serviceColumns = repo.serviceColumns()
-  val labels = repo.labels()
-
-  lazy val serviceColumnOnServiceWithPropInputObjectFields = services.map { 
service =>
+  lazy val serviceColumnOnServiceWithPropInputObjectFields = repo.services.map 
{ service =>
     InputField(service.serviceName.toValidName, 
OptionInputType(InputObjectType(
       s"Input_${service.serviceName.toValidName}_ServiceColumn_Props",
       description = "desc here",
@@ -82,7 +78,7 @@ class ManagementType(repo: GraphRepository) {
     )))
   }
 
-  lazy val serviceColumnOnServiceInputObjectFields = services.map { service =>
+  lazy val serviceColumnOnServiceInputObjectFields = repo.services.map { 
service =>
     InputField(service.serviceName.toValidName, 
OptionInputType(InputObjectType(
       s"Input_${service.serviceName.toValidName}_ServiceColumn",
       description = "desc here",
@@ -93,7 +89,8 @@ class ManagementType(repo: GraphRepository) {
   }
 
   def makeServiceColumnEnumTypeOnService(service: Service): EnumType[String] = 
{
-    val columns = service.serviceColumns(false).toList
+    val columns = repo.serviceColumnMap(service)
+
     EnumType(
       s"Enum_${service.serviceName.toValidName}_ServiceColumn",
       description = Option("desc here"),
@@ -105,7 +102,7 @@ class ManagementType(repo: GraphRepository) {
     )
   }
 
-  lazy val labelPropsInputFields = labels.map { label =>
+  lazy val labelPropsInputFields = repo.labels.map { label =>
     InputField(label.label.toValidName, OptionInputType(InputObjectType(
       s"Input_${label.label.toValidName}_props",
       description = "desc here",
@@ -120,7 +117,7 @@ class ManagementType(repo: GraphRepository) {
     ObjectTypeDescription("desc here"),
     RenameField("serviceName", "name"),
     AddFields(
-      Field("serviceColumns", ListType(ServiceColumnType), resolve = c => 
c.value.serviceColumns(false).toList)
+      Field("serviceColumns", ListType(ServiceColumnType), resolve = c => 
c.value.serviceColumns(true).toList)
     )
   )
 
@@ -141,8 +138,8 @@ class ManagementType(repo: GraphRepository) {
     s"Enum_Service",
     description = Option("desc here"),
     values = {
-      if (services.isEmpty) dummyEnum :: Nil
-      else services.map { service =>
+      if (repo.services.isEmpty) dummyEnum :: Nil
+      else repo.services.map { service =>
         EnumValue(service.serviceName.toValidName, value = service.serviceName)
       }
     }
@@ -152,8 +149,8 @@ class ManagementType(repo: GraphRepository) {
     s"Enum_ServiceColumn",
     description = Option("desc here"),
     values = {
-      if (serviceColumns.isEmpty) dummyEnum :: Nil
-      else serviceColumns.map { serviceColumn =>
+      if (repo.serviceColumns.isEmpty) dummyEnum :: Nil
+      else repo.serviceColumns.map { serviceColumn =>
         EnumValue(serviceColumn.columnName.toValidName, value = 
serviceColumn.columnName)
       }
     }
@@ -163,8 +160,8 @@ class ManagementType(repo: GraphRepository) {
     s"Enum_Label",
     description = Option("desc here"),
     values = {
-      if (labels.isEmpty) dummyEnum :: Nil
-      else labels.map { label =>
+      if (repo.labels.isEmpty) dummyEnum :: Nil
+      else repo.labels.map { label =>
         EnumValue(label.label.toValidName, value = label.label)
       }
     }
@@ -195,8 +192,8 @@ class ManagementType(repo: GraphRepository) {
     arguments = List(LabelNameArg),
     resolve = { c =>
       c.argOpt[String]("name") match {
-        case Some(name) => c.ctx.labels().filter(_.label == name)
-        case None => c.ctx.labels()
+        case Some(name) => repo.labels.filter(_.label == name)
+        case None => repo.labels
       }
     }
   )
@@ -240,8 +237,8 @@ class ManagementType(repo: GraphRepository) {
     arguments = List(ServiceNameArg),
     resolve = { c =>
       c.argOpt[String]("name") match {
-        case Some(name) => c.ctx.services().filter(_.serviceName.toValidName 
== name)
-        case None => c.ctx.services()
+        case Some(name) => repo.services.filter(_.serviceName.toValidName == 
name)
+        case None => repo.services
       }
     }
   )

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/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 e41e838..3632525 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
@@ -27,7 +27,6 @@ import org.apache.s2graph.graphql.repository.GraphRepository
 import sangria.schema._
 import org.apache.s2graph.graphql.types.StaticTypes._
 
-import scala.collection.mutable
 import scala.language.existentials
 
 object S2Type {
@@ -69,10 +68,13 @@ object S2Type {
     }
   }
 
-  def makeInputFieldsOnService(service: Service): Seq[InputField[Any]] = {
-    val inputFields = service.serviceColumns(false).map { serviceColumn =>
+  def makeInputFieldsOnService(service: Service)(implicit repo: 
GraphRepository): Seq[InputField[Any]] = {
+    val serviceColumns = repo.serviceColumnMap(service)
+
+    val inputFields = serviceColumns.map { serviceColumn =>
+      val columnMetas = repo.columnMetaMap(serviceColumn)
       val idField = InputField("id", toScalarType(serviceColumn.columnType))
-      val propFields = 
serviceColumn.metasWithoutCache.filter(ColumnMeta.isValid).map { lm =>
+      val propFields = columnMetas.filter(ColumnMeta.isValid).map { lm =>
         InputField(lm.name.toValidName, 
OptionInputType(toScalarType(lm.dataType)))
       }
 
@@ -88,8 +90,10 @@ object S2Type {
     inputFields
   }
 
-  def makeInputFieldsOnLabel(label: Label): Seq[InputField[Any]] = {
-    val propFields = label.labelMetaSet.toList.filterNot(_.name == 
"timestamp").map { lm =>
+  def makeInputFieldsOnLabel(label: Label)(implicit repo: GraphRepository): 
Seq[InputField[Any]] = {
+    val labelMetaSet = repo.labelMetaMap(label)
+
+    val propFields = labelMetaSet.filterNot(_.name == "timestamp").map { lm =>
       InputField(lm.name.toValidName, 
OptionInputType(toScalarType(lm.dataType)))
     }
 
@@ -103,12 +107,14 @@ object S2Type {
     labelFields.asInstanceOf[Seq[InputField[Any]]] ++ 
propFields.asInstanceOf[Seq[InputField[Any]]]
   }
 
-  def makeServiceColumnFields(column: ServiceColumn,
-                              relatedLabels: Seq[Label])
-                             (typeCache: mutable.Map[String, 
ObjectType[GraphRepository, Any]]): List[Field[GraphRepository, Any]] = {
+  def makeServiceColumnFields(column: ServiceColumn)
+                             (implicit repo: GraphRepository): 
List[Field[GraphRepository, Any]] = {
+
+    val columnMetas = repo.columnMetaMap(column)
+    val relatedLabels = repo.columnLabelMap(column)
 
     val reservedFields = Vector("id" -> column.columnType, "timestamp" -> 
"long")
-    val columnMetasKv = 
column.metasWithoutCache.filter(ColumnMeta.isValid).map { columnMeta => 
columnMeta.name -> columnMeta.dataType }
+    val columnMetasKv = columnMetas.filter(ColumnMeta.isValid).map { 
columnMeta => columnMeta.name -> columnMeta.dataType }
 
     val (sameLabel, diffLabel) = relatedLabels.toList.partition(l => 
l.srcColumn == l.tgtColumn)
 
@@ -116,22 +122,27 @@ object S2Type {
     val inLabels = diffLabel.filter(l => column == l.tgtColumn).distinct
     val inOutLabels = sameLabel.filter(l => l.srcColumn == column && 
l.tgtColumn == column)
 
-    val columnFields = (reservedFields ++ columnMetasKv).map { case (k, v) => 
makeGraphElementField(k.toValidName, v) }
+    val columnFields = reservedFields.map { case (k, v) => 
makeGraphElementField(k.toValidName, v) }
+    val propFields = columnMetasKv.map { case (k, v) => 
makeGraphElementField(k.toValidName, v) }
+
+    val outLabelFields: List[Field[GraphRepository, Any]] = outLabels.map(l => 
toLabelFieldOnColumn("out", l))
+    val inLabelFields: List[Field[GraphRepository, Any]] = inLabels.map(l => 
toLabelFieldOnColumn("in", l))
+    val inOutLabelFields: List[Field[GraphRepository, Any]] = 
inOutLabels.map(l => toLabelFieldOnColumn("both", l))
 
-    val outLabelFields: List[Field[GraphRepository, Any]] = outLabels.map(l => 
toLabelFieldOnColumn("out", l, relatedLabels)(typeCache))
-    val inLabelFields: List[Field[GraphRepository, Any]] = inLabels.map(l => 
toLabelFieldOnColumn("in", l, relatedLabels)(typeCache))
-    val inOutLabelFields: List[Field[GraphRepository, Any]] = 
inOutLabels.map(l => toLabelFieldOnColumn("both", l, relatedLabels)(typeCache))
-    val propsType = 
wrapField(s"ServiceColumn_${column.service.serviceName.toValidName}_${column.columnName.toValidName}_props",
 "props", columnFields)
+    val propsType =
+      if (propFields.isEmpty) Nil
+      else List(wrapField(
+        
s"ServiceColumn_${column.service.serviceName.toValidName}_${column.columnName.toValidName}_props",
 "props", propFields))
 
-    val labelFieldNameSet = (outLabels ++ inLabels ++ 
inOutLabels).map(_.label.toValidName).toSet
+    lazy val labelFieldNameSet = (outLabels ++ inLabels ++ 
inOutLabels).map(_.label.toValidName).toSet
 
-    propsType :: inLabelFields ++ outLabelFields ++ inOutLabelFields ++ 
columnFields.filterNot(cf => labelFieldNameSet(cf.name.toValidName))
+    propsType ++ inLabelFields ++ outLabelFields ++ inOutLabelFields ++ 
columnFields
   }
 
-  def toLabelFieldOnColumn(dir: String, label: Label, relatedLabels: 
Seq[Label])
-                          (typeCache: mutable.Map[String, 
ObjectType[GraphRepository, Any]]): Field[GraphRepository, Any] = {
+  def toLabelFieldOnColumn(dir: String, label: Label)
+                          (implicit repo: GraphRepository): 
Field[GraphRepository, Any] = {
 
-    val LabelType = makeLabelType(dir, label, relatedLabels)(typeCache)
+    val LabelType = makeLabelType(dir, label)
 
     val dirArgs = dir match {
       case "in" => Argument("direction", OptionInputType(InDirectionType), 
"desc here", defaultValue = "in") :: Nil
@@ -139,12 +150,14 @@ object S2Type {
       case "both" => Argument("direction", OptionInputType(BothDirectionType), 
"desc here", defaultValue = "out") :: Nil
     }
 
+    val indices = repo.labelIndiceMap(label)
+
     val indexEnumType = EnumType(
       s"Label_Index_${label.label.toValidName}",
       description = Option("desc here"),
       values =
-        if (label.indices.isEmpty) EnumValue("_", value = "_") :: Nil
-        else label.indices.map(idx => EnumValue(idx.name.toValidName, value = 
idx.name))
+        if (indices.isEmpty) EnumValue("_", value = "_") :: Nil
+        else indices.map(idx => EnumValue(idx.name.toValidName, value = 
idx.name))
     )
 
     val paramArgs = List(
@@ -175,29 +188,24 @@ object S2Type {
   }
 
 
-  def makeColumnType(column: ServiceColumn, relatedLabels: Seq[Label])
-                    (typeCache: mutable.Map[String, 
ObjectType[GraphRepository, Any]]): ObjectType[GraphRepository, Any] = {
+  def makeColumnType(column: ServiceColumn)
+                    (implicit repo: GraphRepository): 
ObjectType[GraphRepository, Any] = {
 
     val objectName = 
s"ServiceColumn_${column.service.serviceName.toValidName}_${column.columnName.toValidName}"
 
-    typeCache.getOrElseUpdate(objectName, {
-      lazy val serviceColumnFields = makeServiceColumnFields(column, 
relatedLabels)(typeCache)
+    lazy val serviceColumnFields = makeServiceColumnFields(column)
 
-      val ColumnType = ObjectType(
-        objectName,
-        () => fields[GraphRepository, Any](serviceColumnFields: _*)
-      )
+    val ColumnType = ObjectType(
+      objectName,
+      () => fields[GraphRepository, Any](serviceColumnFields: _*)
+    )
 
-      ColumnType
-    })
+    ColumnType
   }
 
-  def makeServiceType(service: Service,
-                      relatedColumns: Seq[ServiceColumn],
-                      relatedLabels: Seq[Label])
-                     (typeCache: mutable.Map[String, 
ObjectType[GraphRepository, Any]]): ObjectType[GraphRepository, Any] = {
+  def makeServiceType(service: Service)(implicit repo: GraphRepository): 
ObjectType[GraphRepository, Any] = {
 
-    val _serviceFields = makeServiceFields(service, relatedColumns, 
relatedLabels)(typeCache)
+    val _serviceFields = makeServiceFields(service)
     val serviceFields = if (_serviceFields.isEmpty) DummyObjectTypeField :: 
_serviceFields else _serviceFields
 
     ObjectType(
@@ -206,12 +214,12 @@ object S2Type {
     )
   }
 
-  def makeServiceFields(service: Service, columns: Seq[ServiceColumn], 
relatedLabels: Seq[Label])
-                       (typeCache: mutable.Map[String, 
ObjectType[GraphRepository, Any]]): List[Field[GraphRepository, Any]] = {
+  def makeServiceFields(service: Service)(implicit repo: GraphRepository): 
List[Field[GraphRepository, Any]] = {
 
-    val columnsOnService = columns.map { column =>
+    val serviceColumns = repo.serviceColumnMap(service)
+    val columnsOnService = serviceColumns.map { column =>
 
-      val ColumnType = makeColumnType(column, relatedLabels)(typeCache)
+      val ColumnType = makeColumnType(column)
 
       Field(column.columnName.toValidName,
         ListType(ColumnType),
@@ -236,39 +244,41 @@ object S2Type {
     columnsOnService.toList
   }
 
-  def makeLabelType(dir: String, label: Label, relatedLabels: Seq[Label])
-                   (typeCache: mutable.Map[String, ObjectType[GraphRepository, 
Any]]): ObjectType[GraphRepository, Any] = {
+  def makeLabelType(dir: String, label: Label)
+                   (implicit repo: GraphRepository): 
ObjectType[GraphRepository, Any] = {
 
     val objectName = s"Label_${label.label.toValidName}_${dir}"
 
-    typeCache.getOrElseUpdate(objectName, {
-      lazy val labelFields = makeLabelFields(dir, label, 
relatedLabels)(typeCache)
+    lazy val labelFields = makeLabelFields(dir, label)
 
-      val LabelType = ObjectType(
-        objectName,
-        () => fields[GraphRepository, Any](labelFields: _*)
-      )
+    val LabelType = ObjectType(
+      objectName,
+      () => fields[GraphRepository, Any](labelFields: _*)
+    )
 
-      LabelType
-    })
+    LabelType
   }
 
-  def makeLabelFields(dir: String, label: Label, relatedLabels: Seq[Label])
-                     (typeCache: mutable.Map[String, 
ObjectType[GraphRepository, Any]]): List[Field[GraphRepository, Any]] = {
+  def makeLabelFields(dir: String, label: Label)
+                     (implicit repo: GraphRepository): 
List[Field[GraphRepository, Any]] = {
 
+    val relatedMetas = repo.labelMetaMap(label)
     val labelReserved = List("direction" -> "string", "timestamp" -> "long")
 
-    val labelProps = label.labelMetas
+    val labelProps = relatedMetas
       .filterNot(l => labelReserved.exists(kv => kv._1 == l.name))
       .map { lm => lm.name -> lm.dataType }
 
     val column = if (dir == "out") label.tgtColumn else label.srcColumn
 
-    val labelFields: List[Field[GraphRepository, Any]] =
-      (labelReserved ++ labelProps).map { case (k, v) => 
makeGraphElementField(k.toValidName, v) }
+    val labelFields = labelReserved.map { case (k, v) => 
makeGraphElementField(k.toValidName, v) }
+    val propFields = labelProps.map { case (k, v) => 
makeGraphElementField(k.toValidName, v) }
 
-    val labelPropField = wrapField(s"Label_${label.label.toValidName}_props", 
"props", labelFields)
-    val labelColumnType = makeColumnType(column, relatedLabels)(typeCache)
+    val labelPropField =
+      if (propFields.isEmpty) Nil
+      else List(wrapField(s"Label_${label.label.toValidName}_props", "props", 
propFields))
+
+    val labelColumnType = makeColumnType(column)
 
     val serviceColumnField: Field[GraphRepository, Any] =
       Field(column.columnName.toValidName, labelColumnType, resolve = c => {
@@ -278,42 +288,66 @@ object S2Type {
         
DeferredValue(GraphRepository.vertexFetcher.defer(vertexQueryParam)).map(m => 
m._2.head)
       })
 
-    List(serviceColumnField, labelPropField) ++ 
labelFields.filterNot(_.name.toValidName == column.columnName.toValidName)
+    List(serviceColumnField) ++ labelPropField ++ 
labelFields.filterNot(_.name.toValidName == column.columnName.toValidName)
+  }
+
+  def services(): List[Service] = {
+    Service.findAll().distinct
+  }
+
+  def serviceColumns(): List[ServiceColumn] = {
+    val allServices = services().toSet
+
+    ServiceColumn
+      .findAll()
+      .filter(sc => allServices(sc.service))
+      .distinct
+  }
+
+  def labels() = {
+    val allServiceColumns = serviceColumns().toSet
+
+    Label
+      .findAll()
+      .filter(l => allServiceColumns(l.srcColumn) || 
allServiceColumns(l.tgtColumn))
+      .distinct
+  }
+
+  def labelIndices() = {
+    LabelIndex.findAll()
+  }
+
+  def labelMetas() = {
+    LabelMeta.findAll()
+  }
+
+  def columnMetas() = {
+    ColumnMeta.findAll()
   }
 }
 
-class S2Type(repo: GraphRepository) {
+class S2Type(_repo: GraphRepository) {
+  implicit val repo = _repo
 
   import S2Type._
   import org.apache.s2graph.graphql.bind.Unmarshaller._
-  import scala.collection._
 
   /**
     * fields
     */
   val serviceFields: List[Field[GraphRepository, Any]] = {
-    val allColumns = repo.serviceColumns()
-    val allLabels = repo.labels()
-
-    val typeCache = mutable.Map.empty[String, ObjectType[GraphRepository, Any]]
 
-    repo.services().flatMap { service =>
-      val relatedColumns = allColumns.filter(_.service == service).toSet
-      val relatedLabels = allLabels.filter(l => relatedColumns(l.srcColumn) || 
relatedColumns(l.tgtColumn))
+    repo.services.flatMap { service =>
+      val ServiceType = makeServiceType(service)
 
-      if (relatedColumns.isEmpty) Nil
-      else {
-        val ServiceType = makeServiceType(service, relatedColumns.toVector, 
relatedLabels.distinct)(typeCache)
-
-        val f = Field(
-          service.serviceName.toValidName,
-          ServiceType,
-          description = Some(s"serviceName: ${service.serviceName}"),
-          resolve = _ => service
-        ): Field[GraphRepository, Any]
+      val f = Field(
+        service.serviceName.toValidName,
+        ServiceType,
+        description = Some(s"serviceName: ${service.serviceName}"),
+        resolve = _ => service
+      ): Field[GraphRepository, Any]
 
-        List(f)
-      }
+      List(f)
     }
   }
 
@@ -321,7 +355,7 @@ class S2Type(repo: GraphRepository) {
     * arguments
     */
   lazy val addVertexArg = {
-    val serviceArguments = repo.services().map { service =>
+    val serviceArguments = repo.services.map { service =>
       val serviceFields = DummyInputField +: makeInputFieldsOnService(service)
 
       val ServiceInputType = InputObjectType[List[AddVertexParam]](
@@ -335,7 +369,7 @@ class S2Type(repo: GraphRepository) {
   }
 
   lazy val addEdgeArg = {
-    val labelArguments = repo.labels().map { label =>
+    val labelArguments = repo.labels.map { label =>
       val labelFields = DummyInputField +: makeInputFieldsOnLabel(label)
       val labelInputType = InputObjectType[AddEdgeParam](
         s"Input_label_${label.label.toValidName}_param",

http://git-wip-us.apache.org/repos/asf/incubator-s2graph/blob/014768af/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 d094ee0..835cd0b 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
@@ -20,6 +20,9 @@
 package org.apache.s2graph.graphql.types
 
 import org.apache.s2graph.graphql.repository.GraphRepository
+import sangria.schema.ObjectType
+
+import scala.collection.mutable
 
 /**
   * S2Graph GraphQL schema.
@@ -60,5 +63,5 @@ class SchemaDef(g: GraphRepository, withAdmin: Boolean = 
false) {
     directives = directives
   )
 
-  val S2GraphSchema = s2Schema
+  val schema = s2Schema
 }

Reply via email to