Skip to content

Commit

Permalink
Put subcatalogs in IO
Browse files Browse the repository at this point in the history
This commit changes the type of a catalog's subcatalogs from a map to
an IO computation that produces a map to allow more flexibility in how
subcatalogs are defined.
  • Loading branch information
lindholc committed Nov 12, 2024
1 parent 870b159 commit d2fd3f7
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 16 deletions.
24 changes: 14 additions & 10 deletions core/src/main/scala/latis/catalog/Catalog.scala
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ trait Catalog { self =>
def datasets: Stream[IO, Dataset]

/** This catalog's subcatalogs. */
def catalogs: Map[Identifier, Catalog] = Map.empty
def catalogs: IO[Map[Identifier, Catalog]] = IO.pure(Map.empty)

/** Adds a single subcatalog to this catalog. */
def addCatalog(id: Identifier, catalog: Catalog): Catalog = new Catalog {
override val datasets: Stream[IO, Dataset] = self.datasets

override val catalogs: Map[Identifier, Catalog] =
self.catalogs + (id -> catalog)
override val catalogs: IO[Map[Identifier, Catalog]] =
self.catalogs.map(_ + (id -> catalog))
}

/**
Expand All @@ -51,17 +51,20 @@ trait Catalog { self =>
def filter(p: Dataset => Boolean): Catalog = new Catalog {
override val datasets: Stream[IO, Dataset] = self.datasets.filter(p)

override val catalogs: Map[Identifier, Catalog] = self.catalogs.map {
case (id, cat) => id -> cat.filter(p)
override val catalogs: IO[Map[Identifier, Catalog]] = self.catalogs.map {
_.map {
case (id, cat) => id -> cat.filter(p)
}
}
}

/** Returns a subcatalog given its name. */
def findCatalog(name: Identifier): Option[Catalog] =
def findCatalog(name: Identifier): IO[Option[Catalog]] =
splitId(name) match {
case (Nil, id) => catalogs.get(id)
case (Nil, id) => catalogs.map(_.get(id))
case (q :: qs, id) =>
catalogs.get(q).flatMap(_.findCatalog(concatId(qs, id)))
OptionT(catalogs.map(_.get(q)))
.flatMapF(_.findCatalog(concatId(qs, id))).value
}

/**
Expand All @@ -72,14 +75,15 @@ trait Catalog { self =>
case (Nil, id) =>
datasets.find(_.id.forall(_ == id)).compile.last
case (q :: qs, id) =>
catalogs.get(q).flatTraverse(_.findDataset(concatId(qs, id)))
OptionT(catalogs.map(_.get(q)))
.flatMapF(_.findDataset(concatId(qs, id))).value
}

/** Sets this catalog's subcatalogs. */
def withCatalogs(scs: (Identifier, Catalog)*): Catalog = new Catalog {
override val datasets: Stream[IO,Dataset] = self.datasets

override val catalogs: Map[Identifier, Catalog] = scs.toMap
override val catalogs: IO[Map[Identifier, Catalog]] = scs.toMap.pure[IO]
}

// Constructs a qualified ID.
Expand Down
9 changes: 6 additions & 3 deletions core/src/test/scala/latis/catalog/CatalogSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,9 @@ class CatalogSuite extends CatsEffectSuite {
// that datasets in this list are unique.
private def listAll(c: Catalog): IO[List[Dataset]] = {
def go(c: Catalog): Stream[IO, Dataset] = {
c.datasets ++ c.catalogs.toList.foldMap { case (_, c) => go(c) }
c.datasets ++ Stream.eval(c.catalogs).flatMap(
sub => Stream.emits(sub.toList)
).flatMap { case (_, c) => go(c) }
}
go(c).compile.toList
}
Expand Down Expand Up @@ -75,8 +77,9 @@ class CatalogSuite extends CatsEffectSuite {
}

test("find catalog in a nested catalog") {
nested.findCatalog(id"b.c")
.fold(fail("Failed to find catalog"))(assertEquals(_, c2))
nested.findCatalog(id"b.c").map(
_.fold(fail("Failed to find catalog"))(assertEquals(_, c2))
)
}

test("find dataset in a nested catalog") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class Dap2Service(catalog: Catalog, operationRegistry: OperationRegistry)
// Dataset path should not end with slash
if (path.endsWithSlash) NotFound(s"Resource not found: $path")
else datasetResponse(ds, ext, query)
case None => catalog.findCatalog(id) match {
case None => catalog.findCatalog(id).flatMap {
case Some(cat) => catalogResponse(cat, headers)
case None => NotFound(s"Resource not found: $path")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ object HtmlCatalogEncoder {

/** Provides a recursive HTML table representation of a Catalog's sub-catalogs */
private[dap2] def subcatalogTable(catalog: Catalog, prefix: String = ""): IO[Text.TypedTag[String]] = {
val catalogs = Stream.emits(catalog.catalogs.toList)
val catalogs = Stream.eval(catalog.catalogs).flatMap(sub => Stream.emits(sub.toList))
catalogs.evalMap { c =>
val id = c._1.asString
val cat = c._2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ object JsonCatalogEncoder {
/** Provides a JSON representation of a Catalog for a dap2 response. */
def encode(catalog: Catalog, id: Option[Identifier] = None): IO[Json] =
for {
cats <- catalog.catalogs.toList.traverse { case (id, cat) => encode(cat, Some(id)) }
subs <- catalog.catalogs
cats <- subs.toList.traverse { case (id, cat) => encode(cat, Some(id)) }
dss <- catalog.datasets.compile.toList.map(dss => dss.map(datasetToJson))
} yield {
val fields = List(
Expand Down

0 comments on commit d2fd3f7

Please sign in to comment.