diff --git a/core/src/main/scala/flatgraph/DiffGraphApplier.scala b/core/src/main/scala/flatgraph/DiffGraphApplier.scala
index a19119fd..ebd47717 100644
--- a/core/src/main/scala/flatgraph/DiffGraphApplier.scala
+++ b/core/src/main/scala/flatgraph/DiffGraphApplier.scala
@@ -7,9 +7,9 @@ import flatgraph.Edge.Direction.{Incoming, Outgoing}
import scala.collection.{Iterator, mutable}
object DiffGraphApplier {
- def applyDiff(g: Graph, diff: DiffGraphBuilder): Unit = {
- if (g.isClosed) throw new GraphClosedException(s"graph cannot be modified any longer since it's closed")
- new DiffGraphApplier(g, diff).applyUpdate()
+ def applyDiff(graph: Graph, diff: DiffGraphBuilder): Unit = {
+ if (graph.isClosed) throw new GraphClosedException(s"graph cannot be modified any longer since it's closed")
+ new DiffGraphApplier(graph, diff).applyUpdate()
diff.buffer = null
}
}
diff --git a/core/src/main/scala/flatgraph/Graph.scala b/core/src/main/scala/flatgraph/Graph.scala
index d499224d..21cd29b3 100644
--- a/core/src/main/scala/flatgraph/Graph.scala
+++ b/core/src/main/scala/flatgraph/Graph.scala
@@ -97,6 +97,9 @@ class Graph(val schema: Schema, val storagePathMaybe: Option[Path] = None) exten
def allEdges: Iterator[Edge] =
allNodes.flatMap(Accessors.getEdgesOut)
+ def edgeCount(): Int =
+ allEdges.size
+
/** Lookup nodes with a given label and property value via index. N.b. currently only supported for String properties. Context:
* MultiDictIndex requires the key to be a String and this is using reverse indices, i.e. the lookup is from String -> GNode.
*/
diff --git a/core/src/main/scala/flatgraph/Schema.scala b/core/src/main/scala/flatgraph/Schema.scala
index dcfffa98..222dc549 100644
--- a/core/src/main/scala/flatgraph/Schema.scala
+++ b/core/src/main/scala/flatgraph/Schema.scala
@@ -1,6 +1,7 @@
package flatgraph
import flatgraph.Edge.Direction
+import flatgraph.Schema.UndefinedKind
object DefaultValue
object NoProperty
@@ -96,7 +97,8 @@ object FormalQtyType {
abstract class Schema {
def getNumberOfNodeKinds: Int
- def nodeKinds: Range = Range(0, getNumberOfNodeKinds)
+ def nodeKinds: Range = Range(0, getNumberOfNodeKinds)
+ def nodeLabels: Seq[String] = nodeKinds.map(getNodeLabel)
def getNumberOfEdgeKinds: Int
def edgeKinds: Range = Range(0, getNumberOfEdgeKinds)
@@ -106,6 +108,9 @@ abstract class Schema {
def getNodeLabel(nodeKind: Int): String
def getNodeKindByLabel(label: String): Int
+ def getNodeKindByLabelMaybe(label: String): Option[Int] = {
+ Option(getNodeKindByLabel(label)).filterNot(_ == UndefinedKind)
+ }
// So, the issue here is: We have a couple of pseudo-properties that can only exist at a single node kind
// (theoretically same for edges). We want to allow our data-layout to alias these properties. This means that multiple
@@ -143,10 +148,10 @@ abstract class Schema {
}
class FreeSchema(
- val nodeLabels: Array[String],
- val propertyLabels: Array[String],
+ nodeLabels: Array[String],
+ propertyLabels: Array[String],
nodePropertyPrototypes: Array[AnyRef],
- val edgeLabels: Array[String],
+ edgeLabels: Array[String],
edgePropertyPrototypes: Array[AnyRef],
formalQuantities: Array[FormalQtyType.FormalQuantity] = null
) extends Schema {
diff --git a/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala b/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala
index 9612cc13..fc5f16c7 100644
--- a/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala
+++ b/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala
@@ -607,7 +607,7 @@ class DomainClassesGenerator(schema: Schema) {
|import flatgraph.FormalQtyType
|
|object GraphSchema extends flatgraph.Schema {
- | val nodeLabels = Array($nodeLabelsSrc)
+ | private val nodeLabels = IndexedSeq($nodeLabelsSrc)
| val nodeKindByLabel = nodeLabels.zipWithIndex.toMap
| val edgeLabels = Array(${edgeTypes.map { e => s""""${e.name}"""" }.mkString(", ")})
| val edgeIdByLabel = edgeLabels.zipWithIndex.toMap
diff --git a/formats-tests/src/test/resources/graphml-small.xml b/formats-tests/src/test/resources/graphml-small.xml
new file mode 100644
index 00000000..6f82c4fd
--- /dev/null
+++ b/formats-tests/src/test/resources/graphml-small.xml
@@ -0,0 +1,29 @@
+
+
+
+
+
+
+
+
+ song
+ HEY BO DIDDLEY
+ cover
+
+
+ artist
+ Garcia
+
+
+ artist
+ Bo_Diddley
+
+
+ writtenBy
+
+
+ sungBy
+
+
+
diff --git a/formats-tests/src/test/resources/graphson-small.json b/formats-tests/src/test/resources/graphson-small.json
new file mode 100644
index 00000000..387b2df9
--- /dev/null
+++ b/formats-tests/src/test/resources/graphson-small.json
@@ -0,0 +1,106 @@
+{
+ "@type": "tinker:graph",
+ "@value": {
+ "edges": [{
+ "@type": "g:Edge",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 0
+ },
+ "inV": {
+ "@type": "g:Int64",
+ "@value": 340
+ },
+ "inVLabel": "artist",
+ "label": "sungBy",
+ "outV": {
+ "@type": "g:Int64",
+ "@value": 1
+ },
+ "outVLabel": "song",
+ "properties": {
+
+ }
+ }, {
+ "@type": "g:Edge",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 1
+ },
+ "inV": {
+ "@type": "g:Int64",
+ "@value": 527
+ },
+ "inVLabel": "artist",
+ "label": "writtenBy",
+ "outV": {
+ "@type": "g:Int64",
+ "@value": 1
+ },
+ "outVLabel": "song",
+ "properties": {
+
+ }
+ }],
+ "vertices": [{
+ "@type": "g:Vertex",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 1
+ },
+ "label": "song",
+ "properties": {
+ "name": {
+ "@type": "g:VertexProperty",
+ "@value": "HEY BO DIDDLEY",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 0
+ }
+ },
+ "songType": {
+ "@type": "g:VertexProperty",
+ "@value": "cover",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 1
+ }
+ }
+ }
+ }, {
+ "@type": "g:Vertex",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 340
+ },
+ "label": "artist",
+ "properties": {
+ "name": {
+ "@type": "g:VertexProperty",
+ "@value": "Garcia",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 2
+ }
+ }
+ }
+ }, {
+ "@type": "g:Vertex",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 527
+ },
+ "label": "artist",
+ "properties": {
+ "name": {
+ "@type": "g:VertexProperty",
+ "@value": "Bo_Diddley",
+ "id": {
+ "@type": "g:Int64",
+ "@value": 3
+ }
+ }
+ }
+ }]
+ }
+}
\ No newline at end of file
diff --git a/formats-tests/src/test/resources/neo4jcsv/invalid_column_content_data.csv b/formats-tests/src/test/resources/neo4jcsv/invalid_column_content_data.csv
new file mode 100644
index 00000000..3d33c96a
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/invalid_column_content_data.csv
@@ -0,0 +1,3 @@
+1,stringProp1,11,testNode,stringListProp1a;stringListProp1b,21;31;41
+2,stringProp2,,testNode,,
+3,,NOT_AN_INT,testNode,,
diff --git a/formats-tests/src/test/resources/neo4jcsv/invalid_column_content_header.csv b/formats-tests/src/test/resources/neo4jcsv/invalid_column_content_header.csv
new file mode 100644
index 00000000..96f0e308
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/invalid_column_content_header.csv
@@ -0,0 +1 @@
+id:ID,StringProperty,IntProperty:int,:LABEL,StringListProperty:string[],IntListProperty:int[]
\ No newline at end of file
diff --git a/formats-tests/src/test/resources/neo4jcsv/testedges_data.csv b/formats-tests/src/test/resources/neo4jcsv/testedges_data.csv
new file mode 100644
index 00000000..e246c6fa
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/testedges_data.csv
@@ -0,0 +1,2 @@
+testEdge,1,2,9223372036854775807
+testEdge,2,3,
diff --git a/formats-tests/src/test/resources/neo4jcsv/testedges_header.csv b/formats-tests/src/test/resources/neo4jcsv/testedges_header.csv
new file mode 100644
index 00000000..5528fbfa
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/testedges_header.csv
@@ -0,0 +1 @@
+:TYPE,:START_ID,:END_ID,longProperty:long
\ No newline at end of file
diff --git a/formats-tests/src/test/resources/neo4jcsv/testnodes_data.csv b/formats-tests/src/test/resources/neo4jcsv/testnodes_data.csv
new file mode 100644
index 00000000..40ba5fb1
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/testnodes_data.csv
@@ -0,0 +1,3 @@
+1,stringProp1,11,testNode,stringListProp1a;stringListProp1b,21;31;41
+2,stringProp2,,testNode,,
+3,,13,testNode,,
diff --git a/formats-tests/src/test/resources/neo4jcsv/testnodes_header.csv b/formats-tests/src/test/resources/neo4jcsv/testnodes_header.csv
new file mode 100644
index 00000000..96f0e308
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/testnodes_header.csv
@@ -0,0 +1 @@
+id:ID,StringProperty,IntProperty:int,:LABEL,StringListProperty:string[],IntListProperty:int[]
\ No newline at end of file
diff --git a/formats-tests/src/test/resources/neo4jcsv/unsupported_multiple_labels_data.csv b/formats-tests/src/test/resources/neo4jcsv/unsupported_multiple_labels_data.csv
new file mode 100644
index 00000000..3c3369e0
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/unsupported_multiple_labels_data.csv
@@ -0,0 +1 @@
+1,LABEL1,11,LABEL2
\ No newline at end of file
diff --git a/formats-tests/src/test/resources/neo4jcsv/unsupported_multiple_labels_header.csv b/formats-tests/src/test/resources/neo4jcsv/unsupported_multiple_labels_header.csv
new file mode 100644
index 00000000..9639be21
--- /dev/null
+++ b/formats-tests/src/test/resources/neo4jcsv/unsupported_multiple_labels_header.csv
@@ -0,0 +1 @@
+id:ID,:LABEL,IntProperty:int,:LABEL
\ No newline at end of file
diff --git a/formats-tests/src/test/scala/flatgraph/formats/graphml/GraphMLTests.scala b/formats-tests/src/test/scala/flatgraph/formats/graphml/GraphMLTests.scala
index 7b78655e..49fc6680 100644
--- a/formats-tests/src/test/scala/flatgraph/formats/graphml/GraphMLTests.scala
+++ b/formats-tests/src/test/scala/flatgraph/formats/graphml/GraphMLTests.scala
@@ -1,7 +1,9 @@
package flatgraph.formats.graphml
import better.files.File
-import org.scalatest.matchers.should.Matchers._
+import flatgraph.testdomains.gratefuldead.GratefulDead
+import flatgraph.testdomains.gratefuldead.Language.*
+import org.scalatest.matchers.should.Matchers.*
import org.scalatest.wordspec.AnyWordSpec
import flatgraph.util.DiffTool
@@ -12,31 +14,28 @@ import scala.jdk.CollectionConverters.{CollectionHasAsScala, IterableHasAsJava}
class GraphMLTests extends AnyWordSpec {
"import minified gratefuldead graph" in {
- pending
-// ??? // TODO
-// val graph = GratefulDead.newGraph()
-// graph.nodeCount() shouldBe 0
-//
-// GraphMLImporter.runImport(graph, Paths.get(getClass.getResource("/graphml-small.xml").toURI))
-// graph.nodeCount() shouldBe 3
-// graph.edgeCount() shouldBe 2
-//
-// val node1 = graph.node(1)
-// node1.label() shouldBe "song"
-// val node340 = node1.out("sungBy").next()
-// val node527 = node1.out("writtenBy").next()
-//
-// node340.label shouldBe "artist"
-// node340.property("name") shouldBe "Garcia"
-// node340.out().hasNext shouldBe false
-// node340.in().hasNext shouldBe true
-//
-// node527.label shouldBe "artist"
-// node527.property("name") shouldBe "Bo_Diddley"
-// node527.out().hasNext shouldBe false
-// node527.in().hasNext shouldBe true
-//
-// graph.close()
+ val gratefulDead = GratefulDead.empty
+ val graph = gratefulDead.graph
+ graph.nodeCount() shouldBe 0
+
+ GraphMLImporter.runImport(graph, Paths.get(getClass.getResource("/graphml-small.xml").toURI))
+ graph.nodeCount() shouldBe 3
+ graph.edgeCount() shouldBe 2
+
+ gratefulDead.song.size shouldBe 1
+ gratefulDead.song.name.l shouldBe List("HEY BO DIDDLEY")
+ gratefulDead.artist.size shouldBe 2
+ gratefulDead.artist.name.l shouldBe List("Garcia", "Bo_Diddley")
+
+ val Seq(boDiddley, garcia) = gratefulDead.artist.sortBy(_.name).l
+ val Seq(heyBoDiddley) = gratefulDead.song.l
+
+ heyBoDiddley.sungBy shouldBe garcia
+ heyBoDiddley.writtenBy shouldBe boDiddley
+ garcia.sang.l shouldBe List(heyBoDiddley)
+ boDiddley.wrote.l shouldBe List(heyBoDiddley)
+
+ graph.close()
}
// "Exporter should export valid xml" when {
diff --git a/formats/src/main/scala/flatgraph/formats/graphml/GraphMLImporter.scala b/formats/src/main/scala/flatgraph/formats/graphml/GraphMLImporter.scala
index bc1d7fb7..77743160 100644
--- a/formats/src/main/scala/flatgraph/formats/graphml/GraphMLImporter.scala
+++ b/formats/src/main/scala/flatgraph/formats/graphml/GraphMLImporter.scala
@@ -1,11 +1,14 @@
package flatgraph.formats.graphml
-import flatgraph.Graph
import flatgraph.formats.Importer
+import flatgraph.misc.Conversions.toShortSafely
+import flatgraph.*
import java.nio.file.Path
+import scala.collection.mutable
import scala.util.{Failure, Success, Try}
-import scala.xml.{NodeSeq, XML}
+import scala.xml
+import scala.xml.XML
/** Imports GraphML into flatgraph
*
@@ -15,27 +18,69 @@ object GraphMLImporter extends Importer {
override def runImport(graph: Graph, inputFiles: Seq[Path]): Unit = {
assert(inputFiles.size == 1, s"input must be exactly one file, but got ${inputFiles.size}")
- val doc = XML.loadFile(inputFiles.head.toFile)
+ val doc = XML.loadFile(inputFiles.head.toFile)
+ val graphXml = doc \ "graph"
- val keyEntries = doc \ "key"
- val graphXml = doc \ "graph"
+ val graphmlNodes = graphXml \ "node"
+ val graphmlNodeIdToGNode = addNodesRaw(graphmlNodes, graph)
- { // nodes
- val nodePropertyContextById = parsePropertyEntries("node", keyEntries)
- for (node <- graphXml \ "node") {
- addNode(graph, node, nodePropertyContextById)
+ val keyEntries = doc \ "key"
+ val diffGraph = new DiffGraphBuilder(graph.schema)
+
+ // node properties
+ val nodePropertyContextById = parsePropertyEntries("node", keyEntries)
+ for {
+ graphmlNode <- graphmlNodes
+ nodeId = graphmlNode \@ "id"
+ entry <- graphmlNode \ "data"
+ } {
+ entry \@ "key" match {
+ case KeyForNodeLabel => // ignore, already extracted in `addNodesRaw`
+ case key =>
+ val propertyType = nodePropertyContextById
+ .get(key)
+ .getOrElse(throw new AssertionError(s"key $key not found in propertyContext..."))
+ .tpe
+ val value = entry.text
+ val convertedValue = convertValue(value, propertyType, context = graphmlNode)
+ diffGraph.setNodeProperty(graphmlNodeIdToGNode(nodeId), key, value)
}
}
- { // edges
- val edgePropertyContextById = parsePropertyEntries("edge", keyEntries)
- for (edge <- graphXml \ "edge") {
- addEdge(graph, edge, edgePropertyContextById)
- }
+ // edges
+ val edgePropertyContextById = parsePropertyEntries("edge", keyEntries)
+ for (edge <- graphXml \ "edge") {
+ addEdge(diffGraph, graphmlNodeIdToGNode, edge, edgePropertyContextById)
+ }
+
+ DiffGraphApplier.applyDiff(graph, diffGraph)
+ }
+
+ private def addNodesRaw(graphmlNodes: Seq[xml.Node], graph: Graph): Map[String, GNode] = {
+ val diffGraphForRawNodes = new DiffGraphBuilder(graph.schema)
+ val graphmlNodeIdToGNode = mutable.Map.empty[String, GenericDNode]
+ graphmlNodes.foreach { graphmlNode =>
+ val id = graphmlNode \@ "id"
+ val label = (graphmlNode \ "data")
+ .find(_ \@ "key" == KeyForNodeLabel)
+ .map(_.text)
+ .getOrElse(throw new AssertionError(s"node label must be defined, but isn't: $graphmlNode"))
+ val nodeKind = graph.schema
+ .getNodeKindByLabelMaybe(label)
+ .getOrElse(
+ throw new AssertionError(
+ s"node label `$label` is not one of the labels defined in the schema, which are: [${graph.schema.nodeLabels.mkString(",")}]"
+ )
+ )
+ val newNode = new GenericDNode(graph.schema.getNodeKindByLabel(label).toShortSafely)
+ diffGraphForRawNodes.addNode(newNode)
+ graphmlNodeIdToGNode.put(id, newNode)
}
+ DiffGraphApplier.applyDiff(graph, diffGraphForRawNodes)
+ graphmlNodeIdToGNode.view.mapValues(_.storedRef.get).toMap
}
- private def parsePropertyEntries(forElementType: String, keyEntries: NodeSeq): Map[String, PropertyContext] = {
+ private def parsePropertyEntries(forElementType: String, keyEntries: xml.NodeSeq): Map[String, PropertyContext] = {
keyEntries
.filter(_ \@ "for" == forElementType)
.map { node =>
@@ -47,37 +92,16 @@ object GraphMLImporter extends Importer {
.toMap
}
- private def addNode(graph: Graph, node: scala.xml.Node, propertyContextById: Map[String, PropertyContext]): Unit = {
- val id = node \@ "id"
- var label: Option[String] = None
- val keyValuePairs = Seq.newBuilder[Any]
-
- for (entry <- node \ "data") {
- val value = entry.text
- entry \@ "key" match {
- case KeyForNodeLabel => label = Option(value)
- case key =>
- val PropertyContext(name, tpe) = propertyContextById
- .get(key)
- .getOrElse(throw new AssertionError(s"key $key not found in propertyContext..."))
- val convertedValue = convertValue(value, tpe, context = node)
- keyValuePairs.addAll(Seq(name, convertedValue))
- }
- }
-
- // TODO reimplement
-// for {
-// id <- id.toLongOption
-// label <- label
-// } graph.addNode(id, label, keyValuePairs.result: _*)
- ???
- }
-
- private def addEdge(graph: Graph, edge: scala.xml.Node, propertyContextById: Map[String, PropertyContext]): Unit = {
- val sourceId = edge \@ "source"
- val targetId = edge \@ "target"
- var label: Option[String] = None
- val keyValuePairs = Seq.newBuilder[Any]
+ private def addEdge(
+ diffGraph: DiffGraphBuilder,
+ graphmlNodeIdToGNode: Map[String, GNode],
+ edge: xml.Node,
+ propertyContextById: Map[String, PropertyContext]
+ ): Unit = {
+ val sourceId = edge \@ "source"
+ val targetId = edge \@ "target"
+ var label: Option[String] = None
+ var edgePropertyMaybe: Option[(String, Any)] = None
for (entry <- edge \ "data") {
val value = entry.text
@@ -88,22 +112,24 @@ object GraphMLImporter extends Importer {
.get(key)
.getOrElse(throw new AssertionError(s"key $key not found in propertyContext..."))
val convertedValue = convertValue(value, tpe, context = edge)
- keyValuePairs.addAll(Seq(name, convertedValue))
+ if (edgePropertyMaybe.isDefined) {
+ logger.warn(
+ s"flatgraph only supports 0..1 edge properties. This graphml edge has more than one properties though - taking only the first one... graphml node: $edge"
+ )
+ }
+ edgePropertyMaybe = Some(name -> convertedValue)
}
}
- // TODO reimplement
-// for {
-// sourceId <- sourceId.toLongOption
-// source <- Option(graph.node(sourceId))
-// targetId <- targetId.toLongOption
-// target <- Option(graph.node(targetId))
-// label <- label
-// } source.addEdge(label, target, keyValuePairs.result: _*)
- ???
+ for {
+ source <- graphmlNodeIdToGNode.get(sourceId)
+ target <- graphmlNodeIdToGNode.get(targetId)
+ label <- label
+ edgeProperty = edgePropertyMaybe.map(_._2).getOrElse(flatgraph.DefaultValue)
+ } diffGraph.addEdge(source, target, label, edgeProperty)
}
- private def convertValue(stringValue: String, tpe: Type.Value, context: scala.xml.Node): Any = {
+ private def convertValue(stringValue: String, tpe: Type.Value, context: xml.Node): Any = {
tryConvertScalarValue(stringValue, tpe) match {
case Success(value) => value
case Failure(e) => throw new AssertionError(s"unable to parse `$stringValue` of tpe=$tpe. context: $context", e)
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Accessors.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Accessors.scala
index 5fb477a9..e1a1ff7b 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Accessors.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Accessors.scala
@@ -6,31 +6,41 @@ object Lang extends ConcreteStoredConversions
object Accessors {
/* accessors for concrete stored nodes start */
- final class Access_Property_Name(val node: nodes.StoredNode) extends AnyVal {
+ final class Access_Property_name(val node: nodes.StoredNode) extends AnyVal {
def name: String = flatgraph.Accessors.getNodePropertySingle(node.graph, node.nodeKind, 0, node.seq(), "": String)
}
+ final class Access_Property_songType(val node: nodes.StoredNode) extends AnyVal {
+ def songtype: Option[String] =
+ flatgraph.Accessors.getNodePropertyOption[String](node.graph, node.nodeKind, 1, node.seq)
+ }
/* accessors for concrete stored nodes end */
/* accessors for base nodes start */
final class Access_ArtistBase(val node: nodes.ArtistBase) extends AnyVal {
def name: String = node match {
- case stored: nodes.StoredNode => new Access_Property_Name(stored).name
+ case stored: nodes.StoredNode => new Access_Property_name(stored).name
case newNode: nodes.NewArtist => newNode.name
}
}
final class Access_SongBase(val node: nodes.SongBase) extends AnyVal {
def name: String = node match {
- case stored: nodes.StoredNode => new Access_Property_Name(stored).name
+ case stored: nodes.StoredNode => new Access_Property_name(stored).name
case newNode: nodes.NewSong => newNode.name
}
+ def songtype: Option[String] = node match {
+ case stored: nodes.StoredNode => new Access_Property_songType(stored).songtype
+ case newNode: nodes.NewSong => newNode.songtype
+ }
}
/* accessors for base nodes end */
}
trait ConcreteStoredConversions extends ConcreteBaseConversions {
import Accessors.*
- implicit def accessPropertyName(node: nodes.StoredNode & nodes.StaticType[nodes.HasNameEMT]): Access_Property_Name =
- new Access_Property_Name(node)
+ implicit def accessPropertyName(node: nodes.StoredNode & nodes.StaticType[nodes.HasNameEMT]): Access_Property_name =
+ new Access_Property_name(node)
+ implicit def accessPropertySongtype(node: nodes.StoredNode & nodes.StaticType[nodes.HasSongtypeEMT]): Access_Property_songType =
+ new Access_Property_songType(node)
}
trait ConcreteBaseConversions {
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/BaseTypes.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/BaseTypes.scala
index 9682c3a9..9f2f0521 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/BaseTypes.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/BaseTypes.scala
@@ -1,6 +1,11 @@
package flatgraph.testdomains.gratefuldead.nodes
-/** Node types with this marker trait are guaranteed to have the Name property. EMT stands for: "erased marker trait", it exists only at
+/** Node types with this marker trait are guaranteed to have the name property. EMT stands for: "erased marker trait", it exists only at
* compile time in order to improve type safety.
*/
trait HasNameEMT
+
+/** Node types with this marker trait are guaranteed to have the songType property. EMT stands for: "erased marker trait", it exists only at
+ * compile time in order to improve type safety.
+ */
+trait HasSongtypeEMT
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.java b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.java
index c94bdd72..0617ea77 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.java
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.java
@@ -8,8 +8,16 @@ public class EdgeTypes {
public static final String followedBy = "followedBy";
+
+public static final String sungBy = "sungBy";
+
+
+public static final String writtenBy = "writtenBy";
+
public static Set ALL = new HashSet() {{
add(followedBy);
+add(sungBy);
+add(writtenBy);
}};
}
\ No newline at end of file
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.scala
index 41884a8d..12d5c11e 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/EdgeTypes.scala
@@ -4,3 +4,7 @@ class Followedby(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_48
extends flatgraph.Edge(src_4762, dst_4762, 0.toShort, subSeq_4862, property_4862) {
def weight: Long = this.property.asInstanceOf[Long]
}
+class Sungby(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_4862: Int, property_4862: Any)
+ extends flatgraph.Edge(src_4762, dst_4762, 1.toShort, subSeq_4862, property_4862)
+class Writtenby(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_4862: Int, property_4862: Any)
+ extends flatgraph.Edge(src_4762, dst_4762, 2.toShort, subSeq_4862, property_4862)
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/GraphSchema.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/GraphSchema.scala
index 5ef63ad8..f008ab52 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/GraphSchema.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/GraphSchema.scala
@@ -4,47 +4,53 @@ import flatgraph.testdomains.gratefuldead.edges
import flatgraph.FormalQtyType
object GraphSchema extends flatgraph.Schema {
- val nodeLabels = Array("Artist", "Song")
- val nodeKindByLabel = nodeLabels.zipWithIndex.toMap
- val edgeLabels = Array("followedBy")
- val edgeIdByLabel = edgeLabels.zipWithIndex.toMap
+ private val nodeLabels = IndexedSeq("artist", "song")
+ val nodeKindByLabel = nodeLabels.zipWithIndex.toMap
+ val edgeLabels = Array("followedBy", "sungBy", "writtenBy")
+ val edgeIdByLabel = edgeLabels.zipWithIndex.toMap
val edgePropertyAllocators: Array[Int => Array[?]] =
- Array(size => Array.fill(size)(0: Long) /* label = followedBy, id = 0 */ )
+ Array(size => Array.fill(size)(0: Long) /* label = followedBy, id = 0 */, size => null, size => null)
val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] =
Array((g, seq) => new nodes.Artist(g, seq), (g, seq) => new nodes.Song(g, seq))
- val edgeFactories: Array[(flatgraph.GNode, flatgraph.GNode, Int, Any) => flatgraph.Edge] =
- Array((s, d, subseq, p) => new edges.Followedby(s, d, subseq, p))
- val nodePropertyAllocators: Array[Int => Array[?]] = Array(size => new Array[String](size))
- val normalNodePropertyNames = Array("Name")
- val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap
+ val edgeFactories: Array[(flatgraph.GNode, flatgraph.GNode, Int, Any) => flatgraph.Edge] = Array(
+ (s, d, subseq, p) => new edges.Followedby(s, d, subseq, p),
+ (s, d, subseq, p) => new edges.Sungby(s, d, subseq, p),
+ (s, d, subseq, p) => new edges.Writtenby(s, d, subseq, p)
+ )
+ val nodePropertyAllocators: Array[Int => Array[?]] =
+ Array(size => new Array[String](size), size => new Array[String](size))
+ val normalNodePropertyNames = Array("name", "songType")
+ val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap
val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = {
- val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](4)
- for (idx <- Range(0, 4)) {
+ val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](8)
+ for (idx <- Range(0, 8)) {
nodePropertyDescriptors(idx) =
if ((idx & 1) == 0) FormalQtyType.NothingType
else FormalQtyType.QtyNone
}
- nodePropertyDescriptors(0) = FormalQtyType.StringType // Artist.Name
+ nodePropertyDescriptors(0) = FormalQtyType.StringType // artist.name
nodePropertyDescriptors(1) = FormalQtyType.QtyOne
- nodePropertyDescriptors(2) = FormalQtyType.StringType // Song.Name
+ nodePropertyDescriptors(2) = FormalQtyType.StringType // song.name
nodePropertyDescriptors(3) = FormalQtyType.QtyOne
+ nodePropertyDescriptors(6) = FormalQtyType.StringType // song.songType
+ nodePropertyDescriptors(7) = FormalQtyType.QtyOption
nodePropertyDescriptors
}
override def getNumberOfNodeKinds: Int = 2
- override def getNumberOfEdgeKinds: Int = 1
+ override def getNumberOfEdgeKinds: Int = 3
override def getNodeLabel(nodeKind: Int): String = nodeLabels(nodeKind)
override def getNodeKindByLabel(label: String): Int = nodeKindByLabel.getOrElse(label, flatgraph.Schema.UndefinedKind)
override def getEdgeLabel(nodeKind: Int, edgeKind: Int): String = edgeLabels(edgeKind)
override def getEdgeKindByLabel(label: String): Int = edgeIdByLabel.getOrElse(label, flatgraph.Schema.UndefinedKind)
override def getPropertyLabel(nodeKind: Int, propertyKind: Int): String = {
- if (propertyKind < 1) normalNodePropertyNames(propertyKind)
+ if (propertyKind < 2) normalNodePropertyNames(propertyKind)
else null
}
override def getPropertyKindByName(label: String): Int =
nodePropertyByLabel.getOrElse(label, flatgraph.Schema.UndefinedKind)
- override def getNumberOfPropertyKinds: Int = 1
+ override def getNumberOfPropertyKinds: Int = 2
override def makeNode(graph: flatgraph.Graph, nodeKind: Short, seq: Int): nodes.StoredNode =
nodeFactories(nodeKind)(graph, seq)
override def makeEdge(src: flatgraph.GNode, dst: flatgraph.GNode, edgeKind: Short, subSeq: Int, property: Any): flatgraph.Edge =
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/NodeTypes.java b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/NodeTypes.java
index 675b6ff9..ade294cc 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/NodeTypes.java
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/NodeTypes.java
@@ -6,14 +6,14 @@
public class NodeTypes {
-public static final String Artist = "Artist";
+public static final String artist = "artist";
-public static final String Song = "Song";
+public static final String song = "song";
public static Set ALL = new HashSet() {{
-add(Artist);
-add(Song);
+add(artist);
+add(song);
}};
}
\ No newline at end of file
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyKeys.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyKeys.scala
index 01b6af14..96b31066 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyKeys.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyKeys.scala
@@ -4,6 +4,8 @@ import flatgraph.PropertyKey
object PropertyKeys {
- val Name = flatgraph.SinglePropertyKey[String](kind = 0, name = "Name", default = "")
+ val Name = flatgraph.SinglePropertyKey[String](kind = 0, name = "name", default = "")
+
+ val Songtype = flatgraph.OptionalPropertyKey[String](kind = 1, name = "songType")
}
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyNames.java b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyNames.java
index a5673f4e..adfa6d6e 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyNames.java
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/PropertyNames.java
@@ -6,21 +6,21 @@
public class PropertyNames {
-public static final String Name = "Name";
+public static final String name = "name";
public static final String performances = "performances";
-public static final String SongType = "SongType";
+public static final String songType = "songType";
public static final String weight = "weight";
public static Set ALL = new HashSet() {{
-add(Name);
+add(name);
add(performances);
-add(SongType);
+add(songType);
add(weight);
}};
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypes.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypes.scala
index 6ed0043d..99224aee 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypes.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypes.scala
@@ -16,6 +16,16 @@ abstract class StoredNode(graph_4762: flatgraph.Graph, kind_4762: Short, seq_476
final def _followedbyIn: Iterator[StoredNode] =
flatgraph.Accessors.getNeighborsIn(this.graph, this.nodeKind, this.seq, 0).asInstanceOf[Iterator[StoredNode]]
+ final def _sungbyOut: Iterator[StoredNode] =
+ flatgraph.Accessors.getNeighborsOut(this.graph, this.nodeKind, this.seq, 1).asInstanceOf[Iterator[StoredNode]]
+ final def _sungbyIn: Iterator[StoredNode] =
+ flatgraph.Accessors.getNeighborsIn(this.graph, this.nodeKind, this.seq, 1).asInstanceOf[Iterator[StoredNode]]
+
+ final def _writtenbyOut: Iterator[StoredNode] =
+ flatgraph.Accessors.getNeighborsOut(this.graph, this.nodeKind, this.seq, 2).asInstanceOf[Iterator[StoredNode]]
+ final def _writtenbyIn: Iterator[StoredNode] =
+ flatgraph.Accessors.getNeighborsIn(this.graph, this.nodeKind, this.seq, 2).asInstanceOf[Iterator[StoredNode]]
+
}
abstract class NewNode(val nodeKind: Short) extends AbstractNode with flatgraph.DNode {
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypesTraversals.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypesTraversals.scala
index 2cb8715f..88618693 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypesTraversals.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/RootTypesTraversals.scala
@@ -5,4 +5,10 @@ extension (iterator: Iterator[StoredNode]) {
final def _followedbyOut: Iterator[StoredNode] = iterator.flatMap(_._followedbyOut)
final def _followedbyIn: Iterator[StoredNode] = iterator.flatMap(_._followedbyIn)
+ final def _sungbyOut: Iterator[StoredNode] = iterator.flatMap(_._sungbyOut)
+ final def _sungbyIn: Iterator[StoredNode] = iterator.flatMap(_._sungbyIn)
+
+ final def _writtenbyOut: Iterator[StoredNode] = iterator.flatMap(_._writtenbyOut)
+ final def _writtenbyIn: Iterator[StoredNode] = iterator.flatMap(_._writtenbyIn)
+
}
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Traversals.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Traversals.scala
index 9c20a950..4ebf8621 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Traversals.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/Traversals.scala
@@ -7,7 +7,7 @@ object Accessors {
import flatgraph.testdomains.gratefuldead.accessors.Lang.*
/* accessors for concrete stored nodes start */
- final class Traversal_Property_Name[NodeType <: nodes.StoredNode & nodes.StaticType[nodes.HasNameEMT]](val traversal: Iterator[NodeType])
+ final class Traversal_Property_name[NodeType <: nodes.StoredNode & nodes.StaticType[nodes.HasNameEMT]](val traversal: Iterator[NodeType])
extends AnyVal {
/** Traverse to name property */
@@ -69,6 +69,84 @@ object Accessors {
traversal.filter { item => matchers.find { _.reset(item.name).matches }.isEmpty }
}
+ }
+ final class Traversal_Property_songType[NodeType <: nodes.StoredNode & nodes.StaticType[nodes.HasSongtypeEMT]](
+ val traversal: Iterator[NodeType]
+ ) extends AnyVal {
+
+ /** Traverse to songtype property */
+ def songtype: Iterator[String] =
+ traversal.flatMap(_.songtype)
+
+ /** Traverse to nodes where the songtype matches the regular expression `value`
+ */
+ def songtype(pattern: String): Iterator[NodeType] = {
+ if (!flatgraph.misc.Regex.isRegex(pattern)) {
+ songtypeExact(pattern)
+ } else {
+ val matcher = flatgraph.misc.Regex.multilineMatcher(pattern)
+ traversal.filter { item =>
+ val tmp = item.songtype; tmp.isDefined && matcher.reset(tmp.get).matches
+ }
+ }
+ }
+
+ /** Traverse to nodes where the songtype matches at least one of the regular expressions in `values`
+ */
+ def songtype(patterns: String*): Iterator[NodeType] = {
+ val matchers = patterns.map(flatgraph.misc.Regex.multilineMatcher)
+ traversal.filter { item =>
+ val tmp = item.songtype; tmp.isDefined && matchers.exists { _.reset(tmp.get).matches }
+ }
+ }
+
+ /** Traverse to nodes where songtype matches `value` exactly.
+ */
+ def songtypeExact(value: String): Iterator[NodeType] = traversal match {
+ case init: flatgraph.misc.InitNodeIterator[flatgraph.GNode @unchecked] if init.isVirgin && init.hasNext =>
+ val someNode = init.next
+ flatgraph.Accessors
+ .getWithInverseIndex(someNode.graph, someNode.nodeKind, 1, value)
+ .asInstanceOf[Iterator[NodeType]]
+ case _ =>
+ traversal.filter { node =>
+ val tmp = node.songtype; tmp.isDefined && tmp.get == value
+ }
+ }
+
+ /** Traverse to nodes where songtype matches one of the elements in `values` exactly.
+ */
+ def songtypeExact(values: String*): Iterator[NodeType] =
+ if (values.length == 1) songtypeExact(values.head)
+ else {
+ val valueSet = values.toSet
+ traversal.filter { item =>
+ val tmp = item.songtype; tmp.isDefined && valueSet.contains(tmp.get)
+ }
+ }
+
+ /** Traverse to nodes where songtype does not match the regular expression `value`.
+ */
+ def songtypeNot(pattern: String): Iterator[NodeType] = {
+ if (!flatgraph.misc.Regex.isRegex(pattern)) {
+ traversal.filter { node => node.songtype.isEmpty || node.songtype.get != pattern }
+ } else {
+ val matcher = flatgraph.misc.Regex.multilineMatcher(pattern)
+ traversal.filterNot { item =>
+ val tmp = item.songtype; tmp.isDefined && matcher.reset(tmp.get).matches
+ }
+ }
+ }
+
+ /** Traverse to nodes where songtype does not match any of the regular expressions in `values`.
+ */
+ def songtypeNot(patterns: String*): Iterator[NodeType] = {
+ val matchers = patterns.map(flatgraph.misc.Regex.multilineMatcher)
+ traversal.filterNot { item =>
+ val tmp = item.songtype; tmp.isDefined && matchers.exists { _.reset(tmp.get).matches }
+ }
+ }
+
}
/* accessors for concrete stored nodes end */
@@ -196,6 +274,79 @@ object Accessors {
traversal.filter { item => matchers.find { _.reset(item.name).matches }.isEmpty }
}
+ /** Traverse to songtype property */
+ def songtype: Iterator[String] =
+ traversal.flatMap(_.songtype)
+
+ /** Traverse to nodes where the songtype matches the regular expression `value`
+ */
+ def songtype(pattern: String): Iterator[NodeType] = {
+ if (!flatgraph.misc.Regex.isRegex(pattern)) {
+ songtypeExact(pattern)
+ } else {
+ val matcher = flatgraph.misc.Regex.multilineMatcher(pattern)
+ traversal.filter { item =>
+ val tmp = item.songtype; tmp.isDefined && matcher.reset(tmp.get).matches
+ }
+ }
+ }
+
+ /** Traverse to nodes where the songtype matches at least one of the regular expressions in `values`
+ */
+ def songtype(patterns: String*): Iterator[NodeType] = {
+ val matchers = patterns.map(flatgraph.misc.Regex.multilineMatcher)
+ traversal.filter { item =>
+ val tmp = item.songtype; tmp.isDefined && matchers.exists { _.reset(tmp.get).matches }
+ }
+ }
+
+ /** Traverse to nodes where songtype matches `value` exactly.
+ */
+ def songtypeExact(value: String): Iterator[NodeType] = traversal match {
+ case init: flatgraph.misc.InitNodeIterator[flatgraph.GNode @unchecked] if init.isVirgin && init.hasNext =>
+ val someNode = init.next
+ flatgraph.Accessors
+ .getWithInverseIndex(someNode.graph, someNode.nodeKind, 1, value)
+ .asInstanceOf[Iterator[NodeType]]
+ case _ =>
+ traversal.filter { node =>
+ val tmp = node.songtype; tmp.isDefined && tmp.get == value
+ }
+ }
+
+ /** Traverse to nodes where songtype matches one of the elements in `values` exactly.
+ */
+ def songtypeExact(values: String*): Iterator[NodeType] =
+ if (values.length == 1) songtypeExact(values.head)
+ else {
+ val valueSet = values.toSet
+ traversal.filter { item =>
+ val tmp = item.songtype; tmp.isDefined && valueSet.contains(tmp.get)
+ }
+ }
+
+ /** Traverse to nodes where songtype does not match the regular expression `value`.
+ */
+ def songtypeNot(pattern: String): Iterator[NodeType] = {
+ if (!flatgraph.misc.Regex.isRegex(pattern)) {
+ traversal.filter { node => node.songtype.isEmpty || node.songtype.get != pattern }
+ } else {
+ val matcher = flatgraph.misc.Regex.multilineMatcher(pattern)
+ traversal.filterNot { item =>
+ val tmp = item.songtype; tmp.isDefined && matcher.reset(tmp.get).matches
+ }
+ }
+ }
+
+ /** Traverse to nodes where songtype does not match any of the regular expressions in `values`.
+ */
+ def songtypeNot(patterns: String*): Iterator[NodeType] = {
+ val matchers = patterns.map(flatgraph.misc.Regex.multilineMatcher)
+ traversal.filterNot { item =>
+ val tmp = item.songtype; tmp.isDefined && matchers.exists { _.reset(tmp.get).matches }
+ }
+ }
+
}
/* accessors for base nodes end */
}
@@ -203,7 +354,10 @@ trait ConcreteStoredConversions extends ConcreteBaseConversions {
import Accessors.*
implicit def accessPropertyNameTraversal[NodeType <: nodes.StoredNode & nodes.StaticType[nodes.HasNameEMT]](
traversal: IterableOnce[NodeType]
- ): Traversal_Property_Name[NodeType] = new Traversal_Property_Name(traversal.iterator)
+ ): Traversal_Property_name[NodeType] = new Traversal_Property_name(traversal.iterator)
+ implicit def accessPropertySongtypeTraversal[NodeType <: nodes.StoredNode & nodes.StaticType[nodes.HasSongtypeEMT]](
+ traversal: IterableOnce[NodeType]
+ ): Traversal_Property_songType[NodeType] = new Traversal_Property_songType(traversal.iterator)
}
trait ConcreteBaseConversions {
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Artist.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Artist.scala
new file mode 100644
index 00000000..9a1f3d00
--- /dev/null
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Artist.scala
@@ -0,0 +1,54 @@
+package flatgraph.testdomains.gratefuldead.neighboraccessors
+
+import flatgraph.testdomains.gratefuldead.nodes
+import flatgraph.testdomains.gratefuldead.Language.*
+
+final class AccessNeighborsForArtist(val node: nodes.Artist) extends AnyVal {
+
+ /** Traverse to song via sungBy IN edge.
+ */
+ @deprecated("please use sang instead")
+ def songViaSungbyIn: Iterator[nodes.Song] = sang
+
+ /** Traverse to song via sungBy IN edge.
+ */
+ def sang: Iterator[nodes.Song] = sungbyIn.collectAll[nodes.Song]
+
+ /** Traverse to song via writtenBy IN edge.
+ */
+ @deprecated("please use wrote instead")
+ def songViaWrittenbyIn: Iterator[nodes.Song] = wrote
+
+ /** Traverse to song via writtenBy IN edge.
+ */
+ def wrote: Iterator[nodes.Song] = writtenbyIn.collectAll[nodes.Song]
+
+ def sungbyIn: Iterator[nodes.Song] = node._sungbyIn.cast[nodes.Song]
+
+ def writtenbyIn: Iterator[nodes.Song] = node._writtenbyIn.cast[nodes.Song]
+}
+
+final class AccessNeighborsForArtistTraversal(val traversal: Iterator[nodes.Artist]) extends AnyVal {
+
+ /** Traverse to song via sungBy IN edge.
+ */
+ def sang: Iterator[nodes.Song] = traversal.flatMap(_.sang)
+
+ /** Traverse to song via sungBy IN edge.
+ */
+ @deprecated("please use sang instead")
+ def songViaSungbyIn: Iterator[nodes.Song] = traversal.flatMap(_.songViaSungbyIn)
+
+ /** Traverse to song via writtenBy IN edge.
+ */
+ def wrote: Iterator[nodes.Song] = traversal.flatMap(_.wrote)
+
+ /** Traverse to song via writtenBy IN edge.
+ */
+ @deprecated("please use wrote instead")
+ def songViaWrittenbyIn: Iterator[nodes.Song] = traversal.flatMap(_.songViaWrittenbyIn)
+
+ def sungbyIn: Iterator[nodes.Song] = traversal.flatMap(_.sungbyIn)
+
+ def writtenbyIn: Iterator[nodes.Song] = traversal.flatMap(_.writtenbyIn)
+}
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Song.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Song.scala
index 2b0b17b7..f94a8cb2 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Song.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/Song.scala
@@ -5,18 +5,59 @@ import flatgraph.testdomains.gratefuldead.Language.*
final class AccessNeighborsForSong(val node: nodes.Song) extends AnyVal {
- /** Traverse to Song via followedBy IN edge.
+ /** Traverse to artist via sungBy OUT edge.
+ */
+ @deprecated("please use sungBy instead")
+ def artistViaSungbyOut: nodes.Artist = sungBy
+
+ /** Traverse to artist via sungBy OUT edge.
+ */
+ def sungBy: nodes.Artist = {
+ try { sungbyOut.collectAll[nodes.Artist].next() }
+ catch {
+ case e: java.util.NoSuchElementException =>
+ throw new flatgraph.SchemaViolationException(
+ "OUT edge with label sungBy to an adjacent artist is mandatory, but not defined for this song node with seq=" + node.seq,
+ e
+ )
+ }
+ }
+
+ /** Traverse to artist via writtenBy OUT edge.
+ */
+ @deprecated("please use writtenBy instead")
+ def artistViaWrittenbyOut: nodes.Artist = writtenBy
+
+ /** Traverse to artist via writtenBy OUT edge.
+ */
+ def writtenBy: nodes.Artist = {
+ try { writtenbyOut.collectAll[nodes.Artist].next() }
+ catch {
+ case e: java.util.NoSuchElementException =>
+ throw new flatgraph.SchemaViolationException(
+ "OUT edge with label writtenBy to an adjacent artist is mandatory, but not defined for this song node with seq=" + node.seq,
+ e
+ )
+ }
+ }
+
+ /** Traverse to song via followedBy IN edge.
*/
def songViaFollowedbyIn: Iterator[nodes.Song] = followedbyIn.collectAll[nodes.Song]
- /** Traverse to Song via followedBy OUT edge.
+ /** Traverse to song via followedBy OUT edge.
+ */
+ @deprecated("please use followedBy instead")
+ def songViaFollowedbyOut: nodes.Song = followedBy
+
+ /** Traverse to song via followedBy OUT edge.
*/
- def songViaFollowedbyOut: nodes.Song = {
+ def followedBy: nodes.Song = {
try { followedbyOut.collectAll[nodes.Song].next() }
catch {
case e: java.util.NoSuchElementException =>
throw new flatgraph.SchemaViolationException(
- "OUT edge with label followedBy to an adjacent Song is mandatory, but not defined for this Song node with seq=" + node.seq,
+ "OUT edge with label followedBy to an adjacent song is mandatory, but not defined for this song node with seq=" + node.seq,
e
)
}
@@ -25,19 +66,50 @@ final class AccessNeighborsForSong(val node: nodes.Song) extends AnyVal {
def followedbyIn: Iterator[nodes.Song] = node._followedbyIn.cast[nodes.Song]
def followedbyOut: Iterator[nodes.Song] = node._followedbyOut.cast[nodes.Song]
+
+ def sungbyOut: Iterator[nodes.Artist] = node._sungbyOut.cast[nodes.Artist]
+
+ def writtenbyOut: Iterator[nodes.Artist] = node._writtenbyOut.cast[nodes.Artist]
}
final class AccessNeighborsForSongTraversal(val traversal: Iterator[nodes.Song]) extends AnyVal {
- /** Traverse to Song via followedBy IN edge.
+ /** Traverse to artist via sungBy OUT edge.
+ */
+ def sungBy: Iterator[nodes.Artist] = traversal.map(_.sungBy)
+
+ /** Traverse to artist via sungBy OUT edge.
+ */
+ @deprecated("please use sungBy instead")
+ def artistViaSungbyOut: Iterator[nodes.Artist] = traversal.map(_.artistViaSungbyOut)
+
+ /** Traverse to artist via writtenBy OUT edge.
+ */
+ def writtenBy: Iterator[nodes.Artist] = traversal.map(_.writtenBy)
+
+ /** Traverse to artist via writtenBy OUT edge.
+ */
+ @deprecated("please use writtenBy instead")
+ def artistViaWrittenbyOut: Iterator[nodes.Artist] = traversal.map(_.artistViaWrittenbyOut)
+
+ /** Traverse to song via followedBy IN edge.
*/
def songViaFollowedbyIn: Iterator[nodes.Song] = traversal.flatMap(_.songViaFollowedbyIn)
- /** Traverse to Song via followedBy OUT edge.
+ /** Traverse to song via followedBy OUT edge.
*/
+ def followedBy: Iterator[nodes.Song] = traversal.map(_.followedBy)
+
+ /** Traverse to song via followedBy OUT edge.
+ */
+ @deprecated("please use followedBy instead")
def songViaFollowedbyOut: Iterator[nodes.Song] = traversal.map(_.songViaFollowedbyOut)
def followedbyIn: Iterator[nodes.Song] = traversal.flatMap(_.followedbyIn)
def followedbyOut: Iterator[nodes.Song] = traversal.flatMap(_.followedbyOut)
+
+ def sungbyOut: Iterator[nodes.Artist] = traversal.flatMap(_.sungbyOut)
+
+ def writtenbyOut: Iterator[nodes.Artist] = traversal.flatMap(_.writtenbyOut)
}
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/package.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/package.scala
index 4cd3d8c1..b24964e1 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/package.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/neighboraccessors/package.scala
@@ -7,6 +7,12 @@ package object neighboraccessors {
object Lang extends Conversions
trait Conversions {
+ implicit def accessNeighborsForArtist(node: nodes.Artist): AccessNeighborsForArtist =
+ new AccessNeighborsForArtist(node)
+
+ implicit def accessNeighborsForArtistTraversal(traversal: IterableOnce[nodes.Artist]): AccessNeighborsForArtistTraversal =
+ new AccessNeighborsForArtistTraversal(traversal.iterator)
+
implicit def accessNeighborsForSong(node: nodes.Song): AccessNeighborsForSong =
new AccessNeighborsForSong(node)
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Artist.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Artist.scala
index 6b1b9729..eb95b56d 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Artist.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Artist.scala
@@ -10,15 +10,15 @@ trait ArtistBase extends AbstractNode with StaticType[ArtistEMT] {
override def propertiesMap: java.util.Map[String, Any] = {
import flatgraph.testdomains.gratefuldead.accessors.Lang.*
val res = new java.util.HashMap[String, Any]()
- if (("": String) != this.name) res.put("Name", this.name)
+ if (("": String) != this.name) res.put("name", this.name)
res
}
}
object Artist {
- val Label = "Artist"
+ val Label = "artist"
object PropertyNames {
- val Name = flatgraph.testdomains.gratefuldead.PropertyNames.Name
+ val Name = flatgraph.testdomains.gratefuldead.PropertyNames.name
}
object PropertyDefaults {
val Name = ""
@@ -51,11 +51,11 @@ class Artist(graph_4762: flatgraph.Graph, seq_4762: Int)
object NewArtist {
def apply(): NewArtist = new NewArtist
private val outNeighbors: Map[String, Set[String]] = Map()
- private val inNeighbors: Map[String, Set[String]] = Map()
+ private val inNeighbors: Map[String, Set[String]] = Map("sungBy" -> Set("song"), "writtenBy" -> Set("song"))
}
class NewArtist extends NewNode(0.toShort) with ArtistBase {
override type StoredNodeType = Artist
- override def label: String = "Artist"
+ override def label: String = "artist"
override def isValidOutNeighbor(edgeLabel: String, n: NewNode): Boolean = {
NewArtist.outNeighbors.getOrElse(edgeLabel, Set.empty).contains(n.label)
diff --git a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Song.scala b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Song.scala
index a0b765ec..b38d1a40 100644
--- a/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Song.scala
+++ b/test-schemas-domain-classes/src/main/scala/flatgraph/testdomains/gratefuldead/nodes/Song.scala
@@ -3,22 +3,24 @@ package flatgraph.testdomains.gratefuldead.nodes
import flatgraph.testdomains.gratefuldead.Language.*
import scala.collection.immutable.{IndexedSeq, ArraySeq}
-trait SongEMT extends AnyRef with HasNameEMT
+trait SongEMT extends AnyRef with HasNameEMT with HasSongtypeEMT
trait SongBase extends AbstractNode with StaticType[SongEMT] {
override def propertiesMap: java.util.Map[String, Any] = {
import flatgraph.testdomains.gratefuldead.accessors.Lang.*
val res = new java.util.HashMap[String, Any]()
- if (("": String) != this.name) res.put("Name", this.name)
+ if (("": String) != this.name) res.put("name", this.name)
+ this.songtype.foreach { p => res.put("songType", p) }
res
}
}
object Song {
- val Label = "Song"
+ val Label = "song"
object PropertyNames {
- val Name = flatgraph.testdomains.gratefuldead.PropertyNames.Name
+ val Name = flatgraph.testdomains.gratefuldead.PropertyNames.name
+ val Songtype = flatgraph.testdomains.gratefuldead.PropertyNames.songType
}
object PropertyDefaults {
val Name = ""
@@ -33,29 +35,32 @@ class Song(graph_4762: flatgraph.Graph, seq_4762: Int)
override def productElementName(n: Int): String =
n match {
case 0 => "name"
+ case 1 => "songtype"
case _ => ""
}
override def productElement(n: Int): Any =
n match {
case 0 => this.name
+ case 1 => this.songtype
case _ => null
}
override def productPrefix = "Song"
- override def productArity = 1
+ override def productArity = 2
override def canEqual(that: Any): Boolean = that != null && that.isInstanceOf[Song]
}
object NewSong {
- def apply(): NewSong = new NewSong
- private val outNeighbors: Map[String, Set[String]] = Map("followedBy" -> Set("Song"))
- private val inNeighbors: Map[String, Set[String]] = Map("followedBy" -> Set("Song"))
+ def apply(): NewSong = new NewSong
+ private val outNeighbors: Map[String, Set[String]] =
+ Map("followedBy" -> Set("song"), "sungBy" -> Set("artist"), "writtenBy" -> Set("artist"))
+ private val inNeighbors: Map[String, Set[String]] = Map("followedBy" -> Set("song"))
}
class NewSong extends NewNode(1.toShort) with SongBase {
override type StoredNodeType = Song
- override def label: String = "Song"
+ override def label: String = "song"
override def isValidOutNeighbor(edgeLabel: String, n: NewNode): Boolean = {
NewSong.outNeighbors.getOrElse(edgeLabel, Set.empty).contains(n.label)
@@ -64,31 +69,38 @@ class NewSong extends NewNode(1.toShort) with SongBase {
NewSong.inNeighbors.getOrElse(edgeLabel, Set.empty).contains(n.label)
}
- var name: String = "": String
- def name(value: String): this.type = { this.name = value; this }
+ var name: String = "": String
+ var songtype: Option[String] = None
+ def name(value: String): this.type = { this.name = value; this }
+ def songtype(value: Option[String]): this.type = { this.songtype = value; this }
+ def songtype(value: String): this.type = { this.songtype = Option(value); this }
override def flattenProperties(interface: flatgraph.BatchedUpdateInterface): Unit = {
interface.insertProperty(this, 0, Iterator(this.name))
+ if (songtype.nonEmpty) interface.insertProperty(this, 1, this.songtype)
}
override def copy(): this.type = {
val newInstance = new NewSong
newInstance.name = this.name
+ newInstance.songtype = this.songtype
newInstance.asInstanceOf[this.type]
}
override def productElementName(n: Int): String =
n match {
case 0 => "name"
+ case 1 => "songtype"
case _ => ""
}
override def productElement(n: Int): Any =
n match {
case 0 => this.name
+ case 1 => this.songtype
case _ => null
}
override def productPrefix = "NewSong"
- override def productArity = 1
+ override def productArity = 2
override def canEqual(that: Any): Boolean = that != null && that.isInstanceOf[NewSong]
}
diff --git a/test-schemas/src/main/scala/flatgraph/testdomains/gratefuldead/Schema.scala b/test-schemas/src/main/scala/flatgraph/testdomains/gratefuldead/Schema.scala
index dbbc5fd3..b454a77c 100644
--- a/test-schemas/src/main/scala/flatgraph/testdomains/gratefuldead/Schema.scala
+++ b/test-schemas/src/main/scala/flatgraph/testdomains/gratefuldead/Schema.scala
@@ -11,21 +11,29 @@ object Schema {
val instance: flatgraph.schema.Schema = {
val builder = new SchemaBuilder(domainShortName = "GratefulDead", basePackage = "flatgraph.testdomains.gratefuldead")
- val name = builder.addProperty("Name", ValueType.String).mandatory(default = "")
- val songType = builder.addProperty("SongType", ValueType.String)
+ // properties
+ val name = builder.addProperty("name", ValueType.String).mandatory(default = "")
+ val songType = builder.addProperty("songType", ValueType.String)
val performances = builder.addProperty("performances", ValueType.Int)
val weight = builder.addProperty("weight", ValueType.Long).mandatory(default = 0)
+ // nodes
val artist = builder
- .addNodeType("Artist")
+ .addNodeType("artist")
.addProperty(name)
val song = builder
- .addNodeType("Song")
+ .addNodeType("song")
.addProperty(name)
+ .addProperty(songType)
+ // edges
+ val sungBy = builder.addEdgeType("sungBy")
+ val writtenBy = builder.addEdgeType("writtenBy")
val followedBy = builder.addEdgeType("followedBy").addProperty(weight)
- song.addOutEdge(followedBy, inNode = song, cardinalityOut = Cardinality.One)
+ song.addOutEdge(sungBy, inNode = artist, cardinalityOut = Cardinality.One, stepNameOut = "sungBy", stepNameIn = "sang")
+ song.addOutEdge(writtenBy, inNode = artist, cardinalityOut = Cardinality.One, stepNameOut = "writtenBy", stepNameIn = "wrote")
+ song.addOutEdge(followedBy, inNode = song, cardinalityOut = Cardinality.One, stepNameOut = "followedBy")
builder.build
}