Skip to content

Commit

Permalink
Merge pull request #128 from kazumatsudo/feature/get_vertices_and_edg…
Browse files Browse the repository at this point in the history
…es_recursively

traverse vertex and edge recursively in UsingSpecificKeyList
  • Loading branch information
kazumatsudo committed Feb 4, 2024
2 parents 80a4a33 + 5b14f27 commit 6a04222
Show file tree
Hide file tree
Showing 7 changed files with 279 additions and 45 deletions.
1 change: 1 addition & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ wartremoverErrors ++= Warts.allBut(
Wart.Nothing,
Wart.OptionPartial,
Wart.PlatformDefault,
Wart.Recursion,
Wart.StringPlusAny,
Wart.Throw
)
Expand Down
2 changes: 1 addition & 1 deletion src/main/scala/domain/graph/GraphEdge.scala
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final case class GraphEdge(private val value: Edge, private val config: Config)
private val columnNameEdgeInVId = config.columnName.edgeInVId
private val columnNameEdgeOutVId = config.columnName.edgeOutVId

private val id = value.id()
val id: AnyRef = value.id()

/** convert to Database Table Information
*
Expand Down
37 changes: 35 additions & 2 deletions src/main/scala/infrastructure/VertexQuery.scala
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package infrastructure

import com.typesafe.scalalogging.StrictLogging
import domain.graph.GraphVertex
import domain.graph.{GraphEdge, GraphVertex}
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(
private val g: GraphTraversalSource,
Expand All @@ -24,6 +23,23 @@ final case class VertexQuery(
GremlinScala(g.V()).count().head().longValue()
}

/** get in Vertices List
*
* @param edge
* target Edge
* @return
* A list of Vertex
*/
def getInVertexList(
edge: GraphEdge
)(implicit ec: ExecutionContext): Future[SeqView[GraphVertex]] = Future {
GremlinScala(g.E(edge.id))
.inV()
.toList()
.view
.map(GraphVertex(_, config))
}

/** get Vertices List
*
* @param start
Expand Down Expand Up @@ -71,4 +87,21 @@ final case class VertexQuery(
.view
.map(GraphVertex(_, config))
}

/** get out Vertices List
*
* @param edge
* target Edge
* @return
* A list of Vertex
*/
def getOutVertexList(
edge: GraphEdge
)(implicit ec: ExecutionContext): Future[SeqView[GraphVertex]] = Future {
GremlinScala(g.E(edge.id))
.outV()
.toList()
.view
.map(GraphVertex(_, config))
}
}
98 changes: 87 additions & 11 deletions src/main/scala/usecase/UsingSpecificKeyList.scala
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package usecase

import domain.graph.{GraphEdge, GraphVertex}
import infrastructure.{EdgeQuery, VertexQuery}
import org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.GraphTraversalSource
import utils.Config

import scala.collection.mutable
import scala.concurrent.{ExecutionContext, Future}

