Skip to content

Commit

Permalink
Run queries manually
Browse files Browse the repository at this point in the history
  • Loading branch information
dantb committed Sep 26, 2023
1 parent b8ff843 commit defb812
Show file tree
Hide file tree
Showing 5 changed files with 58 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import kamon.instrumentation.akka.http.TracingDirectives.operationName
import monix.execution.Scheduler

import scala.annotation.nowarn
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.OrganizationDeleter

/**
* The organization routes.
Expand All @@ -47,6 +48,7 @@ import scala.annotation.nowarn
final class OrganizationsRoutes(
identities: Identities,
organizations: Organizations,
orgDeleter: OrganizationDeleter,
aclCheck: AclCheck,
schemeDirectives: DeltaSchemeDirectives
)(implicit
Expand Down Expand Up @@ -116,14 +118,16 @@ final class OrganizationsRoutes(
// Deprecate organization
delete {
authorizeFor(id, orgs.write).apply {
parameter("rev".as[Int], "prune".?(false)) {
parameter("rev".as[Int].?, "prune".?(false)) {
case (_, true) =>
// TODO do we need rev for deletion? Or just delete everything?
authorizeFor(id, orgs.delete).apply {
emit(organizations.delete(id).mapValue(_.metadata))
emit(orgDeleter.deleteIfEmpty(id).leftMap[OrganizationRejection](_ => OrganizationRejection.OrganizationNonEmpty(id)))
}
case (rev, false) =>
case (Some(rev), false) =>
emit(organizations.deprecate(id, rev).mapValue(_.metadata))
case (None, false) =>
complete(StatusCodes.BadRequest)
}
}
}
Expand Down Expand Up @@ -162,6 +166,7 @@ object OrganizationsRoutes {
def apply(
identities: Identities,
organizations: Organizations,
orgDeleter: OrganizationDeleter,
aclCheck: AclCheck,
schemeDirectives: DeltaSchemeDirectives
)(implicit
Expand All @@ -171,6 +176,6 @@ object OrganizationsRoutes {
cr: RemoteContextResolution,
ordering: JsonKeyOrdering
): Route =
new OrganizationsRoutes(identities, organizations, aclCheck, schemeDirectives).routes
new OrganizationsRoutes(identities, organizations, orgDeleter, aclCheck, schemeDirectives).routes

}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors
import izumi.distage.model.definition.{Id, ModuleDef}
import monix.bio.UIO
import monix.execution.Scheduler
import ch.epfl.bluebrain.nexus.delta.sdk.projects.Projects
import ch.epfl.bluebrain.nexus.delta.sdk.acls.Acls
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.OrganizationDeleter

/**
* Organizations module wiring config.
Expand All @@ -32,35 +31,36 @@ object OrganizationsModule extends ModuleDef {

make[Organizations].from {
(
projects: Projects,
acls: Acls,
config: AppConfig,
scopeInitializations: Set[ScopeInitialization],
clock: Clock[UIO],
uuidF: UUIDF,
xas: Transactors
) =>
OrganizationsImpl(
projects,
acls,
scopeInitializations,
config.organizations,
xas
)(clock, uuidF)
}

make[OrganizationDeleter].from {
(xas: Transactors) => OrganizationDeleter(xas)
}

make[OrganizationsRoutes].from {
(
identities: Identities,
organizations: Organizations,
orgDeleter: OrganizationDeleter,
cfg: AppConfig,
aclCheck: AclCheck,
schemeDirectives: DeltaSchemeDirectives,
s: Scheduler,
cr: RemoteContextResolution @Id("aggregate"),
ordering: JsonKeyOrdering
) =>
new OrganizationsRoutes(identities, organizations, aclCheck, schemeDirectives)(
new OrganizationsRoutes(identities, organizations,orgDeleter, aclCheck, schemeDirectives)(
cfg.http.baseUri,
cfg.organizations.pagination,
s,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,53 +1,53 @@
package ch.epfl.bluebrain.nexus.delta.sdk.organizations

import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination
import ch.epfl.bluebrain.nexus.delta.sdk.ProjectResource
import ch.epfl.bluebrain.nexus.delta.sdk.acls.PurgeAcl
import ch.epfl.bluebrain.nexus.delta.sdk.acls.model.AclAddress
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchParams
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.OrganizationsImpl
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationRejection
import ch.epfl.bluebrain.nexus.delta.sdk.projects.ListProjects
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Label
import monix.bio.IO
import monix.bio.UIO

import ch.epfl.bluebrain.nexus.delta.sdk.acls.Acls
import ch.epfl.bluebrain.nexus.delta.sourcing.model.EntityType
import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode
import ch.epfl.bluebrain.nexus.delta.sourcing.Transactors

import cats.syntax.all._
import ch.epfl.bluebrain.nexus.delta.sourcing.implicits._
import doobie.ConnectionIO
import doobie.implicits._
import monix.bio.Task

trait OrganizationDeleter {
def deleteIfEmpty(org: Label): IO[OrganizationRejection.OrganizationNonEmpty, Unit]
def deleteIfEmpty(id: Label): Task[Unit]
}

object OrganizationDeleter {

def apply(
projects: ListProjects,
acls: PurgeAcl,
orgs: OrganizationsImpl.OrganizationsLog
): OrganizationDeleter = {
val delete = deleteIfEmpty(projects, acls, orgs)(_)
org => delete(org)
def apply(xas: Transactors): OrganizationDeleter = new OrganizationDeleter {

def deleteIfEmpty(id: Label): Task[Unit] =
for {
orgIsEmpty <- orgIsEmpty(id)
_ <- if (orgIsEmpty) deleteAll(id)
else Task.raiseError(new Exception(s"Cannot delete non-empty organization $id"))
} yield ()

def deleteAll(id: Label): Task[Unit] =
List("global_events", "global_states").traverse(deleteFromTable(id, _)).transact(xas.write).void

def deleteFromTable(id: Label, table: String): ConnectionIO[Unit] =
for {
_ <- delete(Organizations.encodeId(id), Organizations.entityType, table)
_ <- delete(Acls.encodeId(AclAddress.fromOrg(id)), Acls.entityType, table)
} yield ()

def delete(id: IriOrBNode.Iri, tpe: EntityType, table: String): ConnectionIO[Unit] =
sql"""DELETE FROM $table WHERE type = $tpe AND id = $id""".update.run.void

def orgIsEmpty(id: Label): Task[Boolean] =
sql"""SELECT type from scoped_events WHERE org = $id LIMIT 1"""
.query[Label]
.option
.map(_.isEmpty)
.transact(xas.read)
}

private val pagination = Pagination.FromPagination(from = 0, size = 1)

private val ordering: Ordering[ProjectResource] = Ordering.by(_.updatedAt)

private def params(id: Label): SearchParams.ProjectSearchParams =
SearchParams.ProjectSearchParams(
organization = Some(id),
filter = _ => UIO.pure(true)
)

def deleteIfEmpty(
projects: ListProjects,
acls: PurgeAcl,
orgs: OrganizationsImpl.OrganizationsLog
)(id: Label): IO[OrganizationRejection.OrganizationNonEmpty, Unit] =
for {
orgIsEmpty <- projects.list(pagination, params(id), ordering).map(_.results.isEmpty)
// TODO: would rather this all be done in one transaction but it will require
// some refactoring - what do you think?
_ <- if (orgIsEmpty) acls.purge(AclAddress.fromOrg(id)) *> orgs.delete(id)
else IO.raiseError(OrganizationRejection.OrganizationNonEmpty(id))
} yield ()

}
Original file line number Diff line number Diff line change
Expand Up @@ -73,20 +73,6 @@ trait Organizations {
rev: Int
)(implicit caller: Subject): IO[OrganizationRejection, OrganizationResource]

/**
* Delete an organization.
*
* @param label
* label of the organization to delete
* @param rev
* latest known revision
* @param caller
* a reference to the subject that initiated the action
*/
def delete(
label: Label
)(implicit caller: Subject): IO[OrganizationRejection, OrganizationResource]

/**
* Fetch an organization at the current revision by label.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import ch.epfl.bluebrain.nexus.delta.kernel.search.Pagination
import ch.epfl.bluebrain.nexus.delta.kernel.utils.UUIDF
import ch.epfl.bluebrain.nexus.delta.sdk.OrganizationResource
import ch.epfl.bluebrain.nexus.delta.sdk.ScopeInitialization
import ch.epfl.bluebrain.nexus.delta.sdk.acls.PurgeAcl
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchParams
import ch.epfl.bluebrain.nexus.delta.sdk.model.search.SearchResults
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.Organizations.entityType
Expand All @@ -17,7 +16,6 @@ import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationEvent
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationRejection
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationRejection._
import ch.epfl.bluebrain.nexus.delta.sdk.organizations.model.OrganizationState
import ch.epfl.bluebrain.nexus.delta.sdk.projects.ListProjects
import ch.epfl.bluebrain.nexus.delta.sdk.syntax._
import ch.epfl.bluebrain.nexus.delta.sourcing._
import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject
Expand All @@ -27,7 +25,6 @@ import monix.bio.UIO

final class OrganizationsImpl private (
log: OrganizationsLog,
deleter: OrganizationDeleter,
scopeInitializations: Set[ScopeInitialization]
) extends Organizations {

Expand Down Expand Up @@ -58,13 +55,6 @@ final class OrganizationsImpl private (
)(implicit caller: Subject): IO[OrganizationRejection, OrganizationResource] =
eval(DeprecateOrganization(label, rev, caller)).span("deprecateOrganization")

override def delete(
label: Label
)(implicit caller: Subject): IO[OrganizationRejection, OrganizationResource] =
(log
.stateOr(label, OrganizationNotFound(label))
.map(_.toResource) <* deleter.deleteIfEmpty(label)).span("deleteOrganization")

override def fetch(label: Label): IO[OrganizationNotFound, OrganizationResource] =
log.stateOr(label, OrganizationNotFound(label)).map(_.toResource).span("fetchOrganization")

Expand Down Expand Up @@ -98,21 +88,17 @@ object OrganizationsImpl {
GlobalEventLog[Label, OrganizationState, OrganizationCommand, OrganizationEvent, OrganizationRejection]

def apply(
projects: ListProjects,
acls: PurgeAcl,
scopeInitializations: Set[ScopeInitialization],
config: OrganizationsConfig,
xas: Transactors
)(implicit
clock: Clock[UIO] = IO.clock,
uuidf: UUIDF
): Organizations = {
val log = GlobalEventLog(Organizations.definition, config.eventLog, xas)
): Organizations =
new OrganizationsImpl(
log,
OrganizationDeleter(projects, acls, log),
GlobalEventLog(Organizations.definition, config.eventLog, xas),
scopeInitializations
)
}


}

0 comments on commit defb812

Please sign in to comment.