Skip to content

Commit

Permalink
Merge pull request #93 from kazumatsudo/feature/future
Browse files Browse the repository at this point in the history
use Future
  • Loading branch information
kazumatsudo committed Jan 20, 2024
2 parents e8732cc + 8584eb6 commit ad5c8ef
Show file tree
Hide file tree
Showing 16 changed files with 633 additions and 556 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ wartremoverErrors ++= Warts.allBut(
Wart.AnyVal,
Wart.AutoUnboxing,
Wart.FinalCaseClass,
Wart.ImplicitParameter,
Wart.IterableOps,
Wart.JavaSerializable,
Wart.LeakingSealed,
Expand Down
91 changes: 41 additions & 50 deletions src/main/scala/Main.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,25 @@ import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSo
import usecase.{ByExhaustiveSearch, UsingSpecificKeyList}
import utils.{Config, FileUtility, JsonUtility}

import java.util.concurrent.Executors.newFixedThreadPool
import scala.concurrent.duration.Duration
import scala.concurrent.{Await, ExecutionContext, Future}
import scala.util.control.NonFatal
import scala.util.{Failure, Success, Using}

object Main extends StrictLogging {

// set gremlin server connection pool max size or less
implicit private val ec: ExecutionContext =
ExecutionContext.fromExecutor(newFixedThreadPool(1))

private val config: Config = Config.default

private def displayOperationResult(
processName: String,
result: Boolean
): Unit = {
private def displayOperationResult(result: Boolean): Unit = {
if (result) {
logger.info(s"$processName: success")
logger.info("generate SQL: success")
} else {
logger.warn(s"$processName: failure")
logger.error("generate SQL: failure")
}
}

Expand Down Expand Up @@ -54,55 +58,42 @@ object Main extends StrictLogging {
}

/* execute analysis method */
val (
verticesDdlResult,
verticesDmlResult,
edgesDdlResult,
edgesDmlResult
) = usecase.execute(checkUnique = false)
val result = usecase.execute(checkUnique = false)

/* output SQL */
verticesDdlResult.foreach { vertexDdl =>
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.ddlVertex,
vertexDdl.toSqlSentence
)
}
displayOperationResult(
"generate vertices DDL",
verticesDdlResult.nonEmpty
)
result.onComplete {
case Failure(exception) =>
logger.error(s"${exception.getMessage}", exception)

verticesDmlResult.foreach { vertexDml =>
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.dmlVertex,
vertexDml.toSqlSentence
)
}
displayOperationResult(
"generate vertices DML",
verticesDmlResult.nonEmpty
)
displayOperationResult(result = false)
sys.exit(1)
case Success(value) =>
/* output SQL */
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.ddlVertex,
value.verticesDdl.toSqlSentence
)
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.dmlVertex,
value.verticesDml.toSqlSentence
)
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.ddlEdge,
value.edgesDdl.toSqlSentence
)
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.dmlEdge,
value.edgesDml.toSqlSentence
)

edgesDdlResult.foreach { edgesDdlResult =>
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.ddlEdge,
edgesDdlResult.toSqlSentence
)
displayOperationResult(result = true)
sys.exit(0)
}
displayOperationResult("generate edges DDL", edgesDdlResult.nonEmpty)

edgesDmlResult.foreach { edgesDmlResult =>
FileUtility.writeSql(
config.sql.outputDirectory,
config.sql.dmlEdge,
edgesDmlResult.toSqlSentence
)
}
displayOperationResult("generate edges DML", edgesDmlResult.nonEmpty)
Await.result(Future.never, Duration.Inf)
}

/** generate DDL and Insert sentence from GraphDB
Expand Down
31 changes: 25 additions & 6 deletions src/main/scala/infrastructure/EdgeQuery.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import gremlin.scala.GremlinScala
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
import utils.Config

import scala.collection.SeqView
import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NonFatal

final case class EdgeQuery(
Expand All @@ -18,7 +20,9 @@ final case class EdgeQuery(
* @return
* the number of all edges
*/
def countAll: Long = GremlinScala(g.E()).count().head()
def countAll()(implicit ec: ExecutionContext): Future[Long] = Future(
GremlinScala(g.E()).count().head()
)

/** get in Edges List
*
Expand All @@ -27,8 +31,14 @@ final case class EdgeQuery(
* @return
* A list of Edge
*/
def getInEdgeList(vertex: GraphVertex): Seq[GraphEdge] = {
GremlinScala(g.V(vertex.id)).inE().toList().map(GraphEdge(_, config))
def getInEdgeList(
vertex: GraphVertex
)(implicit ec: ExecutionContext): Future[SeqView[GraphEdge]] = Future {
GremlinScala(g.V(vertex.id))
.inE()
.toList()
.view
.map(GraphEdge(_, config))
}

/** get Edges List
Expand All @@ -40,14 +50,17 @@ final case class EdgeQuery(
* @return
* A list of Edges based on the specified pagination parameters.
*/
def getList(start: Int, count: Int): Seq[GraphEdge] = {
def getList(start: Int, count: Int)(implicit
ec: ExecutionContext
): Future[SeqView[GraphEdge]] = Future {
require(start >= 0, "start must be positive.")
require(count >= 0, "count must be positive.")

try {
GremlinScala(g.E())
.range(start, start + count)
.toList()
.view
.map(GraphEdge(_, config))
} catch {
case NonFatal(e) =>
Expand All @@ -66,7 +79,13 @@ final case class EdgeQuery(
* @return
* A list of Edge
*/
def getOutEdgeList(vertex: GraphVertex): Seq[GraphEdge] = {
GremlinScala(g.V(vertex.id)).outE().toList().map(GraphEdge(_, config))
def getOutEdgeList(
vertex: GraphVertex
)(implicit ec: ExecutionContext): Future[SeqView[GraphEdge]] = Future {
GremlinScala(g.V(vertex.id))
.outE()
.toList()
.view
.map(GraphEdge(_, config))
}
}
31 changes: 15 additions & 16 deletions src/main/scala/infrastructure/VertexQuery.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import gremlin.scala.{GremlinScala, Key}
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
import utils.Config

import scala.collection.SeqView
import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NonFatal

final case class VertexQuery(
Expand All @@ -18,7 +20,9 @@ final case class VertexQuery(
* @return
* the number of all vertices
*/
def countAll: Long = GremlinScala(g.V()).count().head()
def countAll()(implicit ec: ExecutionContext): Future[Long] = Future {
GremlinScala(g.V()).count().head()
}

/** get Vertices List
*
Expand All @@ -29,23 +33,17 @@ final case class VertexQuery(
* @return
* A list of Vertices based on the specified pagination parameters.
*/
def getList(start: Int, count: Int): Seq[GraphVertex] = {
def getList(start: Int, count: Int)(implicit
ec: ExecutionContext
): Future[SeqView[GraphVertex]] = Future {
require(start >= 0, "start must be positive.")
require(count >= 0, "count must be positive.")

try {
GremlinScala(g.V())
.range(start, start + count)
.toList()
.map(GraphVertex(_, config))
} catch {
case NonFatal(e) =>
logger.error(
s"An exception has occurred when getVerticesList is called. start: $start, count: $count",
e
)
throw e
}
GremlinScala(g.V())
.range(start, start + count)
.toList()
.view
.map(GraphVertex(_, config))
}

/** get Vertices List searched by property key
Expand All @@ -63,13 +61,14 @@ final case class VertexQuery(
label: String,
key: String,
value: Any
): Seq[GraphVertex] = {
)(implicit ec: ExecutionContext): Future[SeqView[GraphVertex]] = Future {
require(label.nonEmpty, "label must not be empty.")
require(key.nonEmpty, "key must not be empty.")

GremlinScala(g.V())
.has(label, Key[Any](key), value)
.toList()
.view
.map(GraphVertex(_, config))
}
}
103 changes: 38 additions & 65 deletions src/main/scala/usecase/ByExhaustiveSearch.scala
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package usecase

import domain.table.ddl.TableList
import domain.table.dml.RecordList
import infrastructure.{EdgeQuery, VertexQuery}
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
import utils.Config

import scala.concurrent.{ExecutionContext, Future}

/** analyze all Vertices and Edges
*
* pros:
Expand All @@ -25,71 +25,44 @@ final case class ByExhaustiveSearch(

override def execute(
checkUnique: Boolean
): (
Option[TableList],
Option[RecordList],
Option[TableList],
Option[RecordList]
) = {

// 1. generate vertex SQL
val (verticesDdl, verticesDml) = {
val vertexQuery = VertexQuery(g, config)
val totalVertexCount = vertexQuery.countAll.toInt

(0 to totalVertexCount).view
.flatMap { start =>
vertexQuery
.getList(start, 1)
.headOption
.map(vertex =>
(
vertex.toDdl,
vertex.toDml
)
)
}
.reduce[(TableList, RecordList)] {
case (
(tableListAccumlator, dmlAccumlator),
(tableListCurrentValue, dmlCurrentValue)
) =>
(
tableListAccumlator.merge(tableListCurrentValue),
dmlAccumlator.merge(dmlCurrentValue, checkUnique)
)
}
}
)(implicit ec: ExecutionContext): Future[UsecaseResponse] = {

// 2. generate edge SQL
val (edgesDdl, edgesDml) = {
val edgeQuery = EdgeQuery(g, config)
val totalEdgeCount = edgeQuery.countAll.toInt
val vertexQuery = VertexQuery(g, config)
val edgeQuery = EdgeQuery(g, config)

(0 to totalEdgeCount).view
.flatMap { start =>
edgeQuery
.getList(start, 1)
.headOption
.map(edge =>
(
edge.toDdl,
edge.toDml
)
)
}
.reduce[(TableList, RecordList)] {
case (
(tableListAccumlator, dmlAccumlator),
(tableListCurrentValue, dmlCurrentValue)
) =>
(
tableListAccumlator.merge(tableListCurrentValue),
dmlAccumlator.merge(dmlCurrentValue, checkUnique)
)
}
}
for {
// 1. generate vertex SQL
(vertexTableList, vertexRecordList) <- for {
count <- vertexQuery.countAll
vertices <- Future
.sequence {
(0 to count.toInt).view.map { start =>
vertexQuery
.getList(start, 1)
.map(_.map(vertex => (vertex.toDdl, vertex.toDml)))
}
}
.map(_.map(foldLeft(_, checkUnique)))
} yield foldLeft(vertices, checkUnique)

(Some(verticesDdl), Some(verticesDml), Some(edgesDdl), Some(edgesDml))
// 2. generate edge SQL
(edgeTableList, edgeRecordList) <- for {
count <- edgeQuery.countAll
edges <- Future
.sequence {
(0 to count.toInt).view.map { start =>
edgeQuery
.getList(start, 1)
.map(_.map(edge => (edge.toDdl, edge.toDml)))
}
}
.map(_.map(foldLeft(_, checkUnique)))
} yield foldLeft(edges, checkUnique)
} yield UsecaseResponse(
vertexTableList,
vertexRecordList,
edgeTableList,
edgeRecordList
)
}
}

0 comments on commit ad5c8ef

Please sign in to comment.