diff --git a/core/src/main/scala/flatgraph/Graph.scala b/core/src/main/scala/flatgraph/Graph.scala index 4d98026f..54326330 100644 --- a/core/src/main/scala/flatgraph/Graph.scala +++ b/core/src/main/scala/flatgraph/Graph.scala @@ -74,8 +74,9 @@ class Graph(val schema: Schema, val storagePathMaybe: Option[Path] = None) exten def node(id: Long): GNode = node(GNode.extractKind(id), GNode.extractSeq(id)) - /** Lookup node by kind and seq - note: this may return null or throw an exception if the referenced node doesn't exist */ + /** Lookup node by kind and seq - note: this may return null if the referenced node doesn't exist */ def node(kind: Int, seq: Int): GNode = { + if (kind < 0 || kind >= nodesArray.length || seq < 0 || seq >= nodesArray(kind).length) return null val node = nodesArray(kind)(seq) if (node._isDeleted) null else node 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 2719413b..2a56738f 100644 --- a/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala +++ b/domain-classes-generator/src/main/scala/flatgraph/codegen/DomainClassesGenerator.scala @@ -1016,6 +1016,10 @@ class DomainClassesGenerator(schema: Schema) { | | @flatgraph.help.Doc(info = "all nodes") | def all: Iterator[nodes.StoredNode] = wrapped$domainShortName.graph.allNodes.asInstanceOf[Iterator[nodes.StoredNode]] + | + | def id(nodeId: Long):Iterator[nodes.StoredNode] = Option(wrapped$domainShortName.graph.node(nodeId)).iterator.asInstanceOf[Iterator[nodes.StoredNode]] + | + | def ids(nodeIds: Long*):Iterator[nodes.StoredNode] = nodeIds.iterator.flatMap(id) | |${starters.mkString("\n\n")} |} diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/generic/GenericDomain.scala b/test-schemas-domain-classes/src/main/scala/testdomains/generic/GenericDomain.scala index 82863378..8f9dbcf5 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/generic/GenericDomain.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/generic/GenericDomain.scala @@ -63,6 +63,11 @@ class GenericDomainNodeStarters(val wrappedGenericDomain: GenericDomain) { @flatgraph.help.Doc(info = "all nodes") def all: Iterator[nodes.StoredNode] = wrappedGenericDomain.graph.allNodes.asInstanceOf[Iterator[nodes.StoredNode]] + def id(nodeId: Long): Iterator[nodes.StoredNode] = + Option(wrappedGenericDomain.graph.node(nodeId)).iterator.asInstanceOf[Iterator[nodes.StoredNode]] + + def ids(nodeIds: Long*): Iterator[nodes.StoredNode] = nodeIds.iterator.flatMap(id) + /** */ @flatgraph.help.Doc(info = """""") def nodeA: Iterator[nodes.NodeA] = wrappedGenericDomain.graph._nodes(0).asInstanceOf[Iterator[nodes.NodeA]] diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GratefulDead.scala b/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GratefulDead.scala index e843d874..8a7215b6 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GratefulDead.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/gratefuldead/GratefulDead.scala @@ -63,6 +63,11 @@ class GratefulDeadNodeStarters(val wrappedGratefulDead: GratefulDead) { @flatgraph.help.Doc(info = "all nodes") def all: Iterator[nodes.StoredNode] = wrappedGratefulDead.graph.allNodes.asInstanceOf[Iterator[nodes.StoredNode]] + def id(nodeId: Long): Iterator[nodes.StoredNode] = + Option(wrappedGratefulDead.graph.node(nodeId)).iterator.asInstanceOf[Iterator[nodes.StoredNode]] + + def ids(nodeIds: Long*): Iterator[nodes.StoredNode] = nodeIds.iterator.flatMap(id) + /** */ @flatgraph.help.Doc(info = """""") def artist: Iterator[nodes.Artist] = wrappedGratefulDead.graph._nodes(0).asInstanceOf[Iterator[nodes.Artist]] diff --git a/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/Hierarchical.scala b/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/Hierarchical.scala index 1e2f19ef..1632eaa5 100644 --- a/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/Hierarchical.scala +++ b/test-schemas-domain-classes/src/main/scala/testdomains/hierarchical/Hierarchical.scala @@ -63,6 +63,11 @@ class HierarchicalNodeStarters(val wrappedHierarchical: Hierarchical) { @flatgraph.help.Doc(info = "all nodes") def all: Iterator[nodes.StoredNode] = wrappedHierarchical.graph.allNodes.asInstanceOf[Iterator[nodes.StoredNode]] + def id(nodeId: Long): Iterator[nodes.StoredNode] = + Option(wrappedHierarchical.graph.node(nodeId)).iterator.asInstanceOf[Iterator[nodes.StoredNode]] + + def ids(nodeIds: Long*): Iterator[nodes.StoredNode] = nodeIds.iterator.flatMap(id) + /** */ @flatgraph.help.Doc(info = """""") def nodeX: Iterator[nodes.NodeX] = wrappedHierarchical.graph._nodes(0).asInstanceOf[Iterator[nodes.NodeX]] diff --git a/tests/src/test/scala/flatgraph/traversal/GratefulDeadTests.scala b/tests/src/test/scala/flatgraph/traversal/GratefulDeadTests.scala index f9465e1e..a9143631 100644 --- a/tests/src/test/scala/flatgraph/traversal/GratefulDeadTests.scala +++ b/tests/src/test/scala/flatgraph/traversal/GratefulDeadTests.scala @@ -27,6 +27,8 @@ class GratefulDeadTests extends AnyWordSpec { gratefulDead.artist.name.sorted shouldBe List("Bo_Diddley", "Garcia") gratefulDead.artist.name("Garcia").sang.name.l shouldBe List("HEY BO DIDDLEY") gratefulDead.song.writtenBy.name.l shouldBe List("Bo_Diddley") + gratefulDead.ids(0L, 1L << 32).l shouldBe List(boDiddley.storedRef.get, heyBoDiddley.storedRef.get) + gratefulDead.id(2L).l shouldBe List.empty } lazy val gratefulDead = {