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 291554fa..d96d155e 100644 --- a/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala +++ b/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala @@ -137,7 +137,9 @@ class DomainClassesGenerator(schema: Schema) { |""".stripMargin ) - os.write(nodesOutputDir / "RootTypesTraversals.scala", generateRootTypesTraversals(schema)) + generateRootTypesTraversals(schema).foreach { source => + os.write(nodesOutputDir / "RootTypesTraversals.scala", source) + } val markerTraitsForProperties = relevantProperties .map { p => @@ -146,75 +148,76 @@ class DomainClassesGenerator(schema: Schema) { |trait Has${p.className}EMT""".stripMargin } .mkString("\n") - val basetypefile = schema.nodeBaseTypes - .map { baseType => - val newExtendz = newExtendzMap(baseType) - val mixinsBase = List("AbstractNode") ++ newExtendz.map(_.className + "Base") ++ baseType.markerTraits.map(_.name) - - val mixinsStored = - List("StoredNode", s"${baseType.className}Base") ++ newExtendz.map(_.className) ++ baseType.markerTraits.map(_.name) - val mixinsNew = - List("NewNode", s"${baseType.className}Base") ++ baseType.extendz.map(_.className + "New") ++ baseType.markerTraits.map(_.name) - val newProperties = newPropsAtNodeList(baseType) - val propertyDefaults = newProperties - .collect { - case p if p.hasDefault => - s"""val ${p.className} = ${Helpers.defaultValueImpl(p.default.get)}""" - } - .mkString("\n") - val mixinsEMT = - (List("AnyRef") ++ newExtendz.map { p => s"${p.className}EMT" } ++ newProperties.map { p => s"Has${p.className}EMT" }) - .mkString(" with ") - val oldProperties = baseType.properties.toSet.diff(newProperties.toSet).toList.sortBy(_.name) - val oldExtendz = baseType.extendzRecursively.toSet.diff(newExtendz.toSet).toList.sortBy(_.name) - - val newNodeDefs: Seq[String] = { - for { - property <- newProperties - pname = camelCase(property.name) - ptyp = unpackTypeUnboxed(property.valueType, isStored = false, raised = false) - } yield property.cardinality match { - case Cardinality.List => - Seq( - s"def ${pname}: IndexedSeq[$ptyp]", - s"def ${pname}_=(value: IndexedSeq[$ptyp]): Unit", - s"def ${pname}(value: IterableOnce[$ptyp]): this.type" - ) - case Cardinality.ZeroOrOne => - Seq( - s"def ${pname}: Option[$ptyp]", - s"def ${pname}_=(value: Option[$ptyp]): Unit", - s"def ${pname}(value: Option[$ptyp]): this.type", - s"def ${pname}(value: $ptyp): this.type" - ) - case one: Cardinality.One[?] => - Seq(s"def ${pname}: $ptyp", s"def ${pname}_=(value: $ptyp): Unit", s"def ${pname}(value: $ptyp): this.type") - } - }.flatten - - s"""trait ${baseType.className}EMT extends $mixinsEMT - | - |trait ${baseType.className}Base extends ${mixinsBase.mkString(" with ")} with StaticType[${baseType.className}EMT] - | // new properties: ${newProperties.map { _.name }.mkString(", ")} - | // inherited properties: ${oldProperties.map { _.name }.mkString(", ")} - | // inherited interfaces: ${oldExtendz.map(_.name).mkString(", ")} - | // implementing nodes: ${nodeTypes - .filter { n => n.extendzRecursively.contains(baseType) } - .map(_.name) - .mkString(", ")} - |trait ${baseType.className} extends ${mixinsStored.mkString(" with ")} with StaticType[${baseType.className}EMT] - | - |object ${baseType.className} { - | object PropertyDefaults { - | $propertyDefaults - | } - |} - | - |trait ${baseType.className}New extends ${mixinsNew.mkString(" with ")} with StaticType[${baseType.className}EMT]{ - | ${newNodeDefs.mkString("\n")} - |} - |""".stripMargin + // format: off + val basetypefile = schema.nodeBaseTypes.map { baseType => + val newExtendz = newExtendzMap(baseType) + val mixinsBase = List("AbstractNode") ++ newExtendz.map(_.className + "Base") ++ baseType.markerTraits.map(_.name) + + val mixinsStored = + List("StoredNode", s"${baseType.className}Base") ++ newExtendz.map(_.className) ++ baseType.markerTraits.map(_.name) + val mixinsNew = + List("NewNode", s"${baseType.className}Base") ++ baseType.extendz.map(_.className + "New") ++ baseType.markerTraits.map(_.name) + val newProperties = newPropsAtNodeList(baseType) + val propertyDefaults = newProperties + .collect { + case p if p.hasDefault => + s"""val ${p.className} = ${Helpers.defaultValueImpl(p.default.get)}""" + } + .mkString("\n") + val mixinsEMT = + (List("AnyRef") ++ newExtendz.map { p => s"${p.className}EMT" } ++ newProperties.map { p => s"Has${p.className}EMT" }) + .mkString(" with ") + val oldProperties = baseType.properties.toSet.diff(newProperties.toSet).toList.sortBy(_.name) + val oldExtendz = baseType.extendzRecursively.toSet.diff(newExtendz.toSet).toList.sortBy(_.name) + + val newNodeDefs: Seq[String] = { + for { + property <- newProperties + pname = camelCase(property.name) + ptyp = unpackTypeUnboxed(property.valueType, isStored = false, raised = false) + } yield property.cardinality match { + case Cardinality.List => + Seq( + s"def ${pname}: IndexedSeq[$ptyp]", + s"def ${pname}_=(value: IndexedSeq[$ptyp]): Unit", + s"def ${pname}(value: IterableOnce[$ptyp]): this.type" + ) + case Cardinality.ZeroOrOne => + Seq( + s"def ${pname}: Option[$ptyp]", + s"def ${pname}_=(value: Option[$ptyp]): Unit", + s"def ${pname}(value: Option[$ptyp]): this.type", + s"def ${pname}(value: $ptyp): this.type" + ) + case one: Cardinality.One[?] => + Seq(s"def ${pname}: $ptyp", s"def ${pname}_=(value: $ptyp): Unit", s"def ${pname}(value: $ptyp): this.type") + } + }.flatten + + s"""trait ${baseType.className}EMT extends $mixinsEMT + | + |trait ${baseType.className}Base extends ${mixinsBase.mkString(" with ")} with StaticType[${baseType.className}EMT] + | // new properties: ${newProperties.map { _.name }.mkString(", ")} + | // inherited properties: ${oldProperties.map { _.name }.mkString(", ")} + | // inherited interfaces: ${oldExtendz.map(_.name).mkString(", ")} + | // implementing nodes: ${nodeTypes + .filter { n => n.extendzRecursively.contains(baseType) } + .map(_.name) + .mkString(", ")} + |trait ${baseType.className} extends ${mixinsStored.mkString(" with ")} with StaticType[${baseType.className}EMT] + | + |object ${baseType.className} { + | object PropertyDefaults { + | $propertyDefaults + | } + |} + | + |trait ${baseType.className}New extends ${mixinsNew.mkString(" with ")} with StaticType[${baseType.className}EMT]{ + | ${newNodeDefs.mkString("\n")} + |} + |""".stripMargin } + // format: on .mkString( s"""package $basePackage.nodes | @@ -225,49 +228,50 @@ class DomainClassesGenerator(schema: Schema) { os.write(nodesOutputDir / "BaseTypes.scala", basetypefile) val edgeKindByEdgeType = edgeTypes.iterator.zipWithIndex.toMap - val edgeTypesSource = edgeTypes.iterator - .map { edgeType => - // format: off - val propertyAccessorMaybe: Option[String] = edgeType.property.map { p => - p.cardinality match { - case _: Cardinality.One[?] => - s"""def ${camelCase(p.name)}: ${unpackTypeUnboxed(p.valueType, true )} = - | this.property.asInstanceOf[${unpackTypeUnboxed(p.valueType, true)}]""".stripMargin - case Cardinality.ZeroOrOne => - s"""def ${camelCase(p.name)}: Option[${unpackTypeUnboxed(p.valueType, true)}] = - | Option(this.property.asInstanceOf[${unpackTypeBoxed(p.valueType, true)}])""".stripMargin - case Cardinality.List => - throw new RuntimeException("edge properties are only supported with cardinality one or optional") - } + // format: off + val edgeTypesSource = edgeTypes.iterator.map { edgeType => + val propertyAccessorMaybe: Option[String] = edgeType.property.map { p => + p.cardinality match { + case _: Cardinality.One[?] => + s"""def ${camelCase(p.name)}: ${unpackTypeUnboxed(p.valueType, true )} = + | this.property.asInstanceOf[${unpackTypeUnboxed(p.valueType, true)}]""".stripMargin + case Cardinality.ZeroOrOne => + s"""def ${camelCase(p.name)}: Option[${unpackTypeUnboxed(p.valueType, true)}] = + | Option(this.property.asInstanceOf[${unpackTypeBoxed(p.valueType, true)}])""".stripMargin + case Cardinality.List => + throw new RuntimeException("edge properties are only supported with cardinality one or optional") } + } - val propertyNameImplForObject = edgeType.property.map { property=> - s"""val propertyName: Option[String] = Some("${property.name}")""" - } - val propertyNameImplForClass = propertyNameImplForObject.map { _ => - s"override def propertyName: Option[String] = ${edgeType.className}.propertyName" - } + val propertyNameImplForObject = edgeType.property.map { property=> + s"""val propertyName: Option[String] = Some("${property.name}")""" + } + val propertyNameImplForClass = propertyNameImplForObject.map { _ => + s"override def propertyName: Option[String] = ${edgeType.className}.propertyName" + } - s"""object ${edgeType.className} { - | val Label = "${edgeType.name}" - | ${propertyNameImplForObject.getOrElse("")} - |} - | - |class ${edgeType.className}(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_4862: Int, property_4862: Any) - | extends flatgraph.Edge(src_4762, dst_4762, ${edgeKindByEdgeType(edgeType)}.toShort, subSeq_4862, property_4862) { - | ${propertyNameImplForClass.getOrElse("")} - |} - |""".stripMargin - // format: on + s"""object ${edgeType.className} { + | val Label = "${edgeType.name}" + | ${propertyNameImplForObject.getOrElse("")} + |} + | + |class ${edgeType.className}(src_4762: flatgraph.GNode, dst_4762: flatgraph.GNode, subSeq_4862: Int, property_4862: Any) + | extends flatgraph.Edge(src_4762, dst_4762, ${edgeKindByEdgeType(edgeType)}.toShort, subSeq_4862, property_4862) { + | ${propertyNameImplForClass.getOrElse("")} + |} + |""".stripMargin + // format: on } .mkString( s"""package $basePackage.edges - | - |""".stripMargin, + | + |""".stripMargin, "\n", "\n" ) - os.write(edgesOutputDir / "EdgeTypes.scala", edgeTypesSource) + if (edgeTypes.nonEmpty) { + os.write(edgesOutputDir / "EdgeTypes.scala", edgeTypesSource) + } nodeTypes.iterator.zipWithIndex.foreach { case (nodeType, kind) => val newExtendz = newExtendzMap(nodeType) @@ -697,13 +701,13 @@ class DomainClassesGenerator(schema: Schema) { |object GraphSchema extends flatgraph.Schema { | private val nodeLabels = IndexedSeq($nodeLabelsSrc) | val nodeKindByLabel = nodeLabels.zipWithIndex.toMap - | val edgeLabels = Array(${edgeTypes.map { e => s""""${e.name}"""" }.mkString(", ")}) + | val edgeLabels: Array[String] = Array(${edgeTypes.map { e => s""""${e.name}"""" }.mkString(", ")}) | val edgeKindByLabel = edgeLabels.zipWithIndex.toMap | val edgePropertyAllocators: Array[Int => Array[?]] = Array($edgePropertyAllocatorsSrc) | val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = Array($nodeFactoriesSrc) | val edgeFactories: Array[(flatgraph.GNode, flatgraph.GNode, Int, Any) => flatgraph.Edge] = Array($edgeFactoriesSrc) | val nodePropertyAllocators: Array[Int => Array[?]] = Array($nodePropertyAllocatorsSrc) - | val normalNodePropertyNames = Array(${relevantProperties.map { p => s""""${p.name}"""" }.mkString(", ")}) + | val normalNodePropertyNames: Array[String] = Array(${relevantProperties.map { p => s""""${p.name}"""" }.mkString(", ")}) | val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap$nodePropertyByLabelSrc | val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = ${nodePropertyDescriptorsSource.mkString("\n")} | ${newNodePropertyHelpers} @@ -1392,24 +1396,26 @@ class DomainClassesGenerator(schema: Schema) { /** Generate accessors for all edge types on all Traversals for each node type. Analogous to the steps directly on StoredNode */ - def generateRootTypesTraversals(schema: Schema): String = { - val neighborSteps = schema.edgeTypes - .map { edgeType => - val stepNameBase = s"_${camelCase(edgeType.name)}" - s""" - |final def ${stepNameBase}Out: Iterator[StoredNode] = iterator.flatMap(_.${stepNameBase}Out) - |final def ${stepNameBase}In: Iterator[StoredNode] = iterator.flatMap(_.${stepNameBase}In) - |""".stripMargin - } - .mkString("\n") + def generateRootTypesTraversals(schema: Schema): Option[String] = { + val neighborSteps = schema.edgeTypes.map { edgeType => + val stepNameBase = s"_${camelCase(edgeType.name)}" + s""" + |final def ${stepNameBase}Out: Iterator[StoredNode] = iterator.flatMap(_.${stepNameBase}Out) + |final def ${stepNameBase}In: Iterator[StoredNode] = iterator.flatMap(_.${stepNameBase}In) + |""".stripMargin + } - s""" - |package ${schema.basePackage}.nodes - | - |extension (iterator: Iterator[StoredNode]) { - | $neighborSteps - |} - |""".stripMargin + if (neighborSteps.isEmpty) { + None + } else { + Some(s""" + |package ${schema.basePackage}.nodes + | + |extension (iterator: Iterator[StoredNode]) { + | ${neighborSteps.mkString("\n")} + |} + |""".stripMargin) + } } def generatePropertyTraversals(property: Property[?], propertyId: Int): String = { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/codepropertygraphminified/GraphSchema.scala b/test-schemas-domain-classes/src/main/scala/testdomains/codepropertygraphminified/GraphSchema.scala index 82898753..34438a37 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/codepropertygraphminified/GraphSchema.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/codepropertygraphminified/GraphSchema.scala @@ -5,7 +5,7 @@ import flatgraph.FormalQtyType object GraphSchema extends flatgraph.Schema { private val nodeLabels = IndexedSeq("CALL", "METHOD") val nodeKindByLabel = nodeLabels.zipWithIndex.toMap - val edgeLabels = Array("CALL") + val edgeLabels: Array[String] = Array("CALL") val edgeKindByLabel = edgeLabels.zipWithIndex.toMap val edgePropertyAllocators: Array[Int => Array[?]] = Array(size => null) val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = @@ -14,8 +14,8 @@ object GraphSchema extends flatgraph.Schema { Array((s, d, subseq, p) => new edges.Call(s, d, subseq, p)) val nodePropertyAllocators: Array[Int => Array[?]] = Array(size => new Array[String](size), size => new Array[String](size), size => new Array[Int](size)) - val normalNodePropertyNames = Array("DISPATCH_TYPE", "NAME", "ORDER") - val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap + val normalNodePropertyNames: Array[String] = Array("DISPATCH_TYPE", "NAME", "ORDER") + val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = { val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](12) for (idx <- Range(0, 12)) { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/EdgeTypes.java b/test-schemas-domain-classes/src/main/scala/testdomains/empty/EdgeTypes.java new file mode 100644 index 00000000..f5066d47 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/EdgeTypes.java @@ -0,0 +1,13 @@ +package testdomains.empty; + +import java.util.HashSet; +import java.util.Set; + +public class EdgeTypes { + + +public static Set ALL = new HashSet() {{ + +}}; + +} \ No newline at end of file diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/Empty.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/Empty.scala new file mode 100644 index 00000000..0d53cb05 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/Empty.scala @@ -0,0 +1,71 @@ +package testdomains.empty +import flatgraph.{DiffGraphApplier, DiffGraphBuilder} +import flatgraph.help.DocSearchPackages +import flatgraph.help.Table.AvailableWidthProvider +import testdomains.empty.language.* + +object Empty { + 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: Empty = new Empty(new flatgraph.Graph(GraphSchema)) + + def from(initialElements: DiffGraphBuilder => DiffGraphBuilder): Empty = { + val graph = new flatgraph.Graph(GraphSchema) + DiffGraphApplier.applyDiff(graph, initialElements(new DiffGraphBuilder(GraphSchema))) + new Empty(graph) + } + + /** 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): Empty = { + val graph = flatgraph.Graph.withStorage(GraphSchema, storagePath, persistOnClose) + new Empty(graph) + } + + def newDiffGraphBuilder: DiffGraphBuilder = new DiffGraphBuilder(GraphSchema) +} + +class Empty(private val _graph: flatgraph.Graph = new flatgraph.Graph(GraphSchema)) extends AutoCloseable { + def graph: flatgraph.Graph = _graph + + def help(implicit searchPackageNames: DocSearchPackages, availableWidthProvider: AvailableWidthProvider) = + Empty.help + def helpVerbose(implicit searchPackageNames: DocSearchPackages, availableWidthProvider: AvailableWidthProvider) = + Empty.helpVerbose + + override def close(): Unit = + _graph.close() + + override def toString(): String = + String.format("Empty[%s]", graph) +} + +@flatgraph.help.TraversalSource +class EmptyNodeStarters(val wrappedEmpty: Empty) { + + @flatgraph.help.Doc(info = "all nodes") + def all: Iterator[nodes.StoredNode] = wrappedEmpty.graph.allNodes.asInstanceOf[Iterator[nodes.StoredNode]] + + def id(nodeId: Long): Iterator[nodes.StoredNode] = + Option(wrappedEmpty.graph.node(nodeId)).iterator.asInstanceOf[Iterator[nodes.StoredNode]] + + def ids(nodeIds: Long*): Iterator[nodes.StoredNode] = nodeIds.iterator.flatMap(id) + +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/GraphSchema.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/GraphSchema.scala new file mode 100644 index 00000000..e35f280f --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/GraphSchema.scala @@ -0,0 +1,71 @@ +package testdomains.empty + +import flatgraph.FormalQtyType + +object GraphSchema extends flatgraph.Schema { + private val nodeLabels = IndexedSeq() + val nodeKindByLabel = nodeLabels.zipWithIndex.toMap + val edgeLabels: Array[String] = Array() + val edgeKindByLabel = edgeLabels.zipWithIndex.toMap + val edgePropertyAllocators: Array[Int => Array[?]] = Array() + val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = Array() + val edgeFactories: Array[(flatgraph.GNode, flatgraph.GNode, Int, Any) => flatgraph.Edge] = Array() + val nodePropertyAllocators: Array[Int => Array[?]] = Array() + val normalNodePropertyNames: Array[String] = Array() + val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap + val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = { + val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](0) + for (idx <- Range(0, 0)) { + nodePropertyDescriptors(idx) = + if ((idx & 1) == 0) FormalQtyType.NothingType + else FormalQtyType.QtyNone + } + + nodePropertyDescriptors + } + private val newNodeInsertionHelpers: Array[flatgraph.NewNodePropertyInsertionHelper] = { + val _newNodeInserters = new Array[flatgraph.NewNodePropertyInsertionHelper](0) + + _newNodeInserters + } + override def getNumberOfNodeKinds: Int = 0 + override def getNumberOfEdgeKinds: Int = 0 + 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 _ => Set.empty + } + } + override def getEdgePropertyName(label: String): Option[String] = { + label match { + + case _ => None + } + } + + override def getPropertyLabel(nodeKind: Int, propertyKind: Int): String = { + if (propertyKind < 0) normalNodePropertyNames(propertyKind) + else null + } + + override def getPropertyKindByName(label: String): Int = nodePropertyByLabel.getOrElse(label, flatgraph.Schema.UndefinedKind) + override def getNumberOfPropertyKinds: Int = 0 + 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] + + override def getNewNodePropertyInserter(nodeKind: Int, propertyKind: Int): flatgraph.NewNodePropertyInsertionHelper = + newNodeInsertionHelpers(propertyOffsetArrayIndex(nodeKind, propertyKind)) +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/NodeTypes.java b/test-schemas-domain-classes/src/main/scala/testdomains/empty/NodeTypes.java new file mode 100644 index 00000000..111b2372 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/NodeTypes.java @@ -0,0 +1,13 @@ +package testdomains.empty; + +import java.util.HashSet; +import java.util.Set; + +public class NodeTypes { + + +public static Set ALL = new HashSet() {{ + +}}; + +} \ No newline at end of file diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/Properties.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/Properties.scala new file mode 100644 index 00000000..ae3eea52 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/Properties.scala @@ -0,0 +1,3 @@ +package testdomains.empty + +object Properties {} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/PropertyErrorRegister.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/PropertyErrorRegister.scala new file mode 100644 index 00000000..c67decbe --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/PropertyErrorRegister.scala @@ -0,0 +1,13 @@ +package testdomains.empty + +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)) + } + } +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/PropertyNames.java b/test-schemas-domain-classes/src/main/scala/testdomains/empty/PropertyNames.java new file mode 100644 index 00000000..5db82e36 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/PropertyNames.java @@ -0,0 +1,13 @@ +package testdomains.empty; + +import java.util.HashSet; +import java.util.Set; + +public class PropertyNames { + + +public static Set ALL = new HashSet() {{ + +}}; + +} \ No newline at end of file diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/accessors/Accessors.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/accessors/Accessors.scala new file mode 100644 index 00000000..35edf87d --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/accessors/Accessors.scala @@ -0,0 +1,21 @@ +package testdomains.empty.accessors +import testdomains.empty.nodes +import scala.collection.immutable.IndexedSeq + +/** not supposed to be used directly by users, hence the `bootstrap` in the name */ +object languagebootstrap extends ConcreteStoredConversions + +object Accessors { + /* accessors for concrete stored nodes start */ + + /* accessors for concrete stored nodes end */ + + /* accessors for base nodes start */ + + /* accessors for base nodes end */ +} + +import Accessors.* +trait ConcreteStoredConversions extends ConcreteBaseConversions {} + +trait ConcreteBaseConversions {} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/language.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/language.scala new file mode 100644 index 00000000..9048e03f --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/language.scala @@ -0,0 +1,14 @@ +package testdomains.empty + +/** 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.help.language + with flatgraph.Implicits { + implicit def toGeneratedNodeStarters(domain: Empty): EmptyNodeStarters = EmptyNodeStarters(domain) +} + +object language extends language diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/neighboraccessors/package.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/neighboraccessors/package.scala new file mode 100644 index 00000000..f81c6100 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/neighboraccessors/package.scala @@ -0,0 +1,10 @@ +package testdomains.empty + +import flatgraph.traversal.language.* +import testdomains.empty.nodes + +package object neighboraccessors { + object Lang extends Conversions + + trait Conversions {} +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/nodes/BaseTypes.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/nodes/BaseTypes.scala new file mode 100644 index 00000000..6f8c93d2 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/nodes/BaseTypes.scala @@ -0,0 +1 @@ +package testdomains.empty.nodes diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/nodes/RootTypes.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/nodes/RootTypes.scala new file mode 100644 index 00000000..4be1bb2a --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/nodes/RootTypes.scala @@ -0,0 +1,27 @@ +package testdomains.empty.nodes + +trait StaticType[+T] + +trait AbstractNode extends flatgraph.DNodeOrNode with StaticType[AnyRef] with Product { + def label: String + + def properties: Map[String, Any] = { + scala.jdk.CollectionConverters.MapHasAsScala(propertiesMap).asScala.toMap + } + + /** TODO deprecate and phase out */ + def propertiesMap: java.util.Map[String, Any] +} + +abstract class StoredNode(graph_4762: flatgraph.Graph, kind_4762: Short, seq_4762: Int) + extends flatgraph.GNode(graph_4762, kind_4762, seq_4762) + with AbstractNode {} + +abstract class NewNode(val nodeKind: Short) extends AbstractNode with flatgraph.DNode { + private /* volatile? */ var _storedRef: StoredNodeType = null.asInstanceOf[StoredNodeType] + override def storedRef: Option[StoredNodeType] = Option(this._storedRef) + override def storedRef_=(stored: Option[flatgraph.GNode]): Unit = this._storedRef = stored.orNull.asInstanceOf[StoredNodeType] + def isValidOutNeighbor(edgeLabel: String, n: NewNode): Boolean + def isValidInNeighbor(edgeLabel: String, n: NewNode): Boolean + def copy: this.type +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/package.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/package.scala new file mode 100644 index 00000000..96ef93e4 --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/package.scala @@ -0,0 +1,12 @@ +package testdomains + +package object empty { + // some type aliases so that the domain-specific code can avoid referencing the `flatgraph` namespace + type DiffGraphBuilder = _root_.flatgraph.DiffGraphBuilder + + object help { + type Doc = _root_.flatgraph.help.Doc + type Traversal = _root_.flatgraph.help.Traversal + type TraversalSource = _root_.flatgraph.help.TraversalSource + } +} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/empty/traversals/package.scala b/test-schemas-domain-classes/src/main/scala/testdomains/empty/traversals/package.scala new file mode 100644 index 00000000..cafdbb3d --- /dev/null +++ b/test-schemas-domain-classes/src/main/scala/testdomains/empty/traversals/package.scala @@ -0,0 +1,13 @@ +package testdomains.empty + +import testdomains.empty.nodes + +package object traversals { + + /** not supposed to be used directly by users, hence the `bootstrap` in the name */ + object languagebootstrap extends ConcreteStoredConversions + + trait ConcreteStoredConversions extends ConcreteBaseConversions {} + + trait ConcreteBaseConversions {} +} 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 980af3df..e7aa47b8 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 @@ -5,7 +5,7 @@ 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 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 */ ) val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = @@ -21,8 +21,9 @@ object GraphSchema extends flatgraph.Schema { 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 normalNodePropertyNames: Array[String] = + 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)) { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GraphSchema.scala b/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GraphSchema.scala index c5105c60..8ac82609 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GraphSchema.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GraphSchema.scala @@ -3,10 +3,10 @@ package testdomains.gratefuldead import flatgraph.FormalQtyType object GraphSchema extends flatgraph.Schema { - private val nodeLabels = IndexedSeq("artist", "song") - val nodeKindByLabel = nodeLabels.zipWithIndex.toMap - val edgeLabels = Array("followedBy", "sungBy", "writtenBy") - val edgeKindByLabel = edgeLabels.zipWithIndex.toMap + private val nodeLabels = IndexedSeq("artist", "song") + val nodeKindByLabel = nodeLabels.zipWithIndex.toMap + val edgeLabels: Array[String] = Array("followedBy", "sungBy", "writtenBy") + val edgeKindByLabel = edgeLabels.zipWithIndex.toMap val edgePropertyAllocators: Array[Int => Array[?]] = Array(size => Array.fill(size)(0: Int) /* label = followedBy, id = 0 */, size => null, size => null) val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = @@ -18,8 +18,8 @@ object GraphSchema extends flatgraph.Schema { ) val nodePropertyAllocators: Array[Int => Array[?]] = Array(size => new Array[String](size), size => new Array[Int](size), size => new Array[String](size)) - val normalNodePropertyNames = Array("name", "performances", "songType") - val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap + val normalNodePropertyNames: Array[String] = Array("name", "performances", "songType") + val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = { val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](12) for (idx <- Range(0, 12)) { diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/GraphSchema.scala b/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/GraphSchema.scala index 89b61c11..2c472206 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/GraphSchema.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/GraphSchema.scala @@ -5,7 +5,7 @@ import flatgraph.FormalQtyType object GraphSchema extends flatgraph.Schema { private val nodeLabels = IndexedSeq("node_x", "node_y") val nodeKindByLabel = nodeLabels.zipWithIndex.toMap - val edgeLabels = Array("connected_to") + val edgeLabels: Array[String] = Array("connected_to") val edgeKindByLabel = edgeLabels.zipWithIndex.toMap val edgePropertyAllocators: Array[Int => Array[?]] = Array(size => null) val nodeFactories: Array[(flatgraph.Graph, Int) => nodes.StoredNode] = @@ -13,7 +13,7 @@ object GraphSchema extends flatgraph.Schema { 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[String](size)) - val normalNodePropertyNames = Array("name") + val normalNodePropertyNames: Array[String] = Array("name") val nodePropertyByLabel = normalNodePropertyNames.zipWithIndex.toMap val nodePropertyDescriptors: Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType] = { val nodePropertyDescriptors = new Array[FormalQtyType.FormalQuantity | FormalQtyType.FormalType](4) diff --git a/test-schemas/src/main/scala/flatgraph/testdomains/Empty.scala b/test-schemas/src/main/scala/flatgraph/testdomains/Empty.scala new file mode 100644 index 00000000..4f8fbdb3 --- /dev/null +++ b/test-schemas/src/main/scala/flatgraph/testdomains/Empty.scala @@ -0,0 +1,13 @@ +package flatgraph.testdomains + +import flatgraph.schema.* + +/** Just to ensure that users can start with a blank page without any compiler errors or warnings in the generated domain classes + */ +object Empty { + val schema: Schema = { + val builder = new SchemaBuilder(domainShortName = "Empty", basePackage = "testdomains.empty") + + builder.build + } +} diff --git a/test-schemas/src/main/scala/flatgraph/testdomains/GenerateDomainClasses.scala b/test-schemas/src/main/scala/flatgraph/testdomains/GenerateDomainClasses.scala index f1c9a902..924e296e 100644 --- a/test-schemas/src/main/scala/flatgraph/testdomains/GenerateDomainClasses.scala +++ b/test-schemas/src/main/scala/flatgraph/testdomains/GenerateDomainClasses.scala @@ -6,7 +6,7 @@ object GenerateDomainClasses { def main(args: Array[String]): Unit = { val outputDir = "test-schemas-domain-classes/src/main/scala" - Seq(GratefulDead.schema, Generic.schema, Hierarchical.schema, CodePropertyGraphMinified.schema).foreach { schema => + Seq(GratefulDead.schema, Generic.schema, Hierarchical.schema, CodePropertyGraphMinified.schema, Empty.schema).foreach { schema => new DomainClassesGenerator(schema).run(java.nio.file.Paths.get(outputDir)) // this also works...