diff --git a/ship/src/main/resources/ship-default.conf b/ship/src/main/resources/ship-default.conf index 5946c51340..d233502cf9 100644 --- a/ship/src/main/resources/ship-default.conf +++ b/ship/src/main/resources/ship-default.conf @@ -54,6 +54,18 @@ ship { } } + view-defaults { + elasticsearch { + name = "Default Elasticsearch view" + description = "An Elasticsearch view of all resources in the project." + } + + blazegraph { + name = "Default Sparql view" + description = "A Sparql view of all resources in the project." + } + } + # Service account configuration for internal operations service-account { subject: "delta" diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala index 5c3e29454e..34038bab37 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/RunShip.scala @@ -62,11 +62,11 @@ trait RunShip { rcr = ContextWiring.resolverContextResolution(fetchResource, fetchContext, remoteContextResolution, eventLogConfig, eventClock, xas) schemaImports = SchemaWiring.schemaImports(fetchResource, fetchSchema, fetchContext, eventLogConfig, eventClock, xas) // Processors - projectProcessor <- ProjectProcessor(fetchActiveOrg, projectMapper, eventLogConfig, eventClock, xas)(baseUri) + projectProcessor <- ProjectProcessor(fetchActiveOrg, fetchContext, rcr, projectMapper, config, eventClock, xas)(baseUri, jsonLdApi) resolverProcessor = ResolverProcessor(fetchContext, projectMapper, eventLogConfig, eventClock, xas) schemaProcessor = SchemaProcessor(schemaLog, fetchContext, schemaImports, rcr, projectMapper, eventClock) resourceProcessor = ResourceProcessor(resourceLog, rcr, projectMapper, fetchContext, eventClock) - esViewsProcessor <- ElasticSearchViewProcessor(fetchContext, rcr, projectMapper, eventLogConfig, eventClock, xas) + esViewsProcessor = ElasticSearchViewProcessor(fetchContext, rcr, projectMapper, eventLogConfig, eventClock, xas) bgViewsProcessor = BlazegraphViewProcessor(fetchContext, rcr, projectMapper, eventLogConfig, eventClock, xas) compositeViewsProcessor = CompositeViewProcessor(fetchContext, rcr, projectMapper, eventLogConfig, eventClock, xas) // format: on diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfig.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfig.scala index 5ce2a14eee..eee6113a39 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfig.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfig.scala @@ -25,6 +25,7 @@ final case class ShipConfig( eventLog: EventLogConfig, organizations: OrganizationCreationConfig, projectMapping: ProjectMapping = Map.empty, + viewDefaults: ViewDefaults, serviceAccount: ServiceAccountConfig ) diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ViewDefaults.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ViewDefaults.scala new file mode 100644 index 0000000000..6c638c57a3 --- /dev/null +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/config/ViewDefaults.scala @@ -0,0 +1,15 @@ +package ch.epfl.bluebrain.nexus.ship.config + +import ch.epfl.bluebrain.nexus.delta.sdk.Defaults +import pureconfig.ConfigReader +import pureconfig.generic.semiauto.deriveReader + +case class ViewDefaults( + elasticsearch: Defaults, + blazegraph: Defaults +) + +object ViewDefaults { + implicit val viewDefaultsConfigReader: ConfigReader[ViewDefaults] = + deriveReader[ViewDefaults] +} diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/projects/ProjectProcessor.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/projects/ProjectProcessor.scala index 4a6f5ce81a..4b5c1d896b 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/projects/ProjectProcessor.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/projects/ProjectProcessor.scala @@ -2,27 +2,31 @@ package ch.epfl.bluebrain.nexus.ship.projects import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.Logger +import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi import ch.epfl.bluebrain.nexus.delta.sdk.ScopeInitializer import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import ch.epfl.bluebrain.nexus.delta.sdk.organizations.FetchActiveOrganization import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ProjectEvent._ import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ProjectRejection.NotFound import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.{ApiMappings, ProjectEvent, ProjectFields, ProjectRejection} -import ch.epfl.bluebrain.nexus.delta.sdk.projects.{Projects, ProjectsImpl, ValidateProjectDeletion} +import ch.epfl.bluebrain.nexus.delta.sdk.projects.{FetchContext, Projects, ProjectsImpl, ValidateProjectDeletion} +import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.ResolverContextResolution import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors -import ch.epfl.bluebrain.nexus.delta.sourcing.config.EventLogConfig import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sourcing.model.{EntityType, ProjectRef} +import ch.epfl.bluebrain.nexus.ship._ +import ch.epfl.bluebrain.nexus.ship.config.ShipConfig import ch.epfl.bluebrain.nexus.ship.error.ShipError.ProjectDeletionIsNotAllowed import ch.epfl.bluebrain.nexus.ship.projects.ProjectProcessor.logger -import ch.epfl.bluebrain.nexus.ship.{EventClock, EventProcessor, EventUUIDF, ImportStatus, ProjectMapper} +import ch.epfl.bluebrain.nexus.ship.views.ViewWiring import io.circe.Decoder final class ProjectProcessor private ( projects: Projects, projectMapper: ProjectMapper, clock: EventClock, - uuidF: EventUUIDF + uuidF: EventUUIDF, + scopeInitializer: ScopeInitializer ) extends EventProcessor[ProjectEvent] { override def resourceType: EntityType = Projects.entityType @@ -44,7 +48,8 @@ final class ProjectProcessor private ( event match { case ProjectCreated(_, _, _, _, _, description, apiMappings, base, vocab, enforceSchema, _, _) => val fields = ProjectFields(description, apiMappings, Some(base), Some(vocab), enforceSchema) - projects.create(projectRef, fields) + projects.create(projectRef, fields) >> + scopeInitializer.initializeProject(projectRef) case ProjectUpdated(_, _, _, _, _, description, apiMappings, base, vocab, enforceSchema, _, _) => val fields = ProjectFields(description, apiMappings, Some(base), Some(vocab), enforceSchema) projects.update(projectRef, cRev, fields) @@ -70,15 +75,19 @@ object ProjectProcessor { private val logger = Logger[ProjectProcessor] def apply( fetchActiveOrg: FetchActiveOrganization, + fetchContext: FetchContext, + rcr: ResolverContextResolution, projectMapper: ProjectMapper, - config: EventLogConfig, + config: ShipConfig, clock: EventClock, xas: Transactors )(implicit - base: BaseUri + base: BaseUri, + jsonLdApi: JsonLdApi ): IO[ProjectProcessor] = for { - uuidF <- EventUUIDF.init() + uuidF <- EventUUIDF.init() + initializer <- ViewWiring.viewInitializer(fetchContext, rcr, config, clock, xas) } yield { val disableDeletion: ValidateProjectDeletion = (p: ProjectRef) => IO.raiseError(ProjectDeletionIsNotAllowed(p)) val projects = ProjectsImpl( @@ -86,10 +95,10 @@ object ProjectProcessor { disableDeletion, ScopeInitializer.noop, ApiMappings.empty, - config, + config.eventLog, xas, clock )(base, uuidF) - new ProjectProcessor(projects, projectMapper, clock, uuidF) + new ProjectProcessor(projects, projectMapper, clock, uuidF, initializer) } } diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/BlazegraphViewProcessor.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/BlazegraphViewProcessor.scala index dddbe98488..cd0d432a14 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/BlazegraphViewProcessor.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/BlazegraphViewProcessor.scala @@ -3,10 +3,10 @@ package ch.epfl.bluebrain.nexus.ship.views import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.Logger import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF +import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.BlazegraphViews import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.BlazegraphViewEvent._ import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.BlazegraphViewRejection.{IncorrectRev, ResourceAlreadyExists} -import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.{defaultViewId, BlazegraphViewEvent, BlazegraphViewValue, ViewResource} -import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.{BlazegraphViews, ValidateBlazegraphView} +import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.{defaultViewId, BlazegraphViewEvent} import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext @@ -45,16 +45,24 @@ class BlazegraphViewProcessor private ( event match { case e: BlazegraphViewCreated => e.id match { - case id if id == defaultViewId => views(event.uuid).flatMap(_.create(e.id, project, e.value)) + case id if id == defaultViewId => IO.unit // the default view is created on project creation case _ => views(event.uuid).flatMap(_.create(e.id, project, e.source)) } case e: BlazegraphViewUpdated => e.id match { - case id if id == defaultViewId => views(event.uuid).flatMap(_.update(e.id, project, cRev, e.value)) + case id if id == defaultViewId => IO.unit case _ => views(event.uuid).flatMap(_.update(e.id, project, cRev, e.source)) } - case e: BlazegraphViewDeprecated => views(event.uuid).flatMap(_.deprecate(e.id, project, cRev)) - case e: BlazegraphViewUndeprecated => views(event.uuid).flatMap(_.undeprecate(e.id, project, cRev)) + case e: BlazegraphViewDeprecated => + e.id match { + case id if id == defaultViewId => IO.unit + case _ => views(event.uuid).flatMap(_.deprecate(e.id, project, cRev)) + } + case e: BlazegraphViewUndeprecated => + e.id match { + case id if id == defaultViewId => IO.unit + case _ => views(event.uuid).flatMap(_.undeprecate(e.id, project, cRev)) + } case _: BlazegraphViewTagAdded => IO.unit // TODO: Can we tag? } }.redeemWith( @@ -81,22 +89,7 @@ object BlazegraphViewProcessor { )(implicit jsonLdApi: JsonLdApi ): BlazegraphViewProcessor = { - val noValidation = new ValidateBlazegraphView { - override def apply(value: BlazegraphViewValue): IO[Unit] = IO.unit - } - val prefix = "nexus" // TODO: use the config? - - val views = (uuid: UUID) => - BlazegraphViews( - fetchContext, - rcr, - noValidation, - (_: ViewResource) => IO.unit, - config, - prefix, - xas, - clock - )(jsonLdApi, UUIDF.fixed(uuid)) + val views = (uuid: UUID) => ViewWiring.blazegraphViews(fetchContext, rcr, config, clock, UUIDF.fixed(uuid), xas) new BlazegraphViewProcessor(views, projectMapper, clock) } diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/CompositeViewProcessor.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/CompositeViewProcessor.scala index 6d0714a09c..6508ee2807 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/CompositeViewProcessor.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/CompositeViewProcessor.scala @@ -2,11 +2,10 @@ package ch.epfl.bluebrain.nexus.ship.views import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.Logger -import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF +import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.CompositeViews +import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewEvent import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewEvent._ import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewRejection.{IncorrectRev, ResourceAlreadyExists} -import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.{CompositeViewEvent, CompositeViewValue} -import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.{CompositeViews, ValidateCompositeView} import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext @@ -20,7 +19,6 @@ import ch.epfl.bluebrain.nexus.ship.{EventClock, EventProcessor, ImportStatus, P import io.circe.Decoder import java.util.UUID -import scala.concurrent.duration.DurationInt class CompositeViewProcessor(views: UUID => IO[CompositeViews], projectMapper: ProjectMapper, clock: EventClock) extends EventProcessor[CompositeViewEvent] { @@ -39,6 +37,7 @@ class CompositeViewProcessor(views: UUID => IO[CompositeViews], projectMapper: P implicit val c: Caller = Caller(s, Set.empty) val cRev = event.rev - 1 val project = projectMapper.map(event.project) + event match { case e: CompositeViewCreated => views(event.uuid).flatMap(_.create(project, e.source)) case e: CompositeViewUpdated => views(event.uuid).flatMap(_.update(e.id, project, cRev, e.source)) @@ -70,23 +69,8 @@ object CompositeViewProcessor { )(implicit jsonLdApi: JsonLdApi ): CompositeViewProcessor = { - val noValidation = new ValidateCompositeView { - override def apply(uuid: UUID, value: CompositeViewValue): IO[Unit] = IO.unit - } - - val views = (uuid: UUID) => - CompositeViews( - fetchContext, - rcr, - noValidation, - 3.seconds, - config, - xas, - clock - )(jsonLdApi, UUIDF.fixed(uuid)) - + val views = ViewWiring.cvViews(fetchContext, rcr, config, clock, xas) new CompositeViewProcessor(views, projectMapper, clock) - } } diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ElasticSearchViewProcessor.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ElasticSearchViewProcessor.scala index 43b017ab35..14d1b6be6c 100644 --- a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ElasticSearchViewProcessor.scala +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ElasticSearchViewProcessor.scala @@ -2,16 +2,15 @@ package ch.epfl.bluebrain.nexus.ship.views import cats.effect.IO import ch.epfl.bluebrain.nexus.delta.kernel.Logger -import ch.epfl.bluebrain.nexus.delta.kernel.utils.{ClasspathResourceLoader, UUIDF} +import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF +import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.ElasticSearchViews import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ElasticSearchViewEvent._ import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ElasticSearchViewRejection.{IncorrectRev, ResourceAlreadyExists} -import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.{defaultViewId, ElasticSearchFiles, ElasticSearchViewEvent, ElasticSearchViewValue} -import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.{ElasticSearchViews, ValidateElasticSearchView} +import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.{defaultViewId, ElasticSearchViewEvent} import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi import ch.epfl.bluebrain.nexus.delta.sdk.identities.model.Caller import ch.epfl.bluebrain.nexus.delta.sdk.projects.FetchContext import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.ResolverContextResolution -import ch.epfl.bluebrain.nexus.delta.sdk.views.IndexingRev import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors import ch.epfl.bluebrain.nexus.delta.sourcing.config.EventLogConfig import ch.epfl.bluebrain.nexus.delta.sourcing.model.EntityType @@ -46,16 +45,24 @@ class ElasticSearchViewProcessor private ( event match { case e: ElasticSearchViewCreated => e.id match { - case id if id == defaultViewId => views(event.uuid).flatMap(_.create(e.id, project, e.value)) + case id if id == defaultViewId => IO.unit // the default view is created on project creation case _ => views(event.uuid).flatMap(_.create(e.id, project, e.source)) } case e: ElasticSearchViewUpdated => e.id match { - case id if id == defaultViewId => views(event.uuid).flatMap(_.update(e.id, project, cRev, e.value)) + case id if id == defaultViewId => IO.unit case _ => views(event.uuid).flatMap(_.update(e.id, project, cRev, e.source)) } - case e: ElasticSearchViewDeprecated => views(event.uuid).flatMap(_.deprecate(e.id, project, cRev)) - case e: ElasticSearchViewUndeprecated => views(event.uuid).flatMap(_.undeprecate(e.id, project, cRev)) + case e: ElasticSearchViewDeprecated => + e.id match { + case id if id == defaultViewId => IO.unit + case _ => views(event.uuid).flatMap(_.deprecate(e.id, project, cRev)) + } + case e: ElasticSearchViewUndeprecated => + e.id match { + case id if id == defaultViewId => IO.unit + case _ => views(event.uuid).flatMap(_.undeprecate(e.id, project, cRev)) + } case _: ElasticSearchViewTagAdded => IO.unit // TODO: Check if this is correct } }.redeemWith( @@ -82,30 +89,9 @@ object ElasticSearchViewProcessor { xas: Transactors )(implicit jsonLdApi: JsonLdApi - ): IO[ElasticSearchViewProcessor] = { - implicit val loader: ClasspathResourceLoader = ClasspathResourceLoader.withContext(getClass) - - val noValidation = new ValidateElasticSearchView { - override def apply(uuid: UUID, indexingRev: IndexingRev, v: ElasticSearchViewValue): IO[Unit] = IO.unit - } - val prefix = "nexus" // TODO: use the config? - val esFiles = ElasticSearchFiles.mk(loader) - - for { - files <- esFiles - views = (uuid: UUID) => - ElasticSearchViews( - fetchContext, - rcr, - noValidation, - config, - prefix, - xas, - files.defaultMapping, - files.defaultSettings, - clock - )(jsonLdApi, UUIDF.fixed(uuid)) - } yield new ElasticSearchViewProcessor(views, projectMapper, clock) + ): ElasticSearchViewProcessor = { + val views = (uuid: UUID) => ViewWiring.elasticSearchViews(fetchContext, rcr, config, clock, UUIDF.fixed(uuid), xas) + new ElasticSearchViewProcessor(views, projectMapper, clock) } } diff --git a/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ViewWiring.scala b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ViewWiring.scala new file mode 100644 index 0000000000..c198b36d3d --- /dev/null +++ b/ship/src/main/scala/ch/epfl/bluebrain/nexus/ship/views/ViewWiring.scala @@ -0,0 +1,135 @@ +package ch.epfl.bluebrain.nexus.ship.views + +import cats.effect.IO +import ch.epfl.bluebrain.nexus.delta.kernel.utils.{ClasspathResourceLoader, UUIDF} +import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.model.{BlazegraphViewValue, ViewResource} +import ch.epfl.bluebrain.nexus.delta.plugins.blazegraph.{BlazegraphScopeInitialization, BlazegraphViews, ValidateBlazegraphView} +import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.model.CompositeViewValue +import ch.epfl.bluebrain.nexus.delta.plugins.compositeviews.{CompositeViews, ValidateCompositeView} +import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.{ElasticSearchFiles, ElasticSearchViewValue} +import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.{ElasticSearchScopeInitialization, ElasticSearchViews, ValidateElasticSearchView} +import ch.epfl.bluebrain.nexus.delta.rdf.jsonld.api.JsonLdApi +import ch.epfl.bluebrain.nexus.delta.sdk.projects.{FetchContext, ScopeInitializationErrorStore} +import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.ResolverContextResolution +import ch.epfl.bluebrain.nexus.delta.sdk.views.IndexingRev +import ch.epfl.bluebrain.nexus.delta.sdk.{ScopeInitialization, ScopeInitializer} +import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors +import ch.epfl.bluebrain.nexus.delta.sourcing.config.EventLogConfig +import ch.epfl.bluebrain.nexus.ship.EventClock +import ch.epfl.bluebrain.nexus.ship.config.ShipConfig + +import java.util.UUID +import scala.concurrent.duration.DurationInt + +object ViewWiring { + + def elasticSearchViews( + fetchContext: FetchContext, + rcr: ResolverContextResolution, + config: EventLogConfig, + clock: EventClock, + uuidF: UUIDF, + xas: Transactors + )(implicit jsonLdApi: JsonLdApi) = { + implicit val loader: ClasspathResourceLoader = ClasspathResourceLoader.withContext(getClass) + val prefix = "nexus" // TODO: use the config? + + val noValidation = new ValidateElasticSearchView { + override def apply(uuid: UUID, indexingRev: IndexingRev, v: ElasticSearchViewValue): IO[Unit] = IO.unit + } + + ElasticSearchFiles.mk(loader).flatMap { files => + ElasticSearchViews( + fetchContext, + rcr, + noValidation, + config, + prefix, + xas, + files.defaultMapping, + files.defaultSettings, + clock + )(jsonLdApi, uuidF) + } + } + + def blazegraphViews( + fetchContext: FetchContext, + rcr: ResolverContextResolution, + config: EventLogConfig, + clock: EventClock, + uuidF: UUIDF, + xas: Transactors + )(implicit jsonLdApi: JsonLdApi) = { + val noValidation = new ValidateBlazegraphView { + override def apply(value: BlazegraphViewValue): IO[Unit] = IO.unit + } + val prefix = "nexus" // TODO: use the config? + BlazegraphViews( + fetchContext, + rcr, + noValidation, + (_: ViewResource) => IO.unit, + config, + prefix, + xas, + clock + )(jsonLdApi, uuidF) + } + + def cvViews( + fetchContext: FetchContext, + rcr: ResolverContextResolution, + config: EventLogConfig, + clock: EventClock, + xas: Transactors + )(implicit jsonLdApi: JsonLdApi) = { + val noValidation = new ValidateCompositeView { + override def apply(uuid: UUID, value: CompositeViewValue): IO[Unit] = IO.unit + } + (uuid: UUID) => + CompositeViews( + fetchContext, + rcr, + noValidation, + 3.seconds, // TODO: use the config? + config, + xas, + clock + )(jsonLdApi, UUIDF.fixed(uuid)) + } + + def viewInitializer( + fetchContext: FetchContext, + rcr: ResolverContextResolution, + config: ShipConfig, + clock: EventClock, + xas: Transactors + )(implicit jsonLdApi: JsonLdApi): IO[ScopeInitializer] = { + for { + esViews <- elasticSearchViews(fetchContext, rcr, config.eventLog, clock, UUIDF.random, xas) + bgViews <- blazegraphViews(fetchContext, rcr, config.eventLog, clock, UUIDF.random, xas) + } yield viewInitializer(esViews, bgViews, config, clock, xas) + } + + private def viewInitializer( + esViews: ElasticSearchViews, + bgViews: BlazegraphViews, + config: ShipConfig, + clock: EventClock, + xas: Transactors + ): ScopeInitializer = { + val viewInits = Set.empty[ScopeInitialization] + + new ElasticSearchScopeInitialization( + esViews, + config.serviceAccount.value, + config.viewDefaults.elasticsearch + ) + new BlazegraphScopeInitialization( + bgViews, + config.serviceAccount.value, + config.viewDefaults.blazegraph + ) + ScopeInitializer(viewInits, ScopeInitializationErrorStore.apply(xas, clock)) + } + +} diff --git a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/RunShipSuite.scala b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/RunShipSuite.scala index 6fe9cf147d..ea5a2142cc 100644 --- a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/RunShipSuite.scala +++ b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/RunShipSuite.scala @@ -3,15 +3,17 @@ package ch.epfl.bluebrain.nexus.ship import cats.effect.{IO, Resource} import cats.syntax.all._ import ch.epfl.bluebrain.nexus.delta.kernel.utils.ClasspathResourceLoader +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.projects.Projects import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.Resolvers import ch.epfl.bluebrain.nexus.delta.sdk.resources.Resources import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors import ch.epfl.bluebrain.nexus.delta.sourcing.model.EntityType import ch.epfl.bluebrain.nexus.delta.sourcing.offset.Offset -import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.Doobie.{PostgresPassword, PostgresUser, transactors} +import ch.epfl.bluebrain.nexus.delta.sourcing.postgres.Doobie.{transactors, PostgresPassword, PostgresUser} import ch.epfl.bluebrain.nexus.ship.ImportReport.Count -import ch.epfl.bluebrain.nexus.ship.RunShipSuite.{clearDB, expectedImportReport, getDistinctOrgProjects} +import ch.epfl.bluebrain.nexus.ship.RunShipSuite.{checkFor, clearDB, expectedImportReport, getDistinctOrgProjects} import ch.epfl.bluebrain.nexus.testkit.config.SystemPropertyOverride import ch.epfl.bluebrain.nexus.testkit.mu.NexusSuite import ch.epfl.bluebrain.nexus.testkit.postgres.PostgresContainer @@ -44,6 +46,15 @@ class RunShipSuite extends NexusSuite with RunShipSuite.Fixture { } yield () } + test("Run import and check for views") { + for { + importFile <- asPath("import/import.json") + _ <- RunShip.localShip.run(importFile, None).assertEquals(expectedImportReport) + _ <- checkFor("elasticsearch", nxv + "defaultElasticSearchIndex", xas).assertEquals(1) + _ <- checkFor("blazegraph", nxv + "defaultSparqlIndex", xas).assertEquals(1) + } yield () + } + test("Run import by providing the path to a directory") { for { importDirectory <- asPath("import/multi-part-import") @@ -95,6 +106,13 @@ object RunShipSuite { | SELECT DISTINCT org, project FROM scoped_events; """.stripMargin.query[(String, String)].to[List].transact(xas.read) + def checkFor(entityType: String, id: Iri, xas: Transactors): IO[Int] = + sql""" + | SELECT COUNT(*) FROM scoped_events + | WHERE type = $entityType + | AND id = ${id.toString} + """.stripMargin.query[Int].unique.transact(xas.read) + // The expected import report for the import.json file, as well as for the /import/multi-part-import directory val expectedImportReport: ImportReport = ImportReport( Offset.at(9999999L), diff --git a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfigSuite.scala b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfigSuite.scala index c663dc240e..b89fde37ae 100644 --- a/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfigSuite.scala +++ b/ship/src/test/scala/ch/epfl/bluebrain/nexus/ship/config/ShipConfigSuite.scala @@ -1,7 +1,9 @@ package ch.epfl.bluebrain.nexus.ship.config +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.{Label, ProjectRef} +import ch.epfl.bluebrain.nexus.ship.config.ShipConfigSuite.{defaultBgValues, defaultEsValues} import ch.epfl.bluebrain.nexus.testkit.mu.NexusSuite import eu.timepit.refined.types.string.NonEmptyString import fs2.aws.s3.models.Models.BucketName @@ -16,6 +18,12 @@ class ShipConfigSuite extends NexusSuite { ShipConfig.load(None).map(_.baseUri).assertEquals(expectedBaseUri) } + test("The defaults (name/description) for views should be correct") { + val config = ShipConfig.load(None) + config.map(_.viewDefaults.elasticsearch).assertEquals(defaultEsValues) >> + config.map(_.viewDefaults.blazegraph).assertEquals(defaultBgValues) + } + test("Default configuration should be overloaded by the external config") { val expectedBaseUri = BaseUri("https://bbp.epfl.ch", Label.unsafe("v1")) for { @@ -47,3 +55,9 @@ class ShipConfigSuite extends NexusSuite { } } + +object ShipConfigSuite { + private val defaultEsValues = + Defaults("Default Elasticsearch view", "An Elasticsearch view of all resources in the project.") + private val defaultBgValues = Defaults("Default Sparql view", "A Sparql view of all resources in the project.") +}