Skip to content

Commit

Permalink
PIN-4743: Improve getAgreementEServices endpoint query (#261)
Browse files Browse the repository at this point in the history
  • Loading branch information
galales authored Mar 28, 2024
1 parent d03cdb6 commit 73f9bcb
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1293,7 +1293,7 @@ final case class AgreementApiServiceImpl(
toEntityMarshallerProblem: ToEntityMarshaller[Problem]
): Route = authorize(ADMIN_ROLE, API_ROLE, SECURITY_ROLE, SUPPORT_ROLE) {
val operationLabel =
s"Retrieving EServices with consumers $consumersIds, producers $producersIds"
s"Retrieving EServices with consumers $consumersIds, producers $producersIds, states $states, offset $offset, limit $limit"
logger.info(operationLabel)

val result: Future[CompactEServices] = for {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
package it.pagopa.interop.agreementprocess.common.readmodel

import it.pagopa.interop.agreementprocess.common.Adapters._
import it.pagopa.interop.agreementmanagement.model.agreement.{PersistentAgreement, PersistentAgreementState}
import it.pagopa.interop.agreementmanagement.model.persistence.JsonFormats._
import it.pagopa.interop.agreementprocess.api.impl._
import it.pagopa.interop.agreementprocess.common.Adapters._
import it.pagopa.interop.agreementprocess.model.{AgreementState, CompactEService, CompactOrganization}
import it.pagopa.interop.catalogmanagement.{model => CatalogManagement}
import it.pagopa.interop.commons.cqrs.service.ReadModelService
import it.pagopa.interop.agreementprocess.model.{AgreementState, CompactEService}
import scala.concurrent.{ExecutionContext, Future}
import org.mongodb.scala.Document
import org.mongodb.scala.bson.conversions.Bson
import org.mongodb.scala.model.Accumulators.first
import org.mongodb.scala.model.Aggregates.{`match`, count, lookup, project, sort, unwind, addFields, group}
import org.mongodb.scala.model.{Filters, Field, UnwindOptions}
import org.mongodb.scala.model.Aggregates._
import org.mongodb.scala.model.Projections.{computed, fields, include}
import org.mongodb.scala.model.Sorts.ascending
import it.pagopa.interop.agreementmanagement.model.persistence.JsonFormats._
import it.pagopa.interop.catalogmanagement.{model => CatalogManagement}
import it.pagopa.interop.agreementprocess.model.CompactOrganization
import it.pagopa.interop.agreementprocess.api.impl._
import org.mongodb.scala.model.{Field, Filters, UnwindOptions}

import java.util.UUID
import scala.concurrent.{ExecutionContext, Future}

object ReadModelAgreementQueries extends ReadModelQuery {

Expand Down Expand Up @@ -298,23 +298,6 @@ object ReadModelAgreementQueries extends ReadModelQuery {
} yield PaginatedResult(results = agreements, totalCount = count.headOption.map(_.totalCount).getOrElse(0))
}

private def listEServiceAgreementsFilters(
name: Option[String],
consumersIds: List[String],
producersIds: List[String],
states: List[AgreementState]
): Bson = {
val nameFilter = name.map(n => Filters.regex("eservices.data.name", escape(n), "i"))
val consumersIdsFilter = mapToVarArgs(consumersIds.map(Filters.eq("data.consumerId", _)))(Filters.or)
val producersIdsFilter = mapToVarArgs(producersIds.map(Filters.eq("data.producerId", _)))(Filters.or)
val statesFilter = listStatesFilter(states)

mapToVarArgs(nameFilter.toList ++ consumersIdsFilter.toList ++ producersIdsFilter.toList ++ statesFilter.toList)(
Filters.and
)
.getOrElse(Filters.empty())
}

def listEServicesAgreements(
eServiceName: Option[String],
consumersIds: List[String],
Expand All @@ -323,45 +306,42 @@ object ReadModelAgreementQueries extends ReadModelQuery {
offset: Int,
limit: Int
)(implicit ec: ExecutionContext, readModel: ReadModelService): Future[PaginatedResult[CompactEService]] = {
val query: Bson = listEServiceAgreementsFilters(eServiceName, consumersIds, producersIds, states)
val filterPipeline: Seq[Bson] = Seq(
lookup("eservices", "data.eserviceId", "data.id", "eservices"),
unwind("$eservices", UnwindOptions().preserveNullAndEmptyArrays(false)),
`match`(query),
group(
Document("""{ "_id": "$data.eserviceId" } """),
first("eserviceId", "$data.eserviceId"),
first("eserviceName", "$eservices.data.name")
)
val agreementQuery: Bson = listAgreementsFilters(
eServicesIds = Nil,
consumersIds = consumersIds,
producersIds = producersIds,
descriptorsIds = Nil,
states = states,
showOnlyUpgradeable = false
)

def eserviceQuery(eserviceIds: Seq[String]): Bson =
`match`(
mapToVarArgs(
eServiceName.map(n => Filters.regex("data.name", escape(n), "i")).toList :+
Filters.in("data.id", eserviceIds: _*)
)(Filters.and).getOrElse(Filters.empty())
)

for {
// Using aggregate to perform case insensitive sorting
// N.B.: Required because DocumentDB does not support collation
agreements <- readModel.aggregate[CompactEService](
"agreements",
filterPipeline ++
Seq(
project(
fields(
computed("data", Document("""{ "id": "$eserviceId", "name": "$eserviceName" }""")),
computed("lowerName", Document("""{ "$toLower" : "$eserviceName" }"""))
)
),
sort(ascending("lowerName"))
agreementEservicesIds <- readModel
.distinct[String]("agreements", "data.eserviceId", agreementQuery)
eservicesFilters = eserviceQuery(agreementEservicesIds)
eservices <- readModel.aggregate[CompactEService](
"eservices",
Seq(
eservicesFilters,
project(
fields(
computed("data", Document("""{ "id": "$data.id", "name": "$data.name" }""")),
computed("lowerName", Document("""{ "$toLower" : "$data.name" }"""))
)
),
sort(ascending("lowerName"))
),
offset = offset,
limit = limit
)
// Note: This could be obtained using $facet function (avoiding to execute the query twice),
// but it is not supported by DocumentDB
count <- readModel.aggregate[TotalCountResult](
"agreements",
filterPipeline ++
Seq(count("totalCount"), project(computed("data", Document("""{ "totalCount" : "$totalCount" }""")))),
offset = 0,
limit = Int.MaxValue
)
} yield PaginatedResult(results = agreements, totalCount = count.headOption.map(_.totalCount).getOrElse(0))
} yield PaginatedResult(results = eservices, totalCount = agreementEservicesIds.size)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package it.pagopa.interop.agreementprocess.common.readmodel

import it.pagopa.interop.commons.queue.message.Message.uuidFormat
import spray.json.DefaultJsonProtocol._
import spray.json.RootJsonFormat

import java.util.UUID

final case class ReadModelId(id: UUID)

object ReadModelId {
implicit val rmiFormat: RootJsonFormat[ReadModelId] = jsonFormat1(ReadModelId.apply)
}

0 comments on commit 73f9bcb

Please sign in to comment.