final case class UsingSpecificKeyListRequestKey(
Expand Down Expand Up @@ -44,6 +46,85 @@ final case class UsingSpecificKeyList(
val vertexQuery = VertexQuery(g, config)
val edgeQuery = EdgeQuery(g, config)

@SuppressWarnings(Array("org.wartremover.warts.MutableDataStructures"))
val verticesSet = mutable.Set.empty[GraphVertex]
@SuppressWarnings(Array("org.wartremover.warts.MutableDataStructures"))
val edgesSet = mutable.Set.empty[GraphEdge]

def getEdges(graphVertex: GraphVertex) = for {
// inEdges
inEdges <- edgeQuery.getInEdgeList(graphVertex)
needToTraverseInEdges = inEdges.filterNot(edgesSet.contains).toIndexedSeq

// outEdges
outEdges <- edgeQuery.getOutEdgeList(graphVertex)
needToTraverseOutEdges = outEdges
.filterNot(edgesSet.contains)
.toIndexedSeq
} yield {
edgesSet ++= needToTraverseInEdges
edgesSet ++= needToTraverseOutEdges

(needToTraverseInEdges, needToTraverseOutEdges)
}

def getVertices(
inEdges: IndexedSeq[GraphEdge],
outEdges: IndexedSeq[GraphEdge]
) = for {
// outVertices
outVertices <- Future.sequence {
inEdges.map {
vertexQuery.getOutVertexList
}
}
needToTraverseOutVertices = outVertices.flatten
.filterNot(verticesSet.contains)

// inVertices
inVertices <- Future.sequence {
outEdges.map {
vertexQuery.getInVertexList
}
}
needToTraverseInVertices = inVertices.flatten
.filterNot(verticesSet.contains)
} yield {
verticesSet ++= needToTraverseInVertices
verticesSet ++= needToTraverseOutVertices

(needToTraverseInVertices, needToTraverseOutVertices)
}

def getGraphByVertex(graphVertex: GraphVertex)(implicit
ec: ExecutionContext
): Future[Boolean] = {
for {
// add edges if need
(needToTraverseInEdges, needToTraverseOutEdges) <- getEdges(graphVertex)
needToTraverseEdges = needToTraverseInEdges ++ needToTraverseOutEdges
result <-
if (needToTraverseEdges.isEmpty) {
Future.successful(true)
} else {
for {
(needToTraverseInVertices, needToTraverseOutVertices) <-
getVertices(needToTraverseInEdges, needToTraverseOutEdges)
needToTraverseVertices =
needToTraverseInVertices ++ needToTraverseOutVertices
result <-
if (needToTraverseVertices.isEmpty) {
Future.successful(true)
} else {
Future
.sequence { needToTraverseVertices.map(getGraphByVertex) }
.map(_.forall(identity))
}
} yield result
}
} yield result
}

Future
.sequence {
for {
Expand All @@ -56,18 +137,13 @@ final case class UsingSpecificKeyList(
keyValue.key,
value
)
inEdges <- Future.sequence {
vertices.map(edgeQuery.getInEdgeList(_))
}
outEdges <- Future.sequence {
vertices.map(edgeQuery.getOutEdgeList(_))
}
} yield (vertices, inEdges, outEdges)
_ = verticesSet ++= vertices
result <- Future.sequence { vertices.map(getGraphByVertex) }
} yield result
}
.flatMap { result =>
val (verticesResult, inEdgesResult, outEdgesResult) = result.unzip3
val vertices = verticesResult.flatten
val edges = (inEdgesResult ++ outEdgesResult).flatten.flatten
.flatMap { _ =>
val vertices = verticesSet.view
val edges = edgesSet.view

for {
vertexTableList <- toDdl(vertices, checkUnique)
Expand Down
34 changes: 16 additions & 18 deletions src/test/scala/MainSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import org.scalatest.funspec.AsyncFunSpec
import org.scalatest.matchers.should.Matchers
import slick.jdbc.H2Profile.api._
import slick.jdbc.JdbcBackend.Database
import usecase.{ByExhaustiveSearch, UsecaseBase}
import usecase.{ByExhaustiveSearch, UsecaseBase, UsingSpecificKeyList}
import utils.Config

class MainSpec extends AsyncFunSpec with Matchers {
Expand Down Expand Up @@ -71,7 +71,7 @@ class MainSpec extends AsyncFunSpec with Matchers {

describe("enable to execute in") {
val config = Config.default
val (g, _) =
val (g, request) =
GenerateTestData.generate(TinkerGraph.open().traversal(), 100, 5, 5)

describe("H2") {
Expand All @@ -83,14 +83,13 @@ class MainSpec extends AsyncFunSpec with Matchers {
)
}

// TODO: https://github.com/kazumatsudo/GraphDB2RDB/issues/73
// it("UsingSpecificKeyList") {
// testWithInitialize(
// DatabaseTypeH2,
// databaseH2,
// UsingSpecificKeyList(g, config, request)
// )
// }
it("UsingSpecificKeyList") {
testWithInitialize(
DatabaseTypeH2,
databaseH2,
UsingSpecificKeyList(g, config, request)
)
}
}

describe("MySQL") {
Expand All @@ -102,14 +101,13 @@ class MainSpec extends AsyncFunSpec with Matchers {
)
}

// TODO: https://github.com/kazumatsudo/GraphDB2RDB/issues/73
// it("UsingSpecificKeyList") {
// testWithInitialize(
// DatabaseTypeMysql,
// databaseMysql,
// UsingSpecificKeyList(g, config, request)
// )
// }
it("UsingSpecificKeyList") {
testWithInitialize(
DatabaseTypeMysql,
databaseMysql,
UsingSpecificKeyList(g, config, request)
)
}
}
}
}
39 changes: 38 additions & 1 deletion src/test/scala/infrastructure/VertexQuerySpec.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package infrastructure

import domain.graph.GraphVertex
import domain.graph.{GraphEdge, GraphVertex}
import gremlin.scala.GremlinScala
import org.apache.tinkerpop.gremlin.tinkergraph.structure.TinkerFactory
import org.scalatest.funspec.AsyncFunSpec
Expand All @@ -18,6 +18,25 @@ class VertexQuerySpec extends AsyncFunSpec with Matchers {
}
}

describe("getInVertexList") {
it("get inV list") {
val graph = TinkerFactory.createModern().traversal()
val vertexQuery = VertexQuery(graph, config)
vertexQuery
.getInVertexList(
GraphEdge(GremlinScala(graph.E()).toList().headOption.get, config)
)
.map {
_.toSeq shouldBe Seq(
GremlinScala(graph.V())
.toList()
.lift(1)
.map(GraphVertex(_, config))
).flatten
}
}
}

describe("getList") {
describe("require") {
it("start must be positive.") {
Expand Down Expand Up @@ -77,7 +96,25 @@ class VertexQuerySpec extends AsyncFunSpec with Matchers {
GraphVertex(GremlinScala(graph.V()).head(), config)
)
}
}
}

describe("getOutVertexList") {
it("get outV list") {
val graph = TinkerFactory.createModern().traversal()
val vertexQuery = VertexQuery(graph, config)
vertexQuery
.getOutVertexList(
GraphEdge(GremlinScala(graph.E()).toList().headOption.get, config)
)
.map {
_.toSeq shouldBe Seq(
GremlinScala(graph.V())
.toList()
.headOption
.map(GraphVertex(_, config))
).flatten
}
}
}
}

0 comments on commit 6a04222

Please sign in to comment.