Skip to content

Commit

Permalink
refactor testdomain schemas: move to non-flatgraph package, simplify …
Browse files Browse the repository at this point in the history
…setup
  • Loading branch information
mpollmeier committed May 7, 2024
1 parent 08009ce commit e649147
Show file tree
Hide file tree
Showing 41 changed files with 2,584 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package testdomains.generic.accessors
import testdomains.generic.nodes
import scala.collection.immutable.IndexedSeq

object Lang extends ConcreteStoredConversions

object Accessors {
/* accessors for concrete stored nodes start */
final class Access_Property_int_list(val node: nodes.StoredNode) extends AnyVal {
def intList: IndexedSeq[Int] = flatgraph.Accessors.getNodePropertyMulti[Int](node.graph, node.nodeKind, 0, node.seq)
}
final class Access_Property_int_mandatory(val node: nodes.StoredNode) extends AnyVal {
def intMandatory: Int = flatgraph.Accessors.getNodePropertySingle(node.graph, node.nodeKind, 1, node.seq(), 42: Int)
}
final class Access_Property_int_optional(val node: nodes.StoredNode) extends AnyVal {
def intOptional: Option[Int] = flatgraph.Accessors.getNodePropertyOption[Int](node.graph, node.nodeKind, 2, node.seq)
}
final class Access_Property_string_list(val node: nodes.StoredNode) extends AnyVal {
def stringList: IndexedSeq[String] = flatgraph.Accessors.getNodePropertyMulti[String](node.graph, node.nodeKind, 3, node.seq)
}
final class Access_Property_string_mandatory(val node: nodes.StoredNode) extends AnyVal {
def stringMandatory: String = flatgraph.Accessors.getNodePropertySingle(node.graph, node.nodeKind, 4, node.seq(), "<empty>": String)
}
final class Access_Property_string_optional(val node: nodes.StoredNode) extends AnyVal {
def stringOptional: Option[String] = flatgraph.Accessors.getNodePropertyOption[String](node.graph, node.nodeKind, 5, node.seq)
}
/* accessors for concrete stored nodes end */

/* accessors for base nodes start */
final class Access_NodeABase(val node: nodes.NodeABase) extends AnyVal {
def intList: IndexedSeq[Int] = node match {
case stored: nodes.StoredNode => new Access_Property_int_list(stored).intList
case newNode: nodes.NewNodeA => newNode.intList
}
def intMandatory: Int = node match {
case stored: nodes.StoredNode => new Access_Property_int_mandatory(stored).intMandatory
case newNode: nodes.NewNodeA => newNode.intMandatory
}
def intOptional: Option[Int] = node match {
case stored: nodes.StoredNode => new Access_Property_int_optional(stored).intOptional
case newNode: nodes.NewNodeA => newNode.intOptional
}
def stringList: IndexedSeq[String] = node match {
case stored: nodes.StoredNode => new Access_Property_string_list(stored).stringList
case newNode: nodes.NewNodeA => newNode.stringList
}
def stringMandatory: String = node match {
case stored: nodes.StoredNode => new Access_Property_string_mandatory(stored).stringMandatory
case newNode: nodes.NewNodeA => newNode.stringMandatory
}
def stringOptional: Option[String] = node match {
case stored: nodes.StoredNode => new Access_Property_string_optional(stored).stringOptional
case newNode: nodes.NewNodeA => newNode.stringOptional
}
}
final class Access_NodeBBase(val node: nodes.NodeBBase) extends AnyVal {
def stringOptional: Option[String] = node match {
case stored: nodes.StoredNode => new Access_Property_string_optional(stored).stringOptional
case newNode: nodes.NewNodeB => newNode.stringOptional
}
}
/* accessors for base nodes end */
}

trait ConcreteStoredConversions extends ConcreteBaseConversions {
import Accessors.*
implicit def accessPropertyIntList(node: nodes.StoredNode & nodes.StaticType[nodes.HasIntListEMT]): Access_Property_int_list =
new Access_Property_int_list(node)
implicit def accessPropertyIntMandatory(
node: nodes.StoredNode & nodes.StaticType[nodes.HasIntMandatoryEMT]
): Access_Property_int_mandatory = new Access_Property_int_mandatory(node)
implicit def accessPropertyIntOptional(node: nodes.StoredNode & nodes.StaticType[nodes.HasIntOptionalEMT]): Access_Property_int_optional =
new Access_Property_int_optional(node)
implicit def accessPropertyStringList(node: nodes.StoredNode & nodes.StaticType[nodes.HasStringListEMT]): Access_Property_string_list =
new Access_Property_string_list(node)
implicit def accessPropertyStringMandatory(
node: nodes.StoredNode & nodes.StaticType[nodes.HasStringMandatoryEMT]
): Access_Property_string_mandatory = new Access_Property_string_mandatory(node)
implicit def accessPropertyStringOptional(
node: nodes.StoredNode & nodes.StaticType[nodes.HasStringOptionalEMT]
): Access_Property_string_optional = new Access_Property_string_optional(node)
}

trait ConcreteBaseConversions {
import Accessors.*
implicit def access_NodeABase(node: nodes.NodeABase): Access_NodeABase = new Access_NodeABase(node)
implicit def access_NodeBBase(node: nodes.NodeBBase): Access_NodeBBase = new Access_NodeBBase(node)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package testdomains.generic.nodes

/** Node types with this marker trait are guaranteed to have the int_list property. EMT stands for: "erased marker trait", it exists only at
* compile time in order to improve type safety.
*/
trait HasIntListEMT

/** Node types with this marker trait are guaranteed to have the int_mandatory property. EMT stands for: "erased marker trait", it exists
* only at compile time in order to improve type safety.
*/
trait HasIntMandatoryEMT

/** Node types with this marker trait are guaranteed to have the int_optional property. EMT stands for: "erased marker trait", it exists
* only at compile time in order to improve type safety.
*/
trait HasIntOptionalEMT

/** Node types with this marker trait are guaranteed to have the string_list property. EMT stands for: "erased marker trait", it exists only
* at compile time in order to improve type safety.
*/
trait HasStringListEMT

/** Node types with this marker trait are guaranteed to have the string_mandatory property. EMT stands for: "erased marker trait", it exists
* only at compile time in order to improve type safety.
*/
trait HasStringMandatoryEMT

/** Node types with this marker trait are guaranteed to have the string_optional property. EMT stands for: "erased marker trait", it exists
* only at compile time in order to improve type safety.
*/
trait HasStringOptionalEMT
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package testdomains.generic;

import java.util.HashSet;
import java.util.Set;

public class EdgeTypes {


public static final String connected_to = "connected_to";

public static Set<String> ALL = new HashSet<String>() {{
add(connected_to);
}};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package testdomains.generic.edges

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.toShort, subSeq_4862, property_4862) {
override def propertyName: Option[String] = ConnectedTo.propertyName
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package testdomains.generic
import flatgraph.DiffGraphBuilder
import flatgraph.help.DocSearchPackages
import flatgraph.help.Table.AvailableWidthProvider
import Language.*

object GenericDomain {
val defaultDocSearchPackage = DocSearchPackages.default.withAdditionalPackage(getClass.getPackage.getName)

@scala.annotation.implicitNotFound("""If you're using flatgraph purely without a schema and associated generated domain classes, you can
|start with `given DocSearchPackages = DocSearchPackages.default`.
|If you have generated domain classes, use `given DocSearchPackages = MyDomain.defaultDocSearchPackage`.
|If you have additional custom extension steps that specify help texts via @Doc annotations, use `given DocSearchPackages = MyDomain.defaultDocSearchPackage.withAdditionalPackage("my.custom.package)"`
|""".stripMargin)
def help(implicit searchPackageNames: DocSearchPackages, availableWidthProvider: AvailableWidthProvider) =
flatgraph.help.TraversalHelp(searchPackageNames).forTraversalSources(verbose = false)

@scala.annotation.implicitNotFound("""If you're using flatgraph purely without a schema and associated generated domain classes, you can
|start with `given DocSearchPackages = DocSearchPackages.default`.
|If you have generated domain classes, use `given DocSearchPackages = MyDomain.defaultDocSearchPackage`.
|If you have additional custom extension steps that specify help texts via @Doc annotations, use `given DocSearchPackages = MyDomain.defaultDocSearchPackage.withAdditionalPackage("my.custom.package)"`
|""".stripMargin)
def helpVerbose(implicit searchPackageNames: DocSearchPackages, availableWidthProvider: AvailableWidthProvider) =
flatgraph.help.TraversalHelp(searchPackageNames).forTraversalSources(verbose = true)

def empty: GenericDomain = new GenericDomain(new flatgraph.Graph(GraphSchema))

/** Instantiate a new graph with storage. If the file already exists, this will deserialize the given file into memory. `Graph.close` will
* serialise graph to that given file (and override whatever was there before), unless you specify `persistOnClose = false`.
*/
def withStorage(storagePath: java.nio.file.Path, persistOnClose: Boolean = true): GenericDomain = {
val graph = flatgraph.Graph.withStorage(GraphSchema, storagePath, persistOnClose)
new GenericDomain(graph)
}

def newDiffGraphBuilder: DiffGraphBuilder = new DiffGraphBuilder(GraphSchema)
}

class GenericDomain(private val _graph: flatgraph.Graph = new flatgraph.Graph(GraphSchema)) extends AutoCloseable {
def graph: flatgraph.Graph = _graph

def help(implicit searchPackageNames: DocSearchPackages, availableWidthProvider: AvailableWidthProvider) =
GenericDomain.help
def helpVerbose(implicit searchPackageNames: DocSearchPackages, availableWidthProvider: AvailableWidthProvider) =
GenericDomain.helpVerbose

override def close(): Unit =
_graph.close()

override def toString(): String =
String.format("GenericDomain[%s]", graph)
}

@flatgraph.help.TraversalSource
class GenericDomainNodeStarters(val wrappedGenericDomain: GenericDomain) {

@flatgraph.help.Doc(info = "all nodes")
def all: Iterator[nodes.StoredNode] = wrappedGenericDomain.graph.allNodes.asInstanceOf[Iterator[nodes.StoredNode]]

/** */
@flatgraph.help.Doc(info = """""")
def nodeA: Iterator[nodes.NodeA] = wrappedGenericDomain.graph._nodes(0).asInstanceOf[Iterator[nodes.NodeA]]

/** */
@flatgraph.help.Doc(info = """""")
def nodeB: Iterator[nodes.NodeB] = wrappedGenericDomain.graph._nodes(1).asInstanceOf[Iterator[nodes.NodeB]]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package testdomains.generic

import testdomains.generic.nodes
import testdomains.generic.edges
import flatgraph.FormalQtyType

object GraphSchema extends flatgraph.Schema {
private val nodeLabels = IndexedSeq("node_a", "node_b")
val nodeKindByLabel = nodeLabels.zipWithIndex.toMap
val edgeLabels = Array("connected_to")
val edgeKindByLabel = edgeLabels.zipWithIndex.toMap
val edgePropertyAllocators: Array[Int => Array[?]] = Array(size => Array.fill(size)("<empty>") /* label = connected_to, id = 0 */ )
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))
val nodePropertyAllocators: Array[Int => Array[?]] = Array(
size => new Array[Int](size),
size => new Array[Int](size),
size => new Array[Int](size),
size => new Array[String](size),
size => new Array[String](size),
size => new Array[String](size),
size => new Array[flatgraph.GNode](size)
)
val normalNodePropertyNames = Array("int_list", "int_mandatory", "int_optional", "string_list", "string_mandatory", "string_optional")
val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap.updated("node_b", 6)
val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = {
val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](28)
for (idx <- Range(0, 28)) {
nodePropertyDescriptors(idx) =
if ((idx & 1) == 0) FormalQtyType.NothingType
else FormalQtyType.QtyNone
}

nodePropertyDescriptors(0) = FormalQtyType.IntType // node_a.int_list
nodePropertyDescriptors(1) = FormalQtyType.QtyMulti
nodePropertyDescriptors(4) = FormalQtyType.IntType // node_a.int_mandatory
nodePropertyDescriptors(5) = FormalQtyType.QtyOne
nodePropertyDescriptors(8) = FormalQtyType.IntType // node_a.int_optional
nodePropertyDescriptors(9) = FormalQtyType.QtyOption
nodePropertyDescriptors(12) = FormalQtyType.StringType // node_a.string_list
nodePropertyDescriptors(13) = FormalQtyType.QtyMulti
nodePropertyDescriptors(16) = FormalQtyType.StringType // node_a.string_mandatory
nodePropertyDescriptors(17) = FormalQtyType.QtyOne
nodePropertyDescriptors(20) = FormalQtyType.StringType // node_a.string_optional
nodePropertyDescriptors(21) = FormalQtyType.QtyOption
nodePropertyDescriptors(24) = FormalQtyType.RefType // node_a.node_b
nodePropertyDescriptors(25) = FormalQtyType.QtyOption
nodePropertyDescriptors(22) = FormalQtyType.StringType // node_b.string_optional
nodePropertyDescriptors(23) = FormalQtyType.QtyOption
nodePropertyDescriptors
}
override def getNumberOfNodeKinds: Int = 2
override def getNumberOfEdgeKinds: Int = 1
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 = edgeKindByLabel.getOrElse(label, flatgraph.Schema.UndefinedKind)
override def getNodePropertyNames(nodeLabel: String): Set[String] = {
nodeLabel match {
case "node_a" => Set("int_list", "int_mandatory", "int_optional", "string_list", "string_mandatory", "string_optional")
case "node_b" => Set("string_optional")
case _ => Set.empty
}
}
override def getEdgePropertyName(label: String): Option[String] = {
label match {
case "connected_to" => Some("string_mandatory")
case _ => None
}
}

override def getPropertyLabel(nodeKind: Int, propertyKind: Int): String = {
if (propertyKind < 6) normalNodePropertyNames(propertyKind)
else if (propertyKind == 6 && nodeKind == 0) "node_b" /*on node node_a*/
else null
}

override def getPropertyKindByName(label: String): Int = nodePropertyByLabel.getOrElse(label, flatgraph.Schema.UndefinedKind)
override def getNumberOfPropertyKinds: Int = 7
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 =
edgeFactories(edgeKind)(src, dst, subSeq, property)
override def allocateEdgeProperty(nodeKind: Int, direction: flatgraph.Edge.Direction, edgeKind: Int, size: Int): Array[?] =
edgePropertyAllocators(edgeKind)(size)
override def getNodePropertyFormalType(nodeKind: Int, propertyKind: Int): FormalQtyType.FormalType = nodePropertyDescriptors(
propertyOffsetArrayIndex(nodeKind, propertyKind)
).asInstanceOf[FormalQtyType.FormalType]
override def getNodePropertyFormalQuantity(nodeKind: Int, propertyKind: Int): FormalQtyType.FormalQuantity = nodePropertyDescriptors(
1 + propertyOffsetArrayIndex(nodeKind, propertyKind)
).asInstanceOf[FormalQtyType.FormalQuantity]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package testdomains.generic

/** combining all implicits into one trait that can be mixed in further downstream */
trait Language
extends accessors.ConcreteStoredConversions
with traversals.ConcreteStoredConversions
with neighboraccessors.Conversions
with flatgraph.traversal.Language
with flatgraph.Implicits {
implicit def toGeneratedNodeStarters(domain: GenericDomain): GenericDomainNodeStarters = GenericDomainNodeStarters(domain)
}

object Language extends Language
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package testdomains.generic;

import java.util.HashSet;
import java.util.Set;

public class NodeTypes {


public static final String node_a = "node_a";


public static final String node_b = "node_b";

public static Set<String> ALL = new HashSet<String>() {{
add(node_a);
add(node_b);
}};

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package testdomains.generic

object PropertyErrorRegister {
private var errorMap = Set.empty[(Class[?], String)]
private val logger = org.slf4j.LoggerFactory.getLogger(getClass)

def logPropertyErrorIfFirst(clazz: Class[?], propertyName: String): Unit = {
if (!errorMap.contains((clazz, propertyName))) {
logger.warn("Property " + propertyName + " is deprecated for " + clazz.getName + ".")
errorMap += ((clazz, propertyName))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package testdomains.generic

object PropertyKeys {
val IntList = flatgraph.MultiPropertyKey[Int](kind = 0, name = "int_list")

val IntMandatory = flatgraph.SinglePropertyKey[Int](kind = 1, name = "int_mandatory", default = 42: Int)

val IntOptional = flatgraph.OptionalPropertyKey[Int](kind = 2, name = "int_optional")

val StringList = flatgraph.MultiPropertyKey[String](kind = 3, name = "string_list")

val StringMandatory = flatgraph.SinglePropertyKey[String](kind = 4, name = "string_mandatory", default = "<empty>")

val StringOptional = flatgraph.OptionalPropertyKey[String](kind = 5, name = "string_optional")
}
Loading

0 comments on commit e649147

Please sign in to comment.