Skip to content

Commit

Permalink
Patch resource types in resolver events in the import batch (#5040)
Browse files Browse the repository at this point in the history
Resolvers can be conditionally applied to a subset of types. When those types start by a prefix, those should be patched
  • Loading branch information
shinyhappydan authored Jun 25, 2024
1 parent da16089 commit ed9f49e
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ object RunShip {
fileSelf = FileSelf(originalProjectContext)(originalBaseUri)
sourcePatcher = SourcePatcher(fileSelf, projectMapper, iriPatcher, targetBaseUri, eventClock, xas, config)
projectProcessor <- ProjectProcessor(fetchActiveOrg, fetchContext, rcr, originalProjectContext, projectMapper, iriPatcher, config, eventClock, xas)(targetBaseUri, jsonLdApi)
resolverProcessor = ResolverProcessor(fetchContext, projectMapper, eventLogConfig, eventClock, xas)
resolverProcessor = ResolverProcessor(fetchContext, projectMapper, iriPatcher, eventLogConfig, eventClock, xas)
schemaProcessor = SchemaProcessor(schemaLog, fetchContext, schemaImports, rcr, projectMapper, sourcePatcher, eventClock)
resourceProcessor = ResourceProcessor(resourceLog, rcr, projectMapper, fetchContext, sourcePatcher, iriPatcher, config.resourceTypesToIgnore, eventClock)
viewPatcher = new ViewPatcher(projectMapper, iriPatcher)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ 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, Identity}
import ch.epfl.bluebrain.nexus.ship.resolvers.ResolverProcessor.{logger, patchValue}
import ch.epfl.bluebrain.nexus.ship.{EventClock, EventProcessor, ImportStatus, ProjectMapper}
import ch.epfl.bluebrain.nexus.ship.{EventClock, EventProcessor, ImportStatus, IriPatcher, ProjectMapper}
import io.circe.Decoder

class ResolverProcessor private (resolvers: Resolvers, projectMapper: ProjectMapper, clock: EventClock)
extends EventProcessor[ResolverEvent] {
class ResolverProcessor private (
resolvers: Resolvers,
projectMapper: ProjectMapper,
iriPatcher: IriPatcher,
clock: EventClock
) extends EventProcessor[ResolverEvent] {
override def resourceType: EntityType = Resolvers.entityType

override def decoder: Decoder[ResolverEvent] = ResolverEvent.serializer.codec
Expand All @@ -40,11 +44,11 @@ class ResolverProcessor private (resolvers: Resolvers, projectMapper: ProjectMap
event match {
case ResolverCreated(_, _, value, _, _, _, _) =>
implicit val caller: Caller = Caller(s, identities(value))
val patched = patchValue(value, projectMapper)
val patched = patchValue(value, projectMapper, iriPatcher)
resolvers.create(id, projectRef, patched)
case ResolverUpdated(_, _, value, _, _, _, _) =>
implicit val caller: Caller = Caller(s, identities(value))
val patched = patchValue(value, projectMapper)
val patched = patchValue(value, projectMapper, iriPatcher)
resolvers.update(id, projectRef, cRev, patched)
case _: ResolverTagAdded =>
// Tags have been removed
Expand Down Expand Up @@ -76,22 +80,24 @@ object ResolverProcessor {

private val logger = Logger[ResolverProcessor]

def patchValue(value: ResolverValue, projectMapper: ProjectMapper): ResolverValue =
def patchValue(value: ResolverValue, projectMapper: ProjectMapper, iriPatcher: IriPatcher): ResolverValue =
value match {
case ip: InProjectValue => ip
case cp: CrossProjectValue =>
val mappedProjects = cp.projects.map(projectMapper.map)
cp.copy(projects = mappedProjects)
val mappedProjects = cp.projects.map(projectMapper.map)
val mappedResourceTypes = cp.resourceTypes.map(iriPatcher.apply)
cp.copy(projects = mappedProjects, resourceTypes = mappedResourceTypes)
}

def apply(
fetchContext: FetchContext,
projectMapper: ProjectMapper,
iriPatcher: IriPatcher,
config: EventLogConfig,
clock: EventClock,
xas: Transactors
)(implicit api: JsonLdApi): ResolverProcessor = {
val resolvers = ResolverWiring.resolvers(fetchContext, config, clock, xas)
new ResolverProcessor(resolvers, projectMapper, clock)
new ResolverProcessor(resolvers, projectMapper, iriPatcher, clock)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package ch.epfl.bluebrain.nexus.ship.resolvers

import cats.data.NonEmptyList
import ch.epfl.bluebrain.nexus.delta.rdf.Vocabulary.nxv
import ch.epfl.bluebrain.nexus.delta.rdf.syntax.iriStringContextSyntax
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.ResolverValue.{CrossProjectValue, InProjectValue}
import ch.epfl.bluebrain.nexus.delta.sdk.resolvers.model.{IdentityResolution, Priority}
import ch.epfl.bluebrain.nexus.delta.sourcing.model.ProjectRef
import ch.epfl.bluebrain.nexus.ship.ProjectMapper
import ch.epfl.bluebrain.nexus.ship.{IriPatcher, ProjectMapper}
import ch.epfl.bluebrain.nexus.testkit.mu.NexusSuite

class ResolverProcessorSuite extends NexusSuite {
Expand All @@ -15,29 +16,39 @@ class ResolverProcessorSuite extends NexusSuite {

private val projectMapper = ProjectMapper(Map(originalProject -> targetProject))

private val originalPrefix = iri"https://bbp.epfl.ch/"
private val targetPrefix = iri"https:/openbrainplatform.com/"

private val iriPatcher = IriPatcher(originalPrefix, targetPrefix, Map(originalProject -> targetProject))

private val priority = Priority.unsafe(42)

test("Patching does not affect in project resolvers") {
val original = InProjectValue(priority)

val obtained = ResolverProcessor.patchValue(original, projectMapper)
val obtained = ResolverProcessor.patchValue(original, projectMapper, iriPatcher)
assertEquals(obtained, original)
}

test("Patching a cross project resolver") {
val unpatchedProject = ProjectRef.unsafe("neurosciencegraph", "datamodels")
val originalProjects = NonEmptyList.of(unpatchedProject, originalProject)
val originalType = originalPrefix / originalProject.organization.value / originalProject.project.value / "Type"
val original = CrossProjectValue(
Some("My resolver"),
Some("My description"),
priority,
Set(nxv + "Schema"),
Set(nxv + "Schema", originalType),
originalProjects,
IdentityResolution.UseCurrentCaller
)

val expected = original.copy(projects = NonEmptyList.of(unpatchedProject, targetProject))
val obtained = ResolverProcessor.patchValue(original, projectMapper)
val expected = original.copy(
projects = NonEmptyList.of(unpatchedProject, targetProject),
resourceTypes =
Set(nxv + "Schema", targetPrefix / targetProject.organization.value / targetProject.project.value / "Type")
)
val obtained = ResolverProcessor.patchValue(original, projectMapper, iriPatcher)
assertEquals(obtained, expected)
}

Expand Down

0 comments on commit ed9f49e

Please sign in to comment.