diff --git a/core/src/main/scala/latis/catalog/Catalog.scala b/core/src/main/scala/latis/catalog/Catalog.scala index 0b93f4f7..726405eb 100644 --- a/core/src/main/scala/latis/catalog/Catalog.scala +++ b/core/src/main/scala/latis/catalog/Catalog.scala @@ -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)) } /** @@ -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 } /** @@ -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. diff --git a/core/src/test/scala/latis/catalog/CatalogSuite.scala b/core/src/test/scala/latis/catalog/CatalogSuite.scala index 33f36ea0..84ef01e8 100644 --- a/core/src/test/scala/latis/catalog/CatalogSuite.scala +++ b/core/src/test/scala/latis/catalog/CatalogSuite.scala @@ -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 } @@ -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") { diff --git a/dap2-service/src/main/scala/latis/service/dap2/Dap2Service.scala b/dap2-service/src/main/scala/latis/service/dap2/Dap2Service.scala index 9f832ec9..64f8ba0c 100644 --- a/dap2-service/src/main/scala/latis/service/dap2/Dap2Service.scala +++ b/dap2-service/src/main/scala/latis/service/dap2/Dap2Service.scala @@ -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") } diff --git a/dap2-service/src/main/scala/latis/service/dap2/HtmlCatalogEncoder.scala b/dap2-service/src/main/scala/latis/service/dap2/HtmlCatalogEncoder.scala index 9c07a05f..9686b87d 100644 --- a/dap2-service/src/main/scala/latis/service/dap2/HtmlCatalogEncoder.scala +++ b/dap2-service/src/main/scala/latis/service/dap2/HtmlCatalogEncoder.scala @@ -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 diff --git a/dap2-service/src/main/scala/latis/service/dap2/JsonCatalogEncoder.scala b/dap2-service/src/main/scala/latis/service/dap2/JsonCatalogEncoder.scala index d437be6d..c6fe7f51 100644 --- a/dap2-service/src/main/scala/latis/service/dap2/JsonCatalogEncoder.scala +++ b/dap2-service/src/main/scala/latis/service/dap2/JsonCatalogEncoder.scala @@ -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(