From 441a43e73d6bf11ffbeb3f0323beae9c24be412c Mon Sep 17 00:00:00 2001 From: Michael Pollmeier Date: Thu, 31 Jul 2025 09:57:23 +0200 Subject: [PATCH 1/2] allow to override default edge accessor --- .../codegen/DomainClassesGenerator.scala | 10 +++++++-- .../main/scala/flatgraph/schema/Schema.scala | 11 ++++++---- .../scala/testdomains/generic/EdgeTypes.java | 4 ++++ .../testdomains/generic/GraphSchema.scala | 15 +++++++------ .../testdomains/generic/edges/EdgeTypes.scala | 10 ++++++++- .../generic/neighboraccessors/NodeA.scala | 12 ++++++++++ .../generic/neighboraccessors/NodeB.scala | 22 +++++++++++++++++++ .../generic/neighboraccessors/package.scala | 6 +++++ .../testdomains/generic/nodes/NewNodeA.scala | 2 +- .../testdomains/generic/nodes/NewNodeB.scala | 2 +- .../testdomains/generic/nodes/RootTypes.scala | 15 +++++++++++-- .../generic/nodes/RootTypesTraversals.scala | 3 +++ .../scala/flatgraph/testdomains/Generic.scala | 3 +++ 13 files changed, 97 insertions(+), 18 deletions(-) create mode 100644 test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeB.scala 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 6cff6044..f11c3770 100644 --- a/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala +++ b/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala @@ -1224,7 +1224,13 @@ class DomainClassesGenerator(schema: Schema) { case class NeighborContext(adjacentNode: AdjacentNode, scaladoc: String, defaultMethodName: String, customStepName: Option[String]) case class NeighborContextsByEdge(direction: Direction.Value, edge: EdgeType, neighborContexts: Seq[NeighborContext]) { - lazy val edgeAccessorName = camelCase(edge.name + "_" + direction) + lazy val edgeAccessorName = { + val namePart = edge.defaultAccessorName.getOrElse(edge.name) + camelCase(namePart + "_" + direction) + } + + lazy val edgeAccessorNameOnRootType = + camelCase(edge.name + "_" + direction) /** common root type across neighbors via this edge */ lazy val commonNeighborClassName = @@ -1253,7 +1259,7 @@ class DomainClassesGenerator(schema: Schema) { val stepImplementations = Seq.newBuilder[String] neighborContextsByEdge.foreach { case context @ NeighborContextsByEdge(direction, edge, neighborContexts) => stepImplementations.addOne( - s"def ${context.edgeAccessorName}: Iterator[nodes.${context.commonNeighborClassName}] = node._${context.edgeAccessorName}.cast[nodes.${context.commonNeighborClassName}]" + s"def ${context.edgeAccessorName}: Iterator[nodes.${context.commonNeighborClassName}] = node._${context.edgeAccessorNameOnRootType}.cast[nodes.${context.commonNeighborClassName}]" ) neighborContexts.foreach { case NeighborContext(adjacentNode, scaladoc, defaultMethodName, customStepName) => diff --git a/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala b/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala index 2d3792da..36520a28 100644 --- a/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala +++ b/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala @@ -226,19 +226,22 @@ class EdgeType(val name: String, val comment: Option[String], val schemaInfo: Sc with HasOptionalProtoId with HasSchemaInfo { protected var _property: Option[Property[?]] = None + protected var _defaultAccessorName: Option[String] = None override def toString = s"EdgeType($name)" def property: Option[Property[?]] = _property + def defaultAccessorName: Option[String] = _defaultAccessorName def withProperty(property: Property[?]): this.type = { _property = Option(property) this } - - @deprecated("use `withProperty` instead, edges can only have one property max", since = "0.0.49") - def addProperty(property: Property[?]): this.type = - withProperty(property) + + def withDefaultAccessorName(value: String): this.type = { + _defaultAccessorName = Option(value) + this + } } object EdgeType { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/EdgeTypes.java b/test-schemas-domain-classes/src/main/scala/testdomains/generic/EdgeTypes.java index 1c35d3e2..ef74bddb 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/EdgeTypes.java +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/EdgeTypes.java @@ -6,9 +6,13 @@ public class EdgeTypes { +public static final String ANOTHER_EDGE = "another_edge"; + + public static final String CONNECTED_TO = "connected_to"; public static Set ALL = new HashSet() {{ +add(ANOTHER_EDGE); add(CONNECTED_TO); }}; diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/GraphSchema.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/GraphSchema.scala index 57836680..99a301d4 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/GraphSchema.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/GraphSchema.scala @@ -3,15 +3,16 @@ package testdomains.generic import flatgraph.FormalQtyType object GraphSchema extends flatgraph.Schema { - private val nodeLabels = IndexedSeq("node_a", "node_b") - val nodeKindByLabel = nodeLabels.zipWithIndex.toMap - val edgeLabels: Array[String] = Array("connected_to") - val edgeKindByLabel = edgeLabels.zipWithIndex.toMap - val edgePropertyAllocators: Array[Int => Array[?]] = Array(size => Array.fill(size)("") /* label = connected_to, id = 0 */ ) + private val nodeLabels = IndexedSeq("node_a", "node_b") + val nodeKindByLabel = nodeLabels.zipWithIndex.toMap + val edgeLabels: Array[String] = Array("another_edge", "connected_to") + val edgeKindByLabel = edgeLabels.zipWithIndex.toMap + val edgePropertyAllocators: Array[Int => Array[?]] = + Array(size => null, size => Array.fill(size)("") /* label = connected_to, id = 1 */ ) val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = Array((g, seq) => new nodes.NodeA(g, seq), (g, seq) => new nodes.NodeB(g, seq)) val edgeFactories: Array[(flatgraph.GNode, flatgraph.GNode, Int, Any) => flatgraph.Edge] = - Array((s, d, subseq, p) => new edges.ConnectedTo(s, d, subseq, p)) + Array((s, d, subseq, p) => new edges.AnotherEdge(s, d, subseq, p), (s, d, subseq, p) => new edges.ConnectedTo(s, d, subseq, p)) val nodePropertyAllocators: Array[Int => Array[?]] = Array( size => new Array[Int](size), size => new Array[Int](size), @@ -63,7 +64,7 @@ object GraphSchema extends flatgraph.Schema { _newNodeInserters } override def getNumberOfNodeKinds: Int = 2 - override def getNumberOfEdgeKinds: Int = 1 + override def getNumberOfEdgeKinds: Int = 2 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) diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/edges/EdgeTypes.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/edges/EdgeTypes.scala index 1921a284..04328781 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/edges/EdgeTypes.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/edges/EdgeTypes.scala @@ -1,11 +1,19 @@ package testdomains.generic.edges +object AnotherEdge { + val Label = "another_edge" + +} + +class AnotherEdge(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_4862: Int, property_4862: Any) + extends flatgraph.Edge(src_4762, dst_4762, 0, subSeq_4862, property_4862) {} + object ConnectedTo { val Label = "connected_to" val propertyName: Option[String] = Some("string_mandatory") } class ConnectedTo(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_4862: Int, property_4862: Any) - extends flatgraph.Edge(src_4762, dst_4762, 0, subSeq_4862, property_4862) { + extends flatgraph.Edge(src_4762, dst_4762, 1, subSeq_4862, property_4862) { override def propertyName: Option[String] = ConnectedTo.propertyName } diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeA.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeA.scala index de0d9ae7..de49a116 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeA.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeA.scala @@ -9,6 +9,10 @@ final class AccessNeighborsForNodeA(val node: nodes.NodeA) extends AnyVal { */ def _nodeAViaConnectedToIn: Iterator[nodes.NodeA] = connectedToIn.collectAll[nodes.NodeA] + /** Traverse to node_b via another_edge OUT edge. + */ + def _nodeBViaAnotherEdgeOut: Iterator[nodes.NodeB] = defaultStepNameOut.collectAll[nodes.NodeB] + /** Connected neighbor node Traverse to node_a via connected_to OUT edge. */ @deprecated("please use connectedTo instead") @@ -21,6 +25,8 @@ final class AccessNeighborsForNodeA(val node: nodes.NodeA) extends AnyVal { def connectedToIn: Iterator[nodes.NodeA] = node._connectedToIn.cast[nodes.NodeA] def connectedToOut: Iterator[nodes.NodeA] = node._connectedToOut.cast[nodes.NodeA] + + def defaultStepNameOut: Iterator[nodes.NodeB] = node._anotherEdgeOut.cast[nodes.NodeB] } final class AccessNeighborsForNodeATraversal(val traversal: Iterator[nodes.NodeA]) extends AnyVal { @@ -29,6 +35,10 @@ final class AccessNeighborsForNodeATraversal(val traversal: Iterator[nodes.NodeA */ def _nodeAViaConnectedToIn: Iterator[nodes.NodeA] = traversal.flatMap(_._nodeAViaConnectedToIn) + /** Traverse to node_b via another_edge OUT edge. + */ + def _nodeBViaAnotherEdgeOut: Iterator[nodes.NodeB] = traversal.flatMap(_._nodeBViaAnotherEdgeOut) + /** Connected neighbor node Traverse to node_a via connected_to OUT edge. */ def connectedTo: Iterator[nodes.NodeA] = traversal.flatMap(_.connectedTo) @@ -41,4 +51,6 @@ final class AccessNeighborsForNodeATraversal(val traversal: Iterator[nodes.NodeA def connectedToIn: Iterator[nodes.NodeA] = traversal.flatMap(_.connectedToIn) def connectedToOut: Iterator[nodes.NodeA] = traversal.flatMap(_.connectedToOut) + + def defaultStepNameOut: Iterator[nodes.NodeB] = traversal.flatMap(_.defaultStepNameOut) } diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeB.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeB.scala new file mode 100644 index 00000000..bc67c026 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/NodeB.scala @@ -0,0 +1,22 @@ +package testdomains.generic.neighboraccessors + +import testdomains.generic.nodes +import testdomains.generic.language.* + +final class AccessNeighborsForNodeB(val node: nodes.NodeB) extends AnyVal { + + /** Traverse to node_a via another_edge IN edge. + */ + def _nodeAViaAnotherEdgeIn: Iterator[nodes.NodeA] = defaultStepNameIn.collectAll[nodes.NodeA] + + def defaultStepNameIn: Iterator[nodes.NodeA] = node._anotherEdgeIn.cast[nodes.NodeA] +} + +final class AccessNeighborsForNodeBTraversal(val traversal: Iterator[nodes.NodeB]) extends AnyVal { + + /** Traverse to node_a via another_edge IN edge. + */ + def _nodeAViaAnotherEdgeIn: Iterator[nodes.NodeA] = traversal.flatMap(_._nodeAViaAnotherEdgeIn) + + def defaultStepNameIn: Iterator[nodes.NodeA] = traversal.flatMap(_.defaultStepNameIn) +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/package.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/package.scala index 87b302a9..693f7f62 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/package.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/neighboraccessors/package.scala @@ -12,5 +12,11 @@ package object neighboraccessors { implicit def accessNeighborsForNodeATraversal(traversal: IterableOnce[nodes.NodeA]): AccessNeighborsForNodeATraversal = new AccessNeighborsForNodeATraversal(traversal.iterator) + + implicit def accessNeighborsForNodeB(node: nodes.NodeB): AccessNeighborsForNodeB = + new AccessNeighborsForNodeB(node) + + implicit def accessNeighborsForNodeBTraversal(traversal: IterableOnce[nodes.NodeB]): AccessNeighborsForNodeBTraversal = + new AccessNeighborsForNodeBTraversal(traversal.iterator) } } diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeA.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeA.scala index 1c265a53..e425fcb3 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeA.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeA.scala @@ -6,7 +6,7 @@ import scala.collection.mutable object NewNodeA { def apply(): NewNodeA = new NewNodeA - private val outNeighbors: Map[String, Set[String]] = Map("connected_to" -> Set("node_a")) + private val outNeighbors: Map[String, Set[String]] = Map("another_edge" -> Set("node_b"), "connected_to" -> Set("node_a")) private val inNeighbors: Map[String, Set[String]] = Map("connected_to" -> Set("node_a")) object InsertionHelpers { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeB.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeB.scala index 1202c75c..884b9cf9 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeB.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/NewNodeB.scala @@ -7,7 +7,7 @@ import scala.collection.mutable object NewNodeB { def apply(): NewNodeB = new NewNodeB private val outNeighbors: Map[String, Set[String]] = Map() - private val inNeighbors: Map[String, Set[String]] = Map() + private val inNeighbors: Map[String, Set[String]] = Map("another_edge" -> Set("node_a")) object InsertionHelpers { object NewNodeInserter_NodeB_stringOptional extends flatgraph.NewNodePropertyInsertionHelper { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypes.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypes.scala index ccfc6a91..4c32eb2b 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypes.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypes.scala @@ -17,17 +17,28 @@ abstract class StoredNode(graph_4762: flatgraph.Graph, kind_4762: Short, seq_476 extends flatgraph.GNode(graph_4762, kind_4762, seq_4762) with AbstractNode { - final def _connectedToOut: Iterator[StoredNode] = { + final def _anotherEdgeOut: Iterator[StoredNode] = { flatgraph.Accessors .getNeighborsOut(this.graph, nodeKind = this.nodeKind, seq = this.seq, edgeKind = 0) .asInstanceOf[Iterator[StoredNode]] } - final def _connectedToIn: Iterator[StoredNode] = { + final def _anotherEdgeIn: Iterator[StoredNode] = { flatgraph.Accessors .getNeighborsIn(this.graph, nodeKind = this.nodeKind, seq = this.seq, edgeKind = 0) .asInstanceOf[Iterator[StoredNode]] } + final def _connectedToOut: Iterator[StoredNode] = { + flatgraph.Accessors + .getNeighborsOut(this.graph, nodeKind = this.nodeKind, seq = this.seq, edgeKind = 1) + .asInstanceOf[Iterator[StoredNode]] + } + final def _connectedToIn: Iterator[StoredNode] = { + flatgraph.Accessors + .getNeighborsIn(this.graph, nodeKind = this.nodeKind, seq = this.seq, edgeKind = 1) + .asInstanceOf[Iterator[StoredNode]] + } + } abstract class NewNode(val nodeKind: Short) extends AbstractNode with flatgraph.DNode { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypesTraversals.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypesTraversals.scala index 10b03f2f..8f0635b4 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypesTraversals.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/nodes/RootTypesTraversals.scala @@ -2,6 +2,9 @@ package testdomains.generic.nodes extension (iterator: Iterator[StoredNode]) { + final def _anotherEdgeOut: Iterator[StoredNode] = iterator.flatMap(_._anotherEdgeOut) + final def _anotherEdgeIn: Iterator[StoredNode] = iterator.flatMap(_._anotherEdgeIn) + final def _connectedToOut: Iterator[StoredNode] = iterator.flatMap(_._connectedToOut) final def _connectedToIn: Iterator[StoredNode] = iterator.flatMap(_._connectedToIn) diff --git a/test-schemas/src/main/scala/flatgraph/testdomains/Generic.scala b/test-schemas/src/main/scala/flatgraph/testdomains/Generic.scala index b63c4b7b..5c79d340 100644 --- a/test-schemas/src/main/scala/flatgraph/testdomains/Generic.scala +++ b/test-schemas/src/main/scala/flatgraph/testdomains/Generic.scala @@ -34,6 +34,9 @@ object Generic { val connectedTo = builder.addEdgeType("connected_to").withProperty(stringMandatory) nodeA.addOutEdge(connectedTo, nodeA, stepNameOut = "connectedTo", stepNameOutDoc = "Connected neighbor node") + val anotherEdge = builder.addEdgeType("another_edge").withDefaultAccessorName("default_step_name") + nodeA.addOutEdge(anotherEdge, nodeB) + builder.build } } From f385a0e88e98b477f252925caccc9b20e25850b2 Mon Sep 17 00:00:00 2001 From: Michael Pollmeier Date: Thu, 31 Jul 2025 10:51:55 +0200 Subject: [PATCH 2/2] fmt --- .../src/main/scala/flatgraph/schema/Schema.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala b/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala index 36520a28..2c4b6a93 100644 --- a/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala +++ b/domain-classes-generator/src/main/scala/flatgraph/schema/Schema.scala @@ -225,19 +225,19 @@ class EdgeType(val name: String, val comment: Option[String], val schemaInfo: Sc extends HasClassName with HasOptionalProtoId with HasSchemaInfo { - protected var _property: Option[Property[?]] = None + protected var _property: Option[Property[?]] = None protected var _defaultAccessorName: Option[String] = None override def toString = s"EdgeType($name)" - def property: Option[Property[?]] = _property + def property: Option[Property[?]] = _property def defaultAccessorName: Option[String] = _defaultAccessorName def withProperty(property: Property[?]): this.type = { _property = Option(property) this } - + def withDefaultAccessorName(value: String): this.type = { _defaultAccessorName = Option(value) this