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 }