From 69cae9dc1cceedc8a7e3d4954c626d02740637c9 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Thu, 28 Sep 2023 14:37:25 +0200 Subject: [PATCH 01/14] Migrate SearchConfigHook --- .../CompositeProjectionLifeCycle.scala | 14 ++++++----- .../model/CompositeViewRejection.scala | 3 ++- .../plugins/search/SearchConfigHook.scala | 25 ++++++++++--------- 3 files changed, 23 insertions(+), 19 deletions(-) diff --git a/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala b/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala index f0d4681919..e6d75bb9f2 100644 --- a/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala +++ b/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala @@ -1,14 +1,16 @@ package ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing -import cats.syntax.all._ +import cats.effect.IO +import cats.implicits._ import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration.toMonixBIOOps import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeViewDef.{ActiveViewDef, DeprecatedViewDef} import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewProjection import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.projections.CompositeProjections import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.stream.CompositeGraphStream import ch.epfl.bluebrain.nexus.delta.sourcing.stream.ExecutionStrategy.TransientSingleNode import ch.epfl.bluebrain.nexus.delta.sourcing.stream.{CompiledProjection, PipeChain} -import monix.bio.{IO, Task} +import monix.bio.{Task, IO => BIO} /** * Handle the different life stages of a composite view projection @@ -39,7 +41,7 @@ object CompositeProjectionLifeCycle { * Hook that allows to capture changes to apply before starting the indexing of a composite view */ trait Hook { - def apply(view: ActiveViewDef): Option[Task[Unit]] + def apply(view: ActiveViewDef): Option[IO[Unit]] } /** @@ -96,20 +98,20 @@ object CompositeProjectionLifeCycle { } private def detectHook(view: ActiveViewDef) = { - val initial: Option[Task[Unit]] = None + val initial: Option[IO[Unit]] = None hooks.toList .foldLeft(initial) { case (acc, hook) => (acc ++ hook(view)).reduceOption(_ >> _) } .map { task => - Task.pure(CompiledProjection.fromTask(view.metadata, TransientSingleNode, task)) + Task.pure(CompiledProjection.fromTask(view.metadata, TransientSingleNode, task.toUIO)) } } override def destroyOnIndexingChange(prev: ActiveViewDef, next: CompositeViewDef): Task[Unit] = (prev, next) match { case (prev, next) if prev.ref != next.ref => - IO.terminate(new IllegalArgumentException(s"Different views were provided: '${prev.ref}' and '${next.ref}'")) + BIO.terminate(new IllegalArgumentException(s"Different views were provided: '${prev.ref}' and '${next.ref}'")) case (prev, _: DeprecatedViewDef) => logger.info(s"View '${prev.ref}' has been deprecated, cleaning up the current one.") >> destroyAll(prev) case (prev, nextActive: ActiveViewDef) if prev.indexingRev != nextActive.indexingRev => diff --git a/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/model/CompositeViewRejection.scala b/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/model/CompositeViewRejection.scala index 20930cc620..574a3151ee 100644 --- a/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/model/CompositeViewRejection.scala +++ b/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/model/CompositeViewRejection.scala @@ -24,6 +24,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext.ContextRejection import ch.epfl.bluebrain.nexus.delta.sdk.views.ViewRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.Tag.UserTag +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import io.circe.syntax._ import io.circe.{Encoder, Json, JsonObject} @@ -33,7 +34,7 @@ import io.circe.{Encoder, Json, JsonObject} * @param reason * a descriptive message as to why the rejection occurred */ -sealed abstract class CompositeViewRejection(val reason: String) extends Product with Serializable +sealed abstract class CompositeViewRejection(val reason: String) extends Rejection object CompositeViewRejection { diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala index a6ddae386d..847653b264 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala @@ -1,5 +1,6 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search +import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeProjectionLifeCycle.Hook @@ -10,16 +11,17 @@ import ch.epfl.bluebrain.nexus.delta.plugins.search.model.defaultViewId import ch.epfl.bluebrain.nexus.delta.sdk.Defaults import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject -import monix.bio.{Task, UIO} + +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ final class SearchConfigHook( defaults: Defaults, config: IndexingConfig, - update: (ActiveViewDef, CompositeViewFields) => UIO[Unit] + update: (ActiveViewDef, CompositeViewFields) => IO[Unit] ) extends Hook { - private val defaultSearchViewFields = SearchViewFactory(defaults, config) - override def apply(view: ActiveViewDef): Option[Task[Unit]] = + private val defaultSearchViewFields = SearchViewFactory(defaults, config) + override def apply(view: ActiveViewDef): Option[IO[Unit]] = Option.when(viewIsDefault(view) && configHasChanged(view))(update(view, defaultSearchViewFields)) private def configHasChanged(v: ActiveViewDef): Boolean = !SearchViewFactory.matches(v.value, defaults, config) @@ -29,7 +31,7 @@ final class SearchConfigHook( object SearchConfigHook { - private val logger: Logger = Logger[SearchConfigHook] + private val logger = Logger.cats[SearchConfigHook] def apply(compositeViews: CompositeViews, defaults: Defaults, indexingConfig: IndexingConfig)(implicit baseUri: BaseUri, @@ -43,13 +45,12 @@ object SearchConfigHook { private def update(views: CompositeViews)(implicit subject: Subject, baseUri: BaseUri - ): (ActiveViewDef, CompositeViewFields) => UIO[Unit] = { (viewDef: ActiveViewDef, fields: CompositeViewFields) => - views - .update(viewDef.ref.viewId, viewDef.ref.project, viewDef.rev, fields) - .redeemWith( - e => logger.error(s"Could not update view '${viewDef.ref}'. Reason: '${e.reason}'"), - _ => logger.info(s"Search view '${viewDef.ref}' has been successfully updated.") - ) + ): (ActiveViewDef, CompositeViewFields) => IO[Unit] = { (viewDef: ActiveViewDef, fields: CompositeViewFields) => + toCatsIO( + views.update(viewDef.ref.viewId, viewDef.ref.project, viewDef.rev, fields) + ) + .handleErrorWith(e => logger.error(s"Could not update view '${viewDef.ref}'. Message: '${e.getMessage}'")) + .flatMap(_ => logger.info(s"Search view '${viewDef.ref}' has been successfully updated.")) } } From 0d36ac238142c8c59e59056353e79a633422d813 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Thu, 28 Sep 2023 20:36:53 +0200 Subject: [PATCH 02/14] Migrate Search --- .../CompositeProjectionLifeCycle.scala | 2 +- .../nexus/delta/plugins/search/Search.scala | 34 ++++++++++--------- .../plugins/search/SearchPluginModule.scala | 4 +-- .../delta/plugins/search/SearchRoutes.scala | 10 +++--- .../search/model/SearchRejection.scala | 3 +- .../sdk/directives/ResponseToMarshaller.scala | 5 +++ 6 files changed, 32 insertions(+), 26 deletions(-) diff --git a/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala b/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala index e6d75bb9f2..57e1296406 100644 --- a/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala +++ b/delta/plugins/composite-views/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycle.scala @@ -10,7 +10,7 @@ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.projections.Composit import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.stream.CompositeGraphStream import ch.epfl.bluebrain.nexus.delta.sourcing.stream.ExecutionStrategy.TransientSingleNode import ch.epfl.bluebrain.nexus.delta.sourcing.stream.{CompiledProjection, PipeChain} -import monix.bio.{Task, IO => BIO} +import monix.bio.{IO => BIO, Task} /** * Handle the different life stages of a composite view projection diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala index c63cf9bcd6..58d5cfae05 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala @@ -1,6 +1,7 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.http.scaladsl.model.Uri +import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.projectionIndex @@ -14,7 +15,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.acls.model.AclAddress.{Project => Proje import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import io.circe.{Json, JsonObject} -import monix.bio.{IO, UIO} + +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ trait Search { @@ -24,7 +26,7 @@ trait Search { * @param payload * the query payload */ - def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[SearchRejection, Json] + def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[Json] /** * Queries the underlying search indices for the provided suite that the ''caller'' has access to @@ -34,14 +36,14 @@ trait Search { * @param payload * the query payload */ - def query(suite: Label, payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[SearchRejection, Json] + def query(suite: Label, payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[Json] } object Search { final case class TargetProjection(projection: ElasticSearchProjection, view: CompositeView) - private[search] type ListProjections = () => UIO[Seq[TargetProjection]] + private[search] type ListProjections = () => IO[Seq[TargetProjection]] /** * Constructs a new [[Search]] instance. @@ -58,7 +60,7 @@ object Search { compositeViews .list( Pagination.OnePage, - CompositeViewSearchParams(deprecated = Some(false), filter = v => UIO.pure(v.id == defaultViewId)), + CompositeViewSearchParams(deprecated = Some(false), filter = v => IO.pure(v.id == defaultViewId).toUIO), Ordering.by(_.createdAt) ) .map( @@ -91,27 +93,27 @@ object Search { ) = for { allProjections <- listProjections().map(_.filter(projectionPredicate)) - accessibleIndices <- aclCheck.mapFilter[TargetProjection, String]( - allProjections, - p => ProjectAcl(p.view.project) -> p.projection.permission, - p => projectionIndex(p.projection, p.view.uuid, prefix).value + accessibleIndices <- toCatsIO( + aclCheck.mapFilter[TargetProjection, String]( + allProjections, + p => ProjectAcl(p.view.project) -> p.projection.permission, + p => projectionIndex(p.projection, p.view.uuid, prefix).value + ) ) - results <- client.search(payload, accessibleIndices, qp)().mapError(WrappedElasticSearchClientError) + results <- toCatsIO(client.search(payload, accessibleIndices, qp)().mapError(WrappedElasticSearchClientError)) } yield results - override def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[SearchRejection, Json] = + override def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[Json] = query(_ => true, payload, qp) override def query(suite: Label, payload: JsonObject, qp: Uri.Query)(implicit caller: Caller - ): IO[SearchRejection, Json] = - IO.fromOption( - suites.get(suite), - UnknownSuite(suite) - ).flatMap { projects => + ): IO[Json] = { + IO.fromOption(suites.get(suite))(UnknownSuite(suite)).flatMap { projects => def predicate(p: TargetProjection): Boolean = projects.contains(p.view.project) query(predicate(_), payload, qp) } + } } } diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala index 7a8f0054fb..eef8c77894 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala @@ -15,7 +15,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import distage.ModuleDef import io.circe.syntax.EncoderOps import izumi.distage.model.definition.Id -import monix.execution.Scheduler class SearchPluginModule(priority: Int) extends ModuleDef { @@ -46,10 +45,9 @@ class SearchPluginModule(priority: Int) extends ModuleDef { search: Search, config: SearchConfig, baseUri: BaseUri, - s: Scheduler, cr: RemoteContextResolution @Id("aggregate"), ordering: JsonKeyOrdering - ) => new SearchRoutes(identities, aclCheck, search, config.fields.asJson)(baseUri, s, cr, ordering) + ) => new SearchRoutes(identities, aclCheck, search, config.fields.asJson)(baseUri, cr, ordering) } many[PriorityRoute].add { (route: SearchRoutes) => diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutes.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutes.scala index ca303253d9..7d5e4dcb88 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutes.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutes.scala @@ -2,26 +2,26 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.http.scaladsl.server.Directives.{as, concat, entity, get, pathEndOrSingleSlash, pathPrefix, post} import akka.http.scaladsl.server.Route +import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.routes.ElasticSearchViewsDirectives.extractQueryParams import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.RemoteContextResolution import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck +import ch.epfl.bluebrain.nexus.delta.sdk.ce.DeltaDirectives import ch.epfl.bluebrain.nexus.delta.sdk.circe.CirceUnmarshalling -import ch.epfl.bluebrain.nexus.delta.sdk.directives.{AuthDirectives, DeltaDirectives} +import ch.epfl.bluebrain.nexus.delta.sdk.directives.AuthDirectives import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.RdfMarshalling import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import io.circe.{Json, JsonObject} import kamon.instrumentation.akka.http.TracingDirectives.operationName -import monix.bio.UIO -import monix.execution.Scheduler class SearchRoutes( identities: Identities, aclCheck: AclCheck, search: Search, configFields: Json -)(implicit baseUri: BaseUri, s: Scheduler, cr: RemoteContextResolution, ordering: JsonKeyOrdering) +)(implicit baseUri: BaseUri, cr: RemoteContextResolution, ordering: JsonKeyOrdering) extends AuthDirectives(identities, aclCheck) with CirceUnmarshalling with RdfMarshalling @@ -50,7 +50,7 @@ class SearchRoutes( // Get fields config (pathPrefix("config") & get & pathEndOrSingleSlash) { operationName(s"$prefixSegment/search/config") { - emit(UIO.pure(configFields: Json)) + emit(IO.pure(configFields: Json)) } } ) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchRejection.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchRejection.scala index 1ab82b9d92..029a05e089 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchRejection.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchRejection.scala @@ -9,6 +9,7 @@ import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.encoder.JsonLdEncoder import ch.epfl.bluebrain.nexus.delta.sdk.http.HttpClientError import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.HttpResponseFields import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import io.circe.syntax._ import io.circe.{Encoder, JsonObject} @@ -18,7 +19,7 @@ import io.circe.{Encoder, JsonObject} * @param reason * a descriptive message as to why the rejection occurred */ -sealed abstract class SearchRejection(val reason: String) extends Product with Serializable +sealed abstract class SearchRejection(val reason: String) extends Rejection object SearchRejection { diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/directives/ResponseToMarshaller.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/directives/ResponseToMarshaller.scala index e2cce0cebb..f76cd651bd 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/directives/ResponseToMarshaller.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/directives/ResponseToMarshaller.scala @@ -75,6 +75,11 @@ object ResponseToMarshaller extends RdfMarshalling { )(implicit s: Scheduler, cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToMarshaller = ResponseToMarshaller(io.map(Complete(OK, Seq.empty, _)).attempt) + implicit def ioEntityMarshaller[A: ToEntityMarshaller]( + io: IO[A] + )(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToMarshaller = + ResponseToMarshaller(io.map[UseRight[A]](v => Right(Complete(OK, Seq.empty, v)))) + implicit def ioEntityMarshaller[E: JsonLdEncoder: HttpResponseFields, A: ToEntityMarshaller]( io: IO[Either[E, A]] )(implicit cr: RemoteContextResolution, jo: JsonKeyOrdering): ResponseToMarshaller = { From 3f91580c7c8c13c5adb0734e134e91e9e6772241 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:01:28 +0200 Subject: [PATCH 03/14] Migrate SearchScopeInitialization --- .../plugins/search/SearchPluginModule.scala | 5 +- .../search/SearchScopeInitialization.scala | 38 +++++------ .../sdk/ce/CatsScopeInitialization.scala | 66 +++++++++++++++++++ 3 files changed, 88 insertions(+), 21 deletions(-) create mode 100644 delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala index eef8c77894..05c9780b8a 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala @@ -9,6 +9,7 @@ import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.RemoteContextResolution import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering import ch.epfl.bluebrain.nexus.delta.sdk._ import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck +import ch.epfl.bluebrain.nexus.delta.sdk.ce.CatsScopeInitialization import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri @@ -36,7 +37,9 @@ class SearchPluginModule(priority: Int) extends ModuleDef { new SearchScopeInitialization(views, config.indexing, serviceAccount, config.defaults)(baseUri) } - many[ScopeInitialization].ref[SearchScopeInitialization] + many[ScopeInitialization].add { (s: SearchScopeInitialization) => + CatsScopeInitialization.toBioScope(s) + } make[SearchRoutes].from { ( diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala index dea97cd957..6d6c71238d 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala @@ -1,21 +1,23 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search +import cats.effect.IO +import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.syntax._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewRejection.{ProjectContextRejection, ViewAlreadyExists} import ch.epfl.bluebrain.nexus.delta.plugins.search.model.SearchConfig.IndexingConfig import ch.epfl.bluebrain.nexus.delta.plugins.search.model.defaultViewId -import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError +import ch.epfl.bluebrain.nexus.delta.sdk.Defaults +import ch.epfl.bluebrain.nexus.delta.sdk.ce.CatsScopeInitialization import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError.ScopeInitializationFailed import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project -import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject -import com.typesafe.scalalogging.Logger -import monix.bio.{IO, UIO} final class SearchScopeInitialization( views: CompositeViews, @@ -23,34 +25,30 @@ final class SearchScopeInitialization( serviceAccount: ServiceAccount, defaults: Defaults )(implicit baseUri: BaseUri) - extends ScopeInitialization { + extends CatsScopeInitialization { + + private val logger = Logger.cats[SearchScopeInitialization] - private val logger: Logger = Logger[SearchScopeInitialization] implicit private val serviceAccountSubject: Subject = serviceAccount.subject override def onProjectCreation( project: Project, subject: Identity.Subject - ): IO[ServiceError.ScopeInitializationFailed, Unit] = - views - .create( - defaultViewId, - project.ref, - SearchViewFactory(defaults, config) - ) - .void - .onErrorHandleWith { - case _: ViewAlreadyExists => UIO.unit // nothing to do, view already exits - case _: ProjectContextRejection => UIO.unit // project or org are likely deprecated + ): IO[Unit] = { + toCatsIO(views.create(defaultViewId, project.ref, SearchViewFactory(defaults, config))).void + .handleErrorWith { + case _: ViewAlreadyExists => IO.unit + case _: ProjectContextRejection => IO.unit case rej => val str = - s"Failed to create the search view for project '${project.ref}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + s"Failed to create the search view for project '${project.ref}' due to '${rej.getMessage}'." + IO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) } .named("createSearchView", "search") + } override def onOrganizationCreation( organization: Organization, subject: Identity.Subject - ): IO[ServiceError.ScopeInitializationFailed, Unit] = IO.unit + ): IO[Unit] = IO.unit } diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala new file mode 100644 index 0000000000..73aa1acca6 --- /dev/null +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala @@ -0,0 +1,66 @@ +package ch.epfl.bluebrain.nexus.delta.sdk.ce + +import cats.effect.IO +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration.toMonixBIOOps +import ch.epfl.bluebrain.nexus.delta.sdk.ScopeInitialization +import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError +import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject +import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization +import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project +import monix.bio.{IO => BIO} + +/** + * Lifecycle hook for organization and project initialization. It's meant to be used for plugins to preconfigure an + * organization or project, like for example the creation of a default view or setting the appropriate permissions. + * Implementations should use a `many[ScopeInitialization]` binding such that all implementation are collected during + * the service bootstrapping. + */ +trait CatsScopeInitialization { + + /** + * The method is invoked synchronously during the organization creation for its immediate configuration. + * Additionally, in order to correct failures that may have occurred, this method will also be invoked as an + * opportunity to heal as part of the organization event log replay during the bootstrapping of the service. The + * method is expected to perform necessary checks such that the initialization would not be executed twice. + * + * @param organization + * the organization that was created + * @param subject + * the identity that was recorded for the creation of the organization + */ + def onOrganizationCreation(organization: Organization, subject: Subject): IO[Unit] + + /** + * The method is invoked synchronously during the project creation for immediate configuration of the project. + * Additionally, in order to correct failures that may have occurred, this method will also be invoked as an + * opportunity to heal as part of the project event log replay during the bootstrapping of the service. The method is + * expected to perform necessary checks such that the initialization would not be executed twice. + * + * @param project + * the project that was created + * @param subject + * the identity that was recorded for the creation of the project + */ + def onProjectCreation(project: Project, subject: Subject): IO[Unit] + +} + +object CatsScopeInitialization { + + /** CE Migration helper */ + def toBioScope(catsScope: CatsScopeInitialization): ScopeInitialization = + new ScopeInitialization { + override def onOrganizationCreation( + organization: Organization, + subject: Subject + ): BIO[ServiceError.ScopeInitializationFailed, Unit] = + catsScope.onOrganizationCreation(organization, subject).toBIO + + override def onProjectCreation( + project: Project, + subject: Subject + ): BIO[ServiceError.ScopeInitializationFailed, Unit] = + catsScope.onProjectCreation(project, subject).toBIO + } + +} From c8001df7c349997428e12656f7cad251ef6dbee7 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Thu, 28 Sep 2023 21:09:51 +0200 Subject: [PATCH 04/14] Migrate SearchConfigError --- .../plugins/search/model/SearchConfig.scala | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfig.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfig.scala index 7a0c64b65a..615c31b220 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfig.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfig.scala @@ -1,5 +1,6 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search.model +import cats.effect.IO import cats.syntax.all._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeView.{Interval, RebuildStrategy} import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.TemplateSparqlConstructQuery @@ -13,7 +14,6 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ProjectRef} import com.typesafe.config.Config import io.circe.parser._ import io.circe.{Decoder, JsonObject} -import monix.bio.IO import pureconfig.configurable.genericMapReader import pureconfig.error.CannotConvert import pureconfig.{ConfigReader, ConfigSource} @@ -49,11 +49,11 @@ object SearchConfig { /** * Converts a [[Config]] into an [[SearchConfig]] */ - def load(config: Config): IO[SearchConfigError, SearchConfig] = { + def load(config: Config): IO[SearchConfig] = { val pluginConfig = config.getConfig("plugins.search") def loadSuites = { val suiteSource = ConfigSource.fromConfig(pluginConfig).at("suites") - IO.fromEither(suiteSource.load[Suites]).mapError(InvalidSuites) + IO.fromEither(suiteSource.load[Suites].leftMap(InvalidSuites)) } for { fields <- loadOption(pluginConfig, "fields", loadExternalConfig[JsonObject]) @@ -80,12 +80,12 @@ object SearchConfig { ) } - private def loadOption[A](config: Config, path: String, io: String => IO[SearchConfigError, A]) = + private def loadOption[A](config: Config, path: String, io: String => IO[A]) = if (config.hasPath(path)) io(config.getString(path)).map(Some(_)) else IO.none - private def loadExternalConfig[A: Decoder](filePath: String): IO[SearchConfigError, A] = + private def loadExternalConfig[A: Decoder](filePath: String): IO[A] = for { content <- IO.fromEither( Try(Files.readString(Path.of(filePath))).toEither.leftMap(LoadingFileError(filePath, _)) @@ -93,7 +93,7 @@ object SearchConfig { json <- IO.fromEither(decode[A](content).leftMap { e => InvalidJsonError(filePath, e.getMessage) }) } yield json - private def loadSparqlQuery(filePath: String): IO[SearchConfigError, SparqlConstructQuery] = + private def loadSparqlQuery(filePath: String): IO[SparqlConstructQuery] = for { content <- IO.fromEither( Try(Files.readString(Path.of(filePath))).toEither.leftMap(LoadingFileError(filePath, _)) @@ -103,7 +103,7 @@ object SearchConfig { }) } yield json - private def loadDefaults(config: Config): IO[SearchConfigError, Defaults] = + private def loadDefaults(config: Config): IO[Defaults] = IO.fromEither( Try( ConfigSource.fromConfig(config).at("defaults").loadOrThrow[Defaults] @@ -116,7 +116,7 @@ object SearchConfig { * correct finite duration, there will be no rebuild strategy. If both finite durations are present, then the * specified rebuild strategy must be greater or equal to the min rebuild interval. */ - private def loadRebuildStrategy(config: Config): IO[SearchConfigError, Option[RebuildStrategy]] = + private def loadRebuildStrategy(config: Config): IO[Option[RebuildStrategy]] = ( readFiniteDuration(config, "indexing.rebuild-strategy"), readFiniteDuration(config, "indexing.min-interval-rebuild") From ea43435b1023372798a05d7f047d74a713c64cb4 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Thu, 28 Sep 2023 22:02:16 +0200 Subject: [PATCH 05/14] Migrate search tests --- .../migration/MigrateEffectSyntax.scala | 5 +++- .../CompositeProjectionLifeCycleSuite.scala | 9 +++--- .../search/SearchConfigHookSuite.scala | 22 +++++++------- .../plugins/search/SearchRoutesSpec.scala | 7 ++--- .../SearchScopeInitializationSpec.scala | 2 ++ .../search/SearchSparqlQuerySpec.scala | 9 ++++-- .../delta/plugins/search/SearchSpec.scala | 6 ++-- .../search/model/SearchConfigSpec.scala | 3 +- .../testkit/ce/CatsEffectAssertions.scala | 5 ++++ .../nexus/testkit/ce/CatsIOValues.scala | 29 +++++++++++++++++++ 10 files changed, 72 insertions(+), 25 deletions(-) create mode 100644 delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala diff --git a/delta/kernel/src/main/scala/ch/epfl/bluebrain/nexus/delta/kernel/effect/migration/MigrateEffectSyntax.scala b/delta/kernel/src/main/scala/ch/epfl/bluebrain/nexus/delta/kernel/effect/migration/MigrateEffectSyntax.scala index 064a04f1c2..6cb620917b 100644 --- a/delta/kernel/src/main/scala/ch/epfl/bluebrain/nexus/delta/kernel/effect/migration/MigrateEffectSyntax.scala +++ b/delta/kernel/src/main/scala/ch/epfl/bluebrain/nexus/delta/kernel/effect/migration/MigrateEffectSyntax.scala @@ -1,7 +1,8 @@ package ch.epfl.bluebrain.nexus.delta.kernel.effect.migration import cats.effect.IO -import monix.bio.{IO => BIO, UIO} +import cats.~> +import monix.bio.{IO => BIO, Task, UIO} import monix.execution.Scheduler.Implicits.global import scala.reflect.ClassTag @@ -12,6 +13,8 @@ trait MigrateEffectSyntax { implicit def toMonixBIOOps[A](io: IO[A]): CatsIOToBioOps[A] = new CatsIOToBioOps(io) + val taskToIoK: Task ~> IO = λ[Task ~> IO](toCatsIO(_)) + } final class CatsIOToBioOps[A](private val io: IO[A]) extends AnyVal { diff --git a/delta/plugins/composite-views/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycleSuite.scala b/delta/plugins/composite-views/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycleSuite.scala index 0c55502e27..eac8f3d376 100644 --- a/delta/plugins/composite-views/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycleSuite.scala +++ b/delta/plugins/composite-views/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/compositeviews/indexing/CompositeProjectionLifeCycleSuite.scala @@ -2,22 +2,23 @@ package ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing import cats.data.NonEmptyMapImpl import cats.effect.concurrent.Ref +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViewsFixture import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeProjectionLifeCycle.Hook import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeProjectionLifeCycleSuite.DestroyResult +import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeProjectionLifeCycleSuite.DestroyResult._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeViewDef.{ActiveViewDef, DeprecatedViewDef} import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.nxv import ch.epfl.bluebrain.nexus.delta.sdk.views.{IndexingRev, IndexingViewRef, ViewRef} import ch.epfl.bluebrain.nexus.delta.sourcing.config.BatchConfig -import ch.epfl.bluebrain.nexus.delta.sourcing.stream.{CompiledProjection, ExecutionStatus, ExecutionStrategy, Projection, ProjectionMetadata} +import ch.epfl.bluebrain.nexus.delta.sourcing.stream._ import ch.epfl.bluebrain.nexus.testkit.bio.{BioSuite, PatienceConfig} -import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeProjectionLifeCycleSuite.DestroyResult._ import monix.bio.{Task, UIO} import munit.Location -import concurrent.duration._ import java.util.UUID +import scala.concurrent.duration._ class CompositeProjectionLifeCycleSuite extends BioSuite with CompositeViewsFixture { @@ -34,7 +35,7 @@ class CompositeProjectionLifeCycleSuite extends BioSuite with CompositeViewsFixt private def createHook(name: String, test: ViewRef => Boolean, ref: Ref[Task, Set[String]]): Hook = (view: CompositeViewDef.ActiveViewDef) => { Option.when(test(view.ref)) { - ref.update { + ref.mapK(taskToIoK).update { _ + name } } diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala index b7f6e87c79..f06c5696cf 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala @@ -1,6 +1,8 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search +import cats.effect.IO import cats.effect.concurrent.Ref +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeViewDef.ActiveViewDef import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeView import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.{CompositeViewFactory, CompositeViewsFixture} @@ -13,14 +15,13 @@ import ch.epfl.bluebrain.nexus.delta.sdk.Defaults import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ProjectBase import ch.epfl.bluebrain.nexus.delta.sdk.views.ViewRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef -import ch.epfl.bluebrain.nexus.testkit.bio.BioSuite +import ch.epfl.bluebrain.nexus.testkit.ce.CatsEffectSuite import io.circe.{Json, JsonObject} -import monix.bio.{Task, UIO} import java.util.UUID import scala.concurrent.duration._ -class SearchConfigHookSuite extends BioSuite with CompositeViewsFixture { +class SearchConfigHookSuite extends CatsEffectSuite with CompositeViewsFixture { implicit private val projectBase: ProjectBase = ProjectBase.unsafe(nxv.base) @@ -39,8 +40,9 @@ class SearchConfigHookSuite extends BioSuite with CompositeViewsFixture { // Create a search view from the provided config private def searchView(defaults: Defaults, config: IndexingConfig) = { - val fields = SearchViewFactory(defaults, config) - CompositeViewFactory.create(fields).map { value => + val fields = SearchViewFactory(defaults, config) + val compositeViewValue = toCatsIO(CompositeViewFactory.create(fields)) + compositeViewValue.map { value => ActiveViewDef(ViewRef(proj, defaultViewId), UUID.randomUUID(), 1, value) } } @@ -48,22 +50,22 @@ class SearchConfigHookSuite extends BioSuite with CompositeViewsFixture { // Create the hook with a current config private def execSearchHook(view: ActiveViewDef) = Ref - .of[Task, Option[ViewRef]](None) + .of[IO, Option[ViewRef]](None) .map { r => - new SearchConfigHook(defaults, currentConfig, (v, _) => r.set(Some(v.ref)).hideErrors) -> r.get.hideErrors + new SearchConfigHook(defaults, currentConfig, (v, _) => r.set(Some(v.ref))) -> r.get } .flatMap { case (hook, updatedRef) => - hook(view).getOrElse(Task.unit).as(updatedRef) + hook(view).getOrElse(IO.unit).as(updatedRef) } - private def assertViewUpdated(view: UIO[ActiveViewDef]) = + private def assertViewUpdated(view: IO[ActiveViewDef]) = for { v <- view updated <- execSearchHook(v) _ <- updated.assertSome(v.ref) } yield () - private def assertViewNotUpdated(view: UIO[ActiveViewDef]) = + private def assertViewNotUpdated(view: IO[ActiveViewDef]) = for { v <- view updated <- execSearchHook(v) diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutesSpec.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutesSpec.scala index 510b6e80ed..8480e99bd7 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutesSpec.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchRoutesSpec.scala @@ -2,7 +2,7 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.http.scaladsl.model.{StatusCodes, Uri} import akka.http.scaladsl.server.Route -import ch.epfl.bluebrain.nexus.delta.plugins.search.model.SearchRejection +import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclSimpleCheck import ch.epfl.bluebrain.nexus.delta.sdk.identities.IdentitiesDummy import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller @@ -10,18 +10,17 @@ import ch.epfl.bluebrain.nexus.delta.sdk.utils.BaseRouteSpec import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import io.circe.syntax._ import io.circe.{Json, JsonObject} -import monix.bio.IO class SearchRoutesSpec extends BaseRouteSpec { // Dummy implementation of search which just returns the payload private val search = new Search { - override def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[SearchRejection, Json] = + override def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[Json] = IO.pure(payload.asJson) override def query(suite: Label, payload: JsonObject, qp: Uri.Query)(implicit caller: Caller - ): IO[SearchRejection, Json] = + ): IO[Json] = IO.pure(Json.obj(suite.value -> payload.asJson)) } diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitializationSpec.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitializationSpec.scala index 1ab8afcb6b..1cec422b1b 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitializationSpec.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitializationSpec.scala @@ -16,6 +16,7 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Subject, User} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture import ch.epfl.bluebrain.nexus.testkit.IOValues +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import io.circe.JsonObject import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike @@ -25,6 +26,7 @@ class SearchScopeInitializationSpec with AnyWordSpecLike with CompositeViewsFixture with Matchers + with CatsIOValues with IOValues with Fixtures { diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSparqlQuerySpec.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSparqlQuerySpec.scala index 354b7b58e9..6b0252771e 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSparqlQuerySpec.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSparqlQuerySpec.scala @@ -2,6 +2,8 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.actor.ActorSystem import akka.testkit.TestKit +import cats.effect.IO +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.client.BlazegraphClient import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.client.SparqlQueryResponseType.SparqlNTriples import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode @@ -15,9 +17,9 @@ import ch.epfl.bluebrain.nexus.delta.sdk.ConfigFixtures import ch.epfl.bluebrain.nexus.delta.sdk.http.{HttpClient, HttpClientConfig} import ch.epfl.bluebrain.nexus.delta.sdk.syntax._ import ch.epfl.bluebrain.nexus.testkit.blazegraph.BlazegraphDocker +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import ch.epfl.bluebrain.nexus.testkit.{EitherValuable, IOValues, TestHelpers, TestMatchers} import io.circe.Json -import monix.bio.IO import monix.execution.Scheduler import org.scalatest.concurrent.Eventually import org.scalatest.matchers.should.Matchers @@ -39,6 +41,7 @@ class SearchSparqlQuerySpec with Inspectors with TestMatchers with IOValues + with CatsIOValues with BlazegraphDocker { implicit override def patienceConfig: PatienceConfig = PatienceConfig(6.seconds, 10.milliseconds) @@ -57,7 +60,7 @@ class SearchSparqlQuerySpec private def toNTriples(json: Json): NTriples = { for { - expanded <- ExpandedJsonLd(json) + expanded <- toCatsIO(ExpandedJsonLd(json)) graph <- IO.fromEither(expanded.toGraph) ntriples <- IO.fromEither(graph.toNTriples) } yield ntriples @@ -89,7 +92,7 @@ class SearchSparqlQuerySpec val q = contentOf("construct-query.sparql").replaceAll(quote("{resource_id}"), traceId.rdfFormat) val query = SparqlConstructQuery(q).rightValue val compacted = for { - ntriples <- client.query(Set(index), query, SparqlNTriples) + ntriples <- toCatsIO(client.query(Set(index), query, SparqlNTriples)) graph <- IO.fromEither(Graph(ntriples.value.copy(rootNode = traceId))) compacted <- graph.toCompactedJsonLd(ctx) } yield compacted diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSpec.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSpec.scala index cb17174647..6493e7ef77 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSpec.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchSpec.scala @@ -4,6 +4,7 @@ import akka.actor.ActorSystem import akka.http.scaladsl.model.Uri.Query import akka.testkit.TestKit import cats.data.NonEmptyList +import cats.effect.IO import cats.implicits._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeView @@ -31,9 +32,9 @@ import ch.epfl.bluebrain.nexus.delta.sdk.views.IndexingRev import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Group, User} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.testkit._ +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import ch.epfl.bluebrain.nexus.testkit.elasticsearch.ElasticSearchDocker import io.circe.{Json, JsonObject} -import monix.bio.UIO import org.scalatest.concurrent.Eventually import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike @@ -55,6 +56,7 @@ class SearchSpec with Inspectors with ScalaTestElasticSearchClientSetup with ConfigFixtures + with CatsIOValues with IOValues with Eventually with Fixtures @@ -115,7 +117,7 @@ class SearchSpec private val projections = Seq(projectionProj1, projectionProj2) - private val listViews: ListProjections = () => UIO.pure(projections) + private val listViews: ListProjections = () => IO.pure(projections) private val allSuite = Label.unsafe("allSuite") private val proj2Suite = Label.unsafe("proj2Suite") diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfigSpec.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfigSpec.scala index 8031f58012..af6e849c46 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfigSpec.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/model/SearchConfigSpec.scala @@ -5,6 +5,7 @@ import ch.epfl.bluebrain.nexus.delta.plugins.search.model.SearchConfigError.{Inv import ch.epfl.bluebrain.nexus.delta.sdk.Defaults import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ProjectRef} import ch.epfl.bluebrain.nexus.testkit.IOValues +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import com.typesafe.config.ConfigFactory import org.scalatest.Inspectors import org.scalatest.matchers.should.Matchers @@ -12,7 +13,7 @@ import org.scalatest.wordspec.AnyWordSpecLike import scala.concurrent.duration.DurationInt -class SearchConfigSpec extends AnyWordSpecLike with Matchers with Inspectors with IOValues { +class SearchConfigSpec extends AnyWordSpecLike with Matchers with Inspectors with CatsIOValues with IOValues { private def getAbsolutePath(path: String) = getClass.getResource(path).getPath diff --git a/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsEffectAssertions.scala b/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsEffectAssertions.scala index 1df15177bd..46e2291f21 100644 --- a/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsEffectAssertions.scala +++ b/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsEffectAssertions.scala @@ -218,6 +218,11 @@ trait CatsEffectAssertions { self: Assertions => def assert(implicit loc: Location): IO[Unit] = assertIOBoolean(io, "value is not true") } + + implicit class MunitCatsAssertionsOptionOps[A](io: IO[Option[A]])(implicit loc: Location) { + def assertSome(expected: A): IO[Unit] = assertIO(io, Some(expected), s"the Option did not contains $expected") + def assertNone: IO[Unit] = assertIO(io, None, "the Option was not empty") + } } object CatsEffectAssertions extends Assertions with CatsEffectAssertions diff --git a/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala b/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala new file mode 100644 index 0000000000..ea21b5afe9 --- /dev/null +++ b/delta/testkit/src/main/scala/ch/epfl/bluebrain/nexus/testkit/ce/CatsIOValues.scala @@ -0,0 +1,29 @@ +package ch.epfl.bluebrain.nexus.testkit.ce + +import cats.effect.IO +import org.scalactic.source +import org.scalatest.Assertions.fail + +import scala.reflect.ClassTag + +trait CatsIOValues { + + implicit final class CatsIOValuesOps[A](private val io: IO[A]) { + def accepted: A = io.unsafeRunSync() + + def rejectedWith[E](implicit pos: source.Position, EE: ClassTag[E]): E = { + io.attempt.unsafeRunSync() match { + case Left(EE(value)) => value + case Left(value) => + fail( + s"Wrong raised error type caught, expected: '${EE.runtimeClass.getName}', actual: '${value.getClass.getName}'" + ) + case Right(value) => + fail( + s"Expected raising error, but returned successful response with type '${value.getClass.getName}'" + ) + } + } + } + +} From bb7d94d2166e0889400de08c8cbf5492766ec018 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Fri, 29 Sep 2023 08:58:03 +0200 Subject: [PATCH 06/14] Fix wiring --- .../nexus/delta/plugins/search/SearchPluginModule.scala | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala index 05c9780b8a..eae2233535 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala @@ -1,5 +1,6 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.config.CompositeViewsConfig import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.CompositeProjectionLifeCycle @@ -13,13 +14,14 @@ import ch.epfl.bluebrain.nexus.delta.sdk.ce.CatsScopeInitialization import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri +import com.typesafe.config.Config import distage.ModuleDef import io.circe.syntax.EncoderOps import izumi.distage.model.definition.Id class SearchPluginModule(priority: Int) extends ModuleDef { - make[SearchConfig].fromEffect { cfg => SearchConfig.load(cfg) } + make[SearchConfig].fromEffect { (cfg: Config) => SearchConfig.load(cfg).toUIO } make[Search].from { ( From 944573939e035f2c200005ac99c88b1a5cd696b7 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:43:44 +0200 Subject: [PATCH 07/14] Use MigrateEffectSyntax implicitly --- .../nexus/delta/plugins/search/Search.scala | 12 +++++------- .../delta/plugins/search/SearchConfigHook.scala | 5 ++--- .../plugins/search/SearchScopeInitialization.scala | 4 +++- .../delta/plugins/search/SearchConfigHookSuite.scala | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala index 58d5cfae05..899be3a899 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala @@ -93,14 +93,12 @@ object Search { ) = for { allProjections <- listProjections().map(_.filter(projectionPredicate)) - accessibleIndices <- toCatsIO( - aclCheck.mapFilter[TargetProjection, String]( - allProjections, - p => ProjectAcl(p.view.project) -> p.projection.permission, - p => projectionIndex(p.projection, p.view.uuid, prefix).value - ) + accessibleIndices <- aclCheck.mapFilter[TargetProjection, String]( + allProjections, + p => ProjectAcl(p.view.project) -> p.projection.permission, + p => projectionIndex(p.projection, p.view.uuid, prefix).value ) - results <- toCatsIO(client.search(payload, accessibleIndices, qp)().mapError(WrappedElasticSearchClientError)) + results <- client.search(payload, accessibleIndices, qp)().mapError(WrappedElasticSearchClientError) } yield results override def query(payload: JsonObject, qp: Uri.Query)(implicit caller: Caller): IO[Json] = diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala index 847653b264..4b8222decd 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHook.scala @@ -46,9 +46,8 @@ object SearchConfigHook { subject: Subject, baseUri: BaseUri ): (ActiveViewDef, CompositeViewFields) => IO[Unit] = { (viewDef: ActiveViewDef, fields: CompositeViewFields) => - toCatsIO( - views.update(viewDef.ref.viewId, viewDef.ref.project, viewDef.rev, fields) - ) + views + .update(viewDef.ref.viewId, viewDef.ref.project, viewDef.rev, fields) .handleErrorWith(e => logger.error(s"Could not update view '${viewDef.ref}'. Message: '${e.getMessage}'")) .flatMap(_ => logger.info(s"Search view '${viewDef.ref}' has been successfully updated.")) } diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala index 6d6c71238d..88804b74f5 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala @@ -35,7 +35,9 @@ final class SearchScopeInitialization( project: Project, subject: Identity.Subject ): IO[Unit] = { - toCatsIO(views.create(defaultViewId, project.ref, SearchViewFactory(defaults, config))).void + views + .create(defaultViewId, project.ref, SearchViewFactory(defaults, config)) + .void .handleErrorWith { case _: ViewAlreadyExists => IO.unit case _: ProjectContextRejection => IO.unit diff --git a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala index f06c5696cf..8052fc9344 100644 --- a/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala +++ b/delta/plugins/search/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchConfigHookSuite.scala @@ -39,9 +39,9 @@ class SearchConfigHookSuite extends CatsEffectSuite with CompositeViewsFixture { private val proj = ProjectRef.unsafe("org", "proj") // Create a search view from the provided config - private def searchView(defaults: Defaults, config: IndexingConfig) = { + private def searchView(defaults: Defaults, config: IndexingConfig): IO[ActiveViewDef] = { val fields = SearchViewFactory(defaults, config) - val compositeViewValue = toCatsIO(CompositeViewFactory.create(fields)) + val compositeViewValue = CompositeViewFactory.create(fields) compositeViewValue.map { value => ActiveViewDef(ViewRef(proj, defaultViewId), UUID.randomUUID(), 1, value) } From 9fe5da9428326a738fc8c4bc9730ea2b2adb2d4f Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Mon, 2 Oct 2023 09:44:31 +0200 Subject: [PATCH 08/14] Fix logging statement --- .../nexus/delta/plugins/search/SearchScopeInitialization.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala index 88804b74f5..a5bab38f65 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala @@ -44,7 +44,7 @@ final class SearchScopeInitialization( case rej => val str = s"Failed to create the search view for project '${project.ref}' due to '${rej.getMessage}'." - IO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .named("createSearchView", "search") } From 8e6bb65f26f7fe69d25481f2b0f3e62a22b0c4b7 Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Mon, 2 Oct 2023 10:06:50 +0200 Subject: [PATCH 09/14] Remove explicit conversion --- .../epfl/bluebrain/nexus/delta/plugins/search/Search.scala | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala index 899be3a899..c795703400 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala @@ -2,6 +2,8 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.http.scaladsl.model.Uri import cats.effect.IO +import cats.implicits.catsSyntaxApplicativeId +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.indexing.projectionIndex @@ -16,8 +18,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import io.circe.{Json, JsonObject} -import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ - trait Search { /** @@ -60,7 +60,7 @@ object Search { compositeViews .list( Pagination.OnePage, - CompositeViewSearchParams(deprecated = Some(false), filter = v => IO.pure(v.id == defaultViewId).toUIO), + CompositeViewSearchParams(deprecated = Some(false), filter = v => (v.id == defaultViewId).pure), Ordering.by(_.createdAt) ) .map( From 9c3e90b89b7eaa374a9f4f6ca35880e21ae1ab9d Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:24:47 +0200 Subject: [PATCH 10/14] Remove duplicate trait --- .../plugins/search/SearchPluginModule.scala | 5 -- .../search/SearchScopeInitialization.scala | 3 +- .../nexus/delta/sdk/ScopeInitialization.scala | 17 +++-- .../sdk/ce/CatsScopeInitialization.scala | 66 ------------------- 4 files changed, 14 insertions(+), 77 deletions(-) delete mode 100644 delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala index eae2233535..e2026f66de 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala @@ -10,7 +10,6 @@ import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.context.RemoteContextResolution import ch.epfl.bluebrain.nexus.delta.rdf.utils.JsonKeyOrdering import ch.epfl.bluebrain.nexus.delta.sdk._ import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclCheck -import ch.epfl.bluebrain.nexus.delta.sdk.ce.CatsScopeInitialization import ch.epfl.bluebrain.nexus.delta.sdk.identities.Identities import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri @@ -39,10 +38,6 @@ class SearchPluginModule(priority: Int) extends ModuleDef { new SearchScopeInitialization(views, config.indexing, serviceAccount, config.defaults)(baseUri) } - many[ScopeInitialization].add { (s: SearchScopeInitialization) => - CatsScopeInitialization.toBioScope(s) - } - make[SearchRoutes].from { ( identities: Identities, diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala index a5bab38f65..9ffbe01313 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala @@ -9,13 +9,12 @@ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewRejection.{ProjectContextRejection, ViewAlreadyExists} import ch.epfl.bluebrain.nexus.delta.plugins.search.model.SearchConfig.IndexingConfig import ch.epfl.bluebrain.nexus.delta.plugins.search.model.defaultViewId -import ch.epfl.bluebrain.nexus.delta.sdk.Defaults -import ch.epfl.bluebrain.nexus.delta.sdk.ce.CatsScopeInitialization import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError.ScopeInitializationFailed import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project +import ch.epfl.bluebrain.nexus.delta.sdk.{CatsScopeInitialization, Defaults} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala index 5e1092774b..06184468d6 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala @@ -1,10 +1,12 @@ package ch.epfl.bluebrain.nexus.delta.sdk +import cats.effect.IO +import ch.epfl.bluebrain.nexus.delta.sdk.SIO.SIO import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError.ScopeInitializationFailed import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project -import monix.bio.IO +import monix.bio.{IO => BIO} /** * Lifecycle hook for organization and project initialization. It's meant to be used for plugins to preconfigure an @@ -12,7 +14,7 @@ import monix.bio.IO * Implementations should use a `many[ScopeInitialization]` binding such that all implementation are collected during * the service bootstrapping. */ -trait ScopeInitialization { +trait ScopeInitializationF[F[_]] { /** * The method is invoked synchronously during the organization creation for its immediate configuration. @@ -25,7 +27,7 @@ trait ScopeInitialization { * @param subject * the identity that was recorded for the creation of the organization */ - def onOrganizationCreation(organization: Organization, subject: Subject): IO[ScopeInitializationFailed, Unit] + def onOrganizationCreation(organization: Organization, subject: Subject): F[Unit] /** * The method is invoked synchronously during the project creation for immediate configuration of the project. @@ -38,6 +40,13 @@ trait ScopeInitialization { * @param subject * the identity that was recorded for the creation of the project */ - def onProjectCreation(project: Project, subject: Subject): IO[ScopeInitializationFailed, Unit] + def onProjectCreation(project: Project, subject: Subject): F[Unit] } + +object SIO { + type SIO[A] = BIO[ScopeInitializationFailed, A] +} + +trait ScopeInitialization extends ScopeInitializationF[SIO] +trait CatsScopeInitialization extends ScopeInitializationF[IO] diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala deleted file mode 100644 index 73aa1acca6..0000000000 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ce/CatsScopeInitialization.scala +++ /dev/null @@ -1,66 +0,0 @@ -package ch.epfl.bluebrain.nexus.delta.sdk.ce - -import cats.effect.IO -import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration.toMonixBIOOps -import ch.epfl.bluebrain.nexus.delta.sdk.ScopeInitialization -import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError -import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject -import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization -import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project -import monix.bio.{IO => BIO} - -/** - * Lifecycle hook for organization and project initialization. It's meant to be used for plugins to preconfigure an - * organization or project, like for example the creation of a default view or setting the appropriate permissions. - * Implementations should use a `many[ScopeInitialization]` binding such that all implementation are collected during - * the service bootstrapping. - */ -trait CatsScopeInitialization { - - /** - * The method is invoked synchronously during the organization creation for its immediate configuration. - * Additionally, in order to correct failures that may have occurred, this method will also be invoked as an - * opportunity to heal as part of the organization event log replay during the bootstrapping of the service. The - * method is expected to perform necessary checks such that the initialization would not be executed twice. - * - * @param organization - * the organization that was created - * @param subject - * the identity that was recorded for the creation of the organization - */ - def onOrganizationCreation(organization: Organization, subject: Subject): IO[Unit] - - /** - * The method is invoked synchronously during the project creation for immediate configuration of the project. - * Additionally, in order to correct failures that may have occurred, this method will also be invoked as an - * opportunity to heal as part of the project event log replay during the bootstrapping of the service. The method is - * expected to perform necessary checks such that the initialization would not be executed twice. - * - * @param project - * the project that was created - * @param subject - * the identity that was recorded for the creation of the project - */ - def onProjectCreation(project: Project, subject: Subject): IO[Unit] - -} - -object CatsScopeInitialization { - - /** CE Migration helper */ - def toBioScope(catsScope: CatsScopeInitialization): ScopeInitialization = - new ScopeInitialization { - override def onOrganizationCreation( - organization: Organization, - subject: Subject - ): BIO[ServiceError.ScopeInitializationFailed, Unit] = - catsScope.onOrganizationCreation(organization, subject).toBIO - - override def onProjectCreation( - project: Project, - subject: Subject - ): BIO[ServiceError.ScopeInitializationFailed, Unit] = - catsScope.onProjectCreation(project, subject).toBIO - } - -} From 651a4dbffd7edc8acefc52af4fa4ed1e15e0424c Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Mon, 2 Oct 2023 14:27:40 +0200 Subject: [PATCH 11/14] Go back to using toUIO --- .../ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala index c795703400..eeeb4b1036 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala @@ -2,7 +2,7 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.http.scaladsl.model.Uri import cats.effect.IO -import cats.implicits.catsSyntaxApplicativeId +import cats.implicits._ import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews @@ -60,7 +60,7 @@ object Search { compositeViews .list( Pagination.OnePage, - CompositeViewSearchParams(deprecated = Some(false), filter = v => (v.id == defaultViewId).pure), + CompositeViewSearchParams(deprecated = Some(false), filter = v => IO.delay(v.id == defaultViewId).toUIO), Ordering.by(_.createdAt) ) .map( From 90631e18924c186dfc0a2f21fb07bc01ba6dfc6d Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:04:58 +0200 Subject: [PATCH 12/14] Migrate all ScopeInitializations --- .../BlazegraphScopeInitialization.scala | 26 ++++++++++--------- .../model/BlazegraphViewRejection.scala | 3 ++- .../ElasticSearchScopeInitialization.scala | 22 +++++++++------- .../model/ElasticSearchViewRejection.scala | 3 ++- .../plugins/search/SearchPluginModule.scala | 1 + .../search/SearchScopeInitialization.scala | 4 +-- .../storage/StorageScopeInitialization.scala | 22 +++++++++------- .../storages/model/StorageRejection.scala | 5 ++-- .../nexus/delta/sdk/ScopeInitialization.scala | 18 +++---------- .../delta/sdk/acls/model/AclRejection.scala | 3 ++- .../sdk/organizations/OrganizationsImpl.scala | 3 ++- .../OwnerPermissionsScopeInitialization.scala | 26 ++++++++++--------- .../delta/sdk/projects/ProjectsImpl.scala | 3 ++- .../ResolverScopeInitialization.scala | 24 +++++++++-------- .../resolvers/model/ResolverRejection.scala | 3 ++- .../delta/sdk/ScopeInitializationLog.scala | 10 +++---- 16 files changed, 91 insertions(+), 85 deletions(-) diff --git a/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitialization.scala b/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitialization.scala index 73356fe631..2e595dfa91 100644 --- a/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitialization.scala +++ b/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitialization.scala @@ -1,20 +1,22 @@ package ch.epfl.bluebrain.nexus.delta.plugins.blazegraph +import cats.effect.IO +import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent -import ch.epfl.bluebrain.nexus.delta.kernel.syntax._ +import ch.epfl.bluebrain.nexus.delta.kernel.syntax.kamonSyntax import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.BlazegraphViews.entityType import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.BlazegraphViewRejection.{ProjectContextRejection, ResourceAlreadyExists} import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.BlazegraphViewValue.IndexingBlazegraphViewValue import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model._ -import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError.ScopeInitializationFailed import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project +import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject -import com.typesafe.scalalogging.Logger -import monix.bio.{IO, UIO} /** * The default creation of the default SparqlView as part of the project initialization. @@ -30,7 +32,7 @@ class BlazegraphScopeInitialization( defaults: Defaults ) extends ScopeInitialization { - private val logger: Logger = Logger[BlazegraphScopeInitialization] + private val logger = Logger.cats[BlazegraphScopeInitialization] implicit private val serviceAccountSubject: Subject = serviceAccount.subject implicit private val kamonComponent: KamonMetricComponent = KamonMetricComponent(entityType.value) @@ -45,23 +47,23 @@ class BlazegraphScopeInitialization( permission = permissions.query ) - override def onProjectCreation(project: Project, subject: Identity.Subject): IO[ScopeInitializationFailed, Unit] = + override def onProjectCreation(project: Project, subject: Identity.Subject): IO[Unit] = views .create(defaultViewId, project.ref, defaultValue) .void - .onErrorHandleWith { - case _: ResourceAlreadyExists => UIO.unit // nothing to do, view already exits - case _: ProjectContextRejection => UIO.unit // project or org are likely deprecated + .handleErrorWith { + case _: ResourceAlreadyExists => IO.unit // nothing to do, view already exits + case _: ProjectContextRejection => IO.unit // project or org are likely deprecated case rej => val str = - s"Failed to create the default SparqlView for project '${project.ref}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + s"Failed to create the default SparqlView for project '${project.ref}' due to '${rej.getMessage}'." + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .span("createDefaultSparqlView") override def onOrganizationCreation( organization: Organization, subject: Identity.Subject - ): IO[ScopeInitializationFailed, Unit] = IO.unit + ): IO[Unit] = IO.unit } diff --git a/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/model/BlazegraphViewRejection.scala b/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/model/BlazegraphViewRejection.scala index 70e35c78f1..238972f4b7 100644 --- a/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/model/BlazegraphViewRejection.scala +++ b/delta/plugins/blazegraph/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/model/BlazegraphViewRejection.scala @@ -20,10 +20,11 @@ import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext.ContextRejection import ch.epfl.bluebrain.nexus.delta.sdk.views.ViewRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.Tag.UserTag +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import io.circe.syntax.EncoderOps import io.circe.{Encoder, JsonObject} -sealed abstract class BlazegraphViewRejection(val reason: String) extends Product with Serializable +sealed abstract class BlazegraphViewRejection(val reason: String) extends Rejection object BlazegraphViewRejection { diff --git a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitialization.scala b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitialization.scala index e9750ae8ff..7014802a86 100644 --- a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitialization.scala +++ b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitialization.scala @@ -1,5 +1,7 @@ package ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch +import cats.effect.IO +import cats.implicits._ import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent import ch.epfl.bluebrain.nexus.delta.kernel.syntax._ import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.ElasticSearchViews.entityType @@ -15,8 +17,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.views.PipeStep import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sourcing.stream.pipes.{DefaultLabelPredicates, SourceAsText} -import com.typesafe.scalalogging.Logger -import monix.bio.{IO, UIO} +import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ /** * The default creation of the default ElasticSearchView as part of the project initialization. @@ -32,7 +34,7 @@ class ElasticSearchScopeInitialization( defaults: Defaults ) extends ScopeInitialization { - private val logger: Logger = Logger[ElasticSearchScopeInitialization] + private val logger = Logger.cats[ElasticSearchScopeInitialization] implicit private val serviceAccountSubject: Subject = serviceAccount.subject implicit private val kamonComponent: KamonMetricComponent = KamonMetricComponent(entityType.value) @@ -48,23 +50,23 @@ class ElasticSearchScopeInitialization( permission = permissions.query ) - override def onProjectCreation(project: Project, subject: Identity.Subject): IO[ScopeInitializationFailed, Unit] = + override def onProjectCreation(project: Project, subject: Identity.Subject): IO[Unit] = views .create(defaultViewId, project.ref, defaultValue) .void - .onErrorHandleWith { - case _: ResourceAlreadyExists => UIO.unit // nothing to do, view already exits - case _: ProjectContextRejection => UIO.unit // project or org are likely deprecated + .handleErrorWith { + case _: ResourceAlreadyExists => IO.unit // nothing to do, view already exits + case _: ProjectContextRejection => IO.unit // project or org are likely deprecated case rej => val str = - s"Failed to create the default ElasticSearchView for project '${project.ref}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + s"Failed to create the default ElasticSearchView for project '${project.ref}' due to '${rej.getMessage}'." + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .span("createDefaultElasticSearchView") override def onOrganizationCreation( organization: Organization, subject: Identity.Subject - ): IO[ScopeInitializationFailed, Unit] = IO.unit + ): IO[Unit] = IO.unit } diff --git a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ElasticSearchViewRejection.scala b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ElasticSearchViewRejection.scala index e5c3c3621f..83fe655d2a 100644 --- a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ElasticSearchViewRejection.scala +++ b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ElasticSearchViewRejection.scala @@ -20,6 +20,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.syntax._ import ch.epfl.bluebrain.nexus.delta.sdk.views.ViewRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.Tag.UserTag +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import ch.epfl.bluebrain.nexus.delta.sourcing.stream.ProjectionErr import io.circe.syntax._ import io.circe.{Encoder, Json, JsonObject} @@ -30,7 +31,7 @@ import io.circe.{Encoder, Json, JsonObject} * @param reason * a descriptive message as to why the rejection occurred */ -sealed abstract class ElasticSearchViewRejection(val reason: String) extends Product with Serializable +sealed abstract class ElasticSearchViewRejection(val reason: String) extends Rejection object ElasticSearchViewRejection { diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala index e2026f66de..9a2449c478 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchPluginModule.scala @@ -37,6 +37,7 @@ class SearchPluginModule(priority: Int) extends ModuleDef { (views: CompositeViews, config: SearchConfig, serviceAccount: ServiceAccount, baseUri: BaseUri) => new SearchScopeInitialization(views, config.indexing, serviceAccount, config.defaults)(baseUri) } + many[ScopeInitialization].ref[SearchScopeInitialization] make[SearchRoutes].from { ( diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala index 9ffbe01313..598b8abfd8 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/SearchScopeInitialization.scala @@ -14,7 +14,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.ServiceAccount import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project -import ch.epfl.bluebrain.nexus.delta.sdk.{CatsScopeInitialization, Defaults} +import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject @@ -24,7 +24,7 @@ final class SearchScopeInitialization( serviceAccount: ServiceAccount, defaults: Defaults )(implicit baseUri: BaseUri) - extends CatsScopeInitialization { + extends ScopeInitialization { private val logger = Logger.cats[SearchScopeInitialization] diff --git a/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitialization.scala b/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitialization.scala index 64cce4329d..aa79fe28a3 100644 --- a/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitialization.scala +++ b/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitialization.scala @@ -1,5 +1,6 @@ package ch.epfl.bluebrain.nexus.delta.plugins.storage +import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.Storages.entityType import ch.epfl.bluebrain.nexus.delta.plugins.storage.storages.model.StorageFields.DiskStorageFields @@ -12,8 +13,9 @@ import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity -import com.typesafe.scalalogging.Logger -import monix.bio.{IO, UIO} +import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ /** * The default creation of the default disk storage as part of the project initialization. @@ -29,7 +31,7 @@ class StorageScopeInitialization( defaults: Defaults ) extends ScopeInitialization { - private val logger: Logger = Logger[StorageScopeInitialization] + private val logger = Logger.cats[StorageScopeInitialization] implicit private val kamonComponent: KamonMetricComponent = KamonMetricComponent(entityType.value) implicit private val caller: Caller = serviceAccount.caller @@ -45,23 +47,23 @@ class StorageScopeInitialization( maxFileSize = None ) - override def onProjectCreation(project: Project, subject: Identity.Subject): IO[ScopeInitializationFailed, Unit] = + override def onProjectCreation(project: Project, subject: Identity.Subject): IO[Unit] = storages .create(defaultStorageId, project.ref, defaultValue) .void - .onErrorHandleWith { - case _: ResourceAlreadyExists => UIO.unit // nothing to do, storage already exits - case _: ProjectContextRejection => UIO.unit // project or org are likely deprecated + .handleErrorWith { + case _: ResourceAlreadyExists => IO.unit // nothing to do, storage already exits + case _: ProjectContextRejection => IO.unit // project or org are likely deprecated case rej => val str = - s"Failed to create the default DiskStorage for project '${project.ref}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + s"Failed to create the default DiskStorage for project '${project.ref}' due to '${rej.getMessage}'." + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .span("createDefaultStorage") override def onOrganizationCreation( organization: Organization, subject: Identity.Subject - ): IO[ScopeInitializationFailed, Unit] = IO.unit + ): IO[Unit] = IO.unit } diff --git a/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/storages/model/StorageRejection.scala b/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/storages/model/StorageRejection.scala index e7dbd44bfe..8a42d9f4c3 100644 --- a/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/storages/model/StorageRejection.scala +++ b/delta/plugins/storage/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/storages/model/StorageRejection.scala @@ -16,6 +16,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext.ContextRejection import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef import ch.epfl.bluebrain.nexus.delta.sourcing.model.Tag.UserTag +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import com.typesafe.scalalogging.Logger import io.circe.syntax._ import io.circe.{Encoder, JsonObject} @@ -26,9 +27,7 @@ import io.circe.{Encoder, JsonObject} * @param reason * a descriptive message as to why the rejection occurred */ -sealed abstract class StorageRejection(val reason: String, val loggedDetails: Option[String] = None) - extends Product - with Serializable +sealed abstract class StorageRejection(val reason: String, val loggedDetails: Option[String] = None) extends Rejection object StorageRejection { diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala index 06184468d6..c4e7c1a7fe 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitialization.scala @@ -1,12 +1,9 @@ package ch.epfl.bluebrain.nexus.delta.sdk import cats.effect.IO -import ch.epfl.bluebrain.nexus.delta.sdk.SIO.SIO -import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError.ScopeInitializationFailed -import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project -import monix.bio.{IO => BIO} +import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject /** * Lifecycle hook for organization and project initialization. It's meant to be used for plugins to preconfigure an @@ -14,7 +11,7 @@ import monix.bio.{IO => BIO} * Implementations should use a `many[ScopeInitialization]` binding such that all implementation are collected during * the service bootstrapping. */ -trait ScopeInitializationF[F[_]] { +trait ScopeInitialization { /** * The method is invoked synchronously during the organization creation for its immediate configuration. @@ -27,7 +24,7 @@ trait ScopeInitializationF[F[_]] { * @param subject * the identity that was recorded for the creation of the organization */ - def onOrganizationCreation(organization: Organization, subject: Subject): F[Unit] + def onOrganizationCreation(organization: Organization, subject: Subject): IO[Unit] /** * The method is invoked synchronously during the project creation for immediate configuration of the project. @@ -40,13 +37,6 @@ trait ScopeInitializationF[F[_]] { * @param subject * the identity that was recorded for the creation of the project */ - def onProjectCreation(project: Project, subject: Subject): F[Unit] + def onProjectCreation(project: Project, subject: Subject): IO[Unit] } - -object SIO { - type SIO[A] = BIO[ScopeInitializationFailed, A] -} - -trait ScopeInitialization extends ScopeInitializationF[SIO] -trait CatsScopeInitialization extends ScopeInitializationF[IO] diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/acls/model/AclRejection.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/acls/model/AclRejection.scala index 0b26c4d6e5..f08966b82d 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/acls/model/AclRejection.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/acls/model/AclRejection.scala @@ -10,6 +10,7 @@ import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.encoder.JsonLdEncoder import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.HttpResponseFields import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import io.circe.syntax._ import io.circe.{Encoder, JsonObject} @@ -19,7 +20,7 @@ import io.circe.{Encoder, JsonObject} * @param reason * a descriptive message as to why the rejection occurred */ -sealed abstract class AclRejection(val reason: String) extends Product with Serializable +sealed abstract class AclRejection(val reason: String) extends Rejection object AclRejection { diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImpl.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImpl.scala index 9548d79a45..a816e2bc26 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImpl.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImpl.scala @@ -1,6 +1,7 @@ package ch.epfl.bluebrain.nexus.delta.sdk.organizations import cats.effect.Clock +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF @@ -30,7 +31,7 @@ final class OrganizationsImpl private ( )(implicit caller: Subject): IO[OrganizationRejection, OrganizationResource] = for { resource <- eval(CreateOrganization(label, description, caller)).span("createOrganization") - _ <- IO.parTraverseUnordered(scopeInitializations)(_.onOrganizationCreation(resource.value, caller)) + _ <- IO.parTraverseUnordered(scopeInitializations)(_.onOrganizationCreation(resource.value, caller).toUIO) .void .mapError(OrganizationInitializationFailed) .span("initializeOrganization") diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitialization.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitialization.scala index af02450a96..f06136d799 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitialization.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitialization.scala @@ -1,6 +1,10 @@ package ch.epfl.bluebrain.nexus.delta.sdk.projects +import cats.effect.IO +import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.syntax._ import ch.epfl.bluebrain.nexus.delta.sdk.ScopeInitialization import ch.epfl.bluebrain.nexus.delta.sdk.acls.Acls @@ -11,8 +15,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.permissions.model.Permission import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject -import com.typesafe.scalalogging.Logger -import monix.bio.{IO, UIO} /** * The default creation of ACLs for newly created organizations and projects. @@ -22,33 +24,33 @@ import monix.bio.{IO, UIO} * @param ownerPermissions * the collection of permissions to be granted to the owner (creator) */ -class OwnerPermissionsScopeInitialization(appendAcls: Acl => IO[AclRejection, Unit], ownerPermissions: Set[Permission]) +class OwnerPermissionsScopeInitialization(appendAcls: Acl => IO[Unit], ownerPermissions: Set[Permission]) extends ScopeInitialization { implicit private val kamonComponent: KamonMetricComponent = KamonMetricComponent("ownerPermissions") - private val logger: Logger = Logger[OwnerPermissionsScopeInitialization] + private val logger = Logger.cats[OwnerPermissionsScopeInitialization] override def onOrganizationCreation( organization: Organization, subject: Subject - ): IO[ScopeInitializationFailed, Unit] = + ): IO[Unit] = appendAcls(Acl(organization.label, subject -> ownerPermissions)) - .onErrorHandleWith { + .handleErrorWith { case _: AclRejection.IncorrectRev => IO.unit // acls are already set case rej => - val str = s"Failed to apply the owner permissions for org '${organization.label}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + val str = s"Failed to apply the owner permissions for org '${organization.label}' due to '${rej.getMessage}'." + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .span("setOrgPermissions") - override def onProjectCreation(project: Project, subject: Subject): IO[ScopeInitializationFailed, Unit] = + override def onProjectCreation(project: Project, subject: Subject): IO[Unit] = appendAcls(Acl(project.ref, subject -> ownerPermissions)) - .onErrorHandleWith { + .handleErrorWith { case _: AclRejection.IncorrectRev => IO.unit // acls are already set case rej => - val str = s"Failed to apply the owner permissions for project '${project.ref}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + val str = s"Failed to apply the owner permissions for project '${project.ref}' due to '${rej.getMessage}'." + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .span("setProjectPermissions") } diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImpl.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImpl.scala index 015f290332..a22390a7c7 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImpl.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImpl.scala @@ -1,6 +1,7 @@ package ch.epfl.bluebrain.nexus.delta.sdk.projects import cats.effect.Clock +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF @@ -45,7 +46,7 @@ final class ProjectsImpl private ( caller ) ).span("createProject") - _ <- IO.parTraverseUnordered(scopeInitializations)(_.onProjectCreation(resource.value, caller)) + _ <- IO.parTraverseUnordered(scopeInitializations)(_.onProjectCreation(resource.value, caller).toUIO) .void .mapError(ProjectInitializationFailed) .span("initializeProject") diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitialization.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitialization.scala index 3ba4272818..296a9fa7bf 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitialization.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitialization.scala @@ -1,8 +1,11 @@ package ch.epfl.bluebrain.nexus.delta.sdk.resolvers +import cats.effect.IO +import cats.implicits._ +import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.kamon.KamonMetricComponent import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.nxv -import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError.ScopeInitializationFailed import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.{Caller, ServiceAccount} import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization @@ -12,9 +15,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResolverRejection.{Proj import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResolverValue.InProjectValue import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.{Priority, ResolverValue} import ch.epfl.bluebrain.nexus.delta.sdk.syntax._ +import ch.epfl.bluebrain.nexus.delta.sdk.{Defaults, ScopeInitialization} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject -import com.typesafe.scalalogging.Logger -import monix.bio.{IO, UIO} /** * The default creation of the InProject resolver as part of the project initialization. @@ -30,28 +32,28 @@ class ResolverScopeInitialization( defaults: Defaults ) extends ScopeInitialization { - private val logger: Logger = Logger[ResolverScopeInitialization] + private val logger = Logger.cats[ResolverScopeInitialization] private val defaultInProjectResolverValue: ResolverValue = InProjectValue(Some(defaults.name), Some(defaults.description), Priority.unsafe(1)) implicit private val caller: Caller = serviceAccount.caller implicit private val kamonComponent: KamonMetricComponent = KamonMetricComponent(entityType.value) - override def onProjectCreation(project: Project, subject: Subject): IO[ScopeInitializationFailed, Unit] = + override def onProjectCreation(project: Project, subject: Subject): IO[Unit] = resolvers .create(nxv.defaultResolver, project.ref, defaultInProjectResolverValue) .void - .onErrorHandleWith { - case _: ResourceAlreadyExists => UIO.unit // nothing to do, resolver already exits - case _: ProjectContextRejection => UIO.unit // project or org is likely deprecated + .handleErrorWith { + case _: ResourceAlreadyExists => IO.unit // nothing to do, resolver already exits + case _: ProjectContextRejection => IO.unit // project or org is likely deprecated case rej => val str = - s"Failed to create the default InProject resolver for project '${project.ref}' due to '${rej.reason}'." - UIO.delay(logger.error(str)) >> IO.raiseError(ScopeInitializationFailed(str)) + s"Failed to create the default InProject resolver for project '${project.ref}' due to '${rej.getMessage}'." + logger.error(str) >> IO.raiseError(ScopeInitializationFailed(str)) } .span("createDefaultResolver") override def onOrganizationCreation( organization: Organization, subject: Subject - ): IO[ScopeInitializationFailed, Unit] = IO.unit + ): IO[Unit] = IO.unit } diff --git a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/model/ResolverRejection.scala b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/model/ResolverRejection.scala index f094c91276..c033cb5ad7 100644 --- a/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/model/ResolverRejection.scala +++ b/delta/sdk/src/main/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/model/ResolverRejection.scala @@ -18,6 +18,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResourceResolutionRepor import ch.epfl.bluebrain.nexus.delta.sourcing.model.ResourceRef.{Latest, Revision, Tag} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Tag.UserTag import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Identity, ProjectRef, ResourceRef} +import ch.epfl.bluebrain.nexus.delta.sourcing.rejection.Rejection import io.circe.syntax._ import io.circe.{Encoder, JsonObject} @@ -27,7 +28,7 @@ import io.circe.{Encoder, JsonObject} * @param reason * a descriptive message as to why the rejection occurred */ -sealed abstract class ResolverRejection(val reason: String) extends Product with Serializable +sealed abstract class ResolverRejection(val reason: String) extends Rejection object ResolverRejection { diff --git a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitializationLog.scala b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitializationLog.scala index 10627de29b..c8cba4db7c 100644 --- a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitializationLog.scala +++ b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/ScopeInitializationLog.scala @@ -1,10 +1,10 @@ package ch.epfl.bluebrain.nexus.delta.sdk -import ch.epfl.bluebrain.nexus.delta.sdk.error.ServiceError +import cats.effect.IO +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.Organization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.Project import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Identity, Label, ProjectRef} import ch.epfl.bluebrain.nexus.testkit.IORef -import monix.bio.{IO, UIO} /** * Simple implementation that records created orgs and projects @@ -17,19 +17,19 @@ final class ScopeInitializationLog private ( override def onOrganizationCreation( organization: Organization, subject: Identity.Subject - ): IO[ServiceError.ScopeInitializationFailed, Unit] = + ): IO[Unit] = createdOrgs.update(_ + organization.label) override def onProjectCreation( project: Project, subject: Identity.Subject - ): IO[ServiceError.ScopeInitializationFailed, Unit] = + ): IO[Unit] = createdProjects.update(_ + project.ref) } object ScopeInitializationLog { - def apply(): UIO[ScopeInitializationLog] = + def apply(): IO[ScopeInitializationLog] = for { createdOrgs <- IORef.of(Set.empty[Label]) createdProjects <- IORef.of(Set.empty[ProjectRef]) From ba9404468e651e3ba8c4ff833395bf874329138a Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Tue, 3 Oct 2023 15:20:40 +0200 Subject: [PATCH 13/14] Adapt all ScopeInitialization related tests --- .../nexus/delta/routes/OrganizationsRoutesSpec.scala | 3 ++- .../blazegraph/BlazegraphScopeInitializationSpec.scala | 5 +++-- .../ElasticSearchScopeInitializationSpec.scala | 5 +++-- .../plugins/storage/StorageScopeInitializationSpec.scala | 5 +++-- .../delta/sdk/organizations/OrganizationsImplSpec.scala | 7 ++++--- .../projects/OwnerPermissionsScopeInitializationSpec.scala | 5 +++-- .../nexus/delta/sdk/projects/ProjectsImplSpec.scala | 7 ++++--- .../sdk/resolvers/ResolverScopeInitializationSpec.scala | 5 +++-- 8 files changed, 25 insertions(+), 17 deletions(-) diff --git a/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/OrganizationsRoutesSpec.scala b/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/OrganizationsRoutesSpec.scala index fc59eb1aaf..02560abb53 100644 --- a/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/OrganizationsRoutesSpec.scala +++ b/delta/app/src/test/scala/ch/epfl/bluebrain/nexus/delta/routes/OrganizationsRoutesSpec.scala @@ -3,6 +3,7 @@ package ch.epfl.bluebrain.nexus.delta.routes import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.model.headers.OAuth2BearerToken import akka.http.scaladsl.server.Route +import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.utils.{UUIDF, UrlUtils} import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.contexts import ch.epfl.bluebrain.nexus.delta.sdk.acls.AclSimpleCheck @@ -35,7 +36,7 @@ class OrganizationsRoutesSpec extends BaseRouteSpec with IOFromMap { private val aclChecker = AclSimpleCheck().accepted private val aopd = new OwnerPermissionsScopeInitialization( - aclChecker.append, + acl => aclChecker.append(acl), Set(orgsPermissions.write, orgsPermissions.read) ) private lazy val orgs = OrganizationsImpl(Set(aopd), config, xas) diff --git a/delta/plugins/blazegraph/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitializationSpec.scala b/delta/plugins/blazegraph/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitializationSpec.scala index 1c8c0ab887..bbbb42199f 100644 --- a/delta/plugins/blazegraph/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitializationSpec.scala +++ b/delta/plugins/blazegraph/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/blazegraph/BlazegraphScopeInitializationSpec.scala @@ -14,7 +14,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.{ConfigFixtures, Defaults} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Subject, User} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture -import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, IOValues, TestHelpers} +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues +import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, TestHelpers} import monix.bio.UIO import monix.execution.Scheduler import org.scalatest.Inspectors @@ -27,7 +28,7 @@ class BlazegraphScopeInitializationSpec with Matchers with Inspectors with IOFixedClock - with IOValues + with CatsIOValues with TestHelpers with ConfigFixtures with Fixtures { diff --git a/delta/plugins/elasticsearch/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitializationSpec.scala b/delta/plugins/elasticsearch/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitializationSpec.scala index 1efa62f309..b8db363e40 100644 --- a/delta/plugins/elasticsearch/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitializationSpec.scala +++ b/delta/plugins/elasticsearch/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/ElasticSearchScopeInitializationSpec.scala @@ -17,7 +17,8 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Subject, User} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture import ch.epfl.bluebrain.nexus.delta.sourcing.stream.pipes.{DefaultLabelPredicates, SourceAsText} -import ch.epfl.bluebrain.nexus.testkit.{EitherValuable, IOValues, TestHelpers} +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues +import ch.epfl.bluebrain.nexus.testkit.{EitherValuable, TestHelpers} import org.scalatest.matchers.should.Matchers import org.scalatest.wordspec.AnyWordSpecLike import org.scalatest.{Inspectors, OptionValues} @@ -29,7 +30,7 @@ class ElasticSearchScopeInitializationSpec with AnyWordSpecLike with Matchers with Inspectors - with IOValues + with CatsIOValues with OptionValues with EitherValuable with TestHelpers diff --git a/delta/plugins/storage/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitializationSpec.scala b/delta/plugins/storage/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitializationSpec.scala index 15fe643553..472b04d204 100644 --- a/delta/plugins/storage/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitializationSpec.scala +++ b/delta/plugins/storage/src/test/scala/ch/epfl/bluebrain/nexus/delta/plugins/storage/StorageScopeInitializationSpec.scala @@ -16,7 +16,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.{ConfigFixtures, Defaults} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Subject, User} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture -import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, IOValues, TestHelpers} +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues +import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, TestHelpers} import monix.bio.IO import monix.execution.Scheduler import org.scalatest.matchers.should.Matchers @@ -26,7 +27,7 @@ import java.util.UUID class StorageScopeInitializationSpec extends DoobieScalaTestFixture with Matchers - with IOValues + with CatsIOValues with IOFixedClock with RemoteContextResolutionFixture with ConfigFixtures diff --git a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImplSpec.scala b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImplSpec.scala index 5a744757a2..4fa17d8b97 100644 --- a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImplSpec.scala +++ b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/organizations/OrganizationsImplSpec.scala @@ -1,9 +1,9 @@ package ch.epfl.bluebrain.nexus.delta.sdk.organizations +import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination.FromPagination import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF import ch.epfl.bluebrain.nexus.delta.sdk.generators.OrganizationGen.{organization, resourceFor} import ch.epfl.bluebrain.nexus.delta.sdk.model.ResourceF -import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination.FromPagination import ch.epfl.bluebrain.nexus.delta.sdk.model.search.ResultEntry.UnscoredResultEntry import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchParams.OrganizationSearchParams import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults.UnscoredSearchResults @@ -13,7 +13,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.{ConfigFixtures, ScopeInitializationLog import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Identity, Label} import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture -import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, IOValues} +import ch.epfl.bluebrain.nexus.testkit.IOFixedClock +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import monix.bio.UIO import monix.execution.Scheduler import org.scalatest.matchers.should.Matchers @@ -25,7 +26,7 @@ import java.util.UUID class OrganizationsImplSpec extends DoobieScalaTestFixture with Matchers - with IOValues + with CatsIOValues with IOFixedClock with CancelAfterFailure with OptionValues diff --git a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitializationSpec.scala b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitializationSpec.scala index cfd4db48f7..7e3891315b 100644 --- a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitializationSpec.scala +++ b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/OwnerPermissionsScopeInitializationSpec.scala @@ -9,14 +9,15 @@ import ch.epfl.bluebrain.nexus.delta.sdk.permissions.Permissions import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.User import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture -import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, IOValues, TestHelpers} +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues +import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, TestHelpers} import monix.bio.UIO import org.scalatest.matchers.should.Matchers class OwnerPermissionsScopeInitializationSpec extends DoobieScalaTestFixture with Matchers - with IOValues + with CatsIOValues with IOFixedClock with TestHelpers with ConfigFixtures { diff --git a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImplSpec.scala b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImplSpec.scala index b92eb1ee47..bddace9320 100644 --- a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImplSpec.scala +++ b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/projects/ProjectsImplSpec.scala @@ -1,9 +1,9 @@ package ch.epfl.bluebrain.nexus.delta.sdk.projects +import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination.FromPagination import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.nxv import ch.epfl.bluebrain.nexus.delta.sdk.generators.ProjectGen._ -import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination.FromPagination import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchParams.ProjectSearchParams import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults import ch.epfl.bluebrain.nexus.delta.sdk.model.{BaseUri, ResourceF} @@ -17,7 +17,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.{ConfigFixtures, ScopeInitializationLog import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Identity, Label, ProjectRef} import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture -import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, IOValues} +import ch.epfl.bluebrain.nexus.testkit.IOFixedClock +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues import monix.bio.{IO, UIO} import org.scalatest.matchers.should.Matchers import org.scalatest.{CancelAfterFailure, OptionValues} @@ -27,7 +28,7 @@ import java.util.UUID class ProjectsImplSpec extends DoobieScalaTestFixture with Matchers - with IOValues + with CatsIOValues with IOFixedClock with CancelAfterFailure with OptionValues diff --git a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitializationSpec.scala b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitializationSpec.scala index 9c2b379088..fb23ce6d28 100644 --- a/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitializationSpec.scala +++ b/delta/sdk/src/test/scala/ch/epfl/bluebrain/nexus/delta/sdk/resolvers/ResolverScopeInitializationSpec.scala @@ -17,7 +17,8 @@ import ch.epfl.bluebrain.nexus.delta.sdk.{ConfigFixtures, Defaults} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.{Subject, User} import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.DoobieScalaTestFixture -import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, IOValues, TestHelpers} +import ch.epfl.bluebrain.nexus.testkit.ce.CatsIOValues +import ch.epfl.bluebrain.nexus.testkit.{IOFixedClock, TestHelpers} import monix.bio.IO import org.scalatest.matchers.should.Matchers @@ -26,7 +27,7 @@ import java.util.UUID class ResolverScopeInitializationSpec extends DoobieScalaTestFixture with Matchers - with IOValues + with CatsIOValues with IOFixedClock with TestHelpers with ConfigFixtures { From 87b76a8ab2a99cc2dc4771cb600e1f727845d3ad Mon Sep 17 00:00:00 2001 From: Oliver <20188437+olivergrabinski@users.noreply.github.com> Date: Wed, 4 Oct 2023 09:31:05 +0200 Subject: [PATCH 14/14] Go back to UIO --- .../ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala index eeeb4b1036..7526a2f1f8 100644 --- a/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala +++ b/delta/plugins/search/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/search/Search.scala @@ -2,7 +2,6 @@ package ch.epfl.bluebrain.nexus.delta.plugins.search import akka.http.scaladsl.model.Uri import cats.effect.IO -import cats.implicits._ import ch.epfl.bluebrain.nexus.delta.kernel.effect.migration._ import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews @@ -17,6 +16,7 @@ import ch.epfl.bluebrain.nexus.delta.sdk.acls.model.AclAddress.{Project => Proje import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label import io.circe.{Json, JsonObject} +import monix.bio.UIO trait Search { @@ -60,7 +60,7 @@ object Search { compositeViews .list( Pagination.OnePage, - CompositeViewSearchParams(deprecated = Some(false), filter = v => IO.delay(v.id == defaultViewId).toUIO), + CompositeViewSearchParams(deprecated = Some(false), filter = v => UIO.pure(v.id == defaultViewId)), Ordering.by(_.createdAt) ) .map(