From 861585b751245381c9b4f9ad1183711882637651 Mon Sep 17 00:00:00 2001 From: Daniel Bell Date: Wed, 17 Jan 2024 13:20:09 +0100 Subject: [PATCH] Simplify resources search to only accept keywords --- .../elasticsearch/client/QueryBuilder.scala | 2 +- .../model/ResourcesSearchParams.scala | 17 ++++------------- .../routes/ElasticSearchViewsDirectives.scala | 18 ++++++++++++++---- .../nexus/tests/kg/files/FilesSpec.scala | 4 ++-- 4 files changed, 21 insertions(+), 20 deletions(-) diff --git a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/client/QueryBuilder.scala b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/client/QueryBuilder.scala index c9dba11ccc..a455bf92a5 100644 --- a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/client/QueryBuilder.scala +++ b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/client/QueryBuilder.scala @@ -83,7 +83,7 @@ final case class QueryBuilder private[client] (private val query: JsonObject) { params.updatedBy.map(term(nxv.updatedBy.prefix, _)) ++ range(nxv.updatedAt.prefix, params.updatedAt) ++ params.tag.map(term(nxv.tags.prefix, _)) ++ - params.fileUserMetadata.toList.flatMap(_.keywords).map { case (key, value) => + params.keywords.map { case (key, value) => term(s"keywords.$key", value) }, mustNotTerms = typesTerms(params.typeOperator.negate, excludeTypes), diff --git a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ResourcesSearchParams.scala b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ResourcesSearchParams.scala index 0e1dfbdd3a..5d2e7c50de 100644 --- a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ResourcesSearchParams.scala +++ b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/model/ResourcesSearchParams.scala @@ -2,17 +2,15 @@ package ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model import akka.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} import ch.epfl.bluebrain.nexus.delta.kernel.search.TimeRange -import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ResourcesSearchParams.{FileUserMetadata, Type, TypeOperator} +import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ResourcesSearchParams.{Type, TypeOperator} import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.QueryParamsUnmarshalling.{iriFromStringUnmarshaller, iriVocabFromStringUnmarshaller => iriUnmarshaller} import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ProjectContext import ch.epfl.bluebrain.nexus.delta.sourcing.model.Identity.Subject import ch.epfl.bluebrain.nexus.delta.sourcing.model.Tag.UserTag import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ResourceRef} +import io.circe.Decoder import io.circe.generic.semiauto.deriveDecoder -import io.circe.{parser, Decoder} - -import scala.util.{Failure, Success} /** * Search parameters for any generic resource type. @@ -53,7 +51,7 @@ final case class ResourcesSearchParams( updatedAt: TimeRange = TimeRange.Anytime, types: List[Type] = List.empty, typeOperator: TypeOperator = TypeOperator.Or, - fileUserMetadata: Option[FileUserMetadata] = None, + keywords: Map[Label, String] = Map.empty, schema: Option[ResourceRef] = None, q: Option[String] = None, tag: Option[UserTag] = None @@ -71,14 +69,7 @@ object ResourcesSearchParams { object FileUserMetadata { - implicit val decoder: Decoder[FileUserMetadata] = deriveDecoder[FileUserMetadata] - implicit val fromStringUnmarshaller: FromStringUnmarshaller[FileUserMetadata] = - Unmarshaller.strict[String, FileUserMetadata] { str => - parser.parse(str).flatMap(_.as[FileUserMetadata]).toTry match { - case Failure(exception) => throw exception - case Success(value) => value - } - } + implicit val decoder: Decoder[FileUserMetadata] = deriveDecoder[FileUserMetadata] } sealed trait TypeOperator extends Product with Serializable { diff --git a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/routes/ElasticSearchViewsDirectives.scala b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/routes/ElasticSearchViewsDirectives.scala index 494639320a..5bc9010670 100644 --- a/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/routes/ElasticSearchViewsDirectives.scala +++ b/delta/plugins/elasticsearch/src/main/scala/ch/epfl/bluebrain/nexus/delta/plugins/elasticsearch/routes/ElasticSearchViewsDirectives.scala @@ -6,14 +6,15 @@ import akka.http.scaladsl.server.{Directive, Directive0, Directive1, MalformedQu import akka.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ResourcesSearchParams import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ResourcesSearchParams.TypeOperator.Or -import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ResourcesSearchParams.{FileUserMetadata, Type, TypeOperator} +import ch.epfl.bluebrain.nexus.delta.plugins.elasticsearch.model.ResourcesSearchParams.{Type, TypeOperator} import ch.epfl.bluebrain.nexus.delta.rdf.IriOrBNode.Iri import ch.epfl.bluebrain.nexus.delta.sdk.directives.{DeltaSchemeDirectives, UriDirectives} import ch.epfl.bluebrain.nexus.delta.sdk.marshalling.QueryParamsUnmarshalling.IriBase import ch.epfl.bluebrain.nexus.delta.sdk.model.BaseUri import ch.epfl.bluebrain.nexus.delta.sdk.model.search.{Sort, SortList} import ch.epfl.bluebrain.nexus.delta.sdk.projects.model.ProjectContext -import ch.epfl.bluebrain.nexus.delta.sourcing.model.ResourceRef +import ch.epfl.bluebrain.nexus.delta.sourcing.model.{Label, ResourceRef} +import io.circe.parser trait ElasticSearchViewsDirectives extends UriDirectives { @@ -29,8 +30,17 @@ trait ElasticSearchViewsDirectives extends UriDirectives { private def types(implicit um: FromStringUnmarshaller[Type]): Directive1[List[Type]] = parameter("type".as[Type].*).map(_.toList.reverse) - private def userFileMetadata: Directive1[Option[FileUserMetadata]] = - parameter("metadata".as[FileUserMetadata].?) + implicit val keywordsFromStringUnmarshaller: FromStringUnmarshaller[Map[Label, String]] = Unmarshaller.strict { + string => + parser.parse(string).flatMap(_.as[Map[Label, String]]) match { + case Left(e) => throw e + case Right(value) => value + } + } + + private def userFileMetadata: Directive1[Map[Label, String]] = { + parameter("keywords".as[Map[Label, String]].withDefault(Map.empty[Label, String])) + } private def typeOperator(implicit um: FromStringUnmarshaller[TypeOperator]): Directive1[TypeOperator] = { parameter("typeOperator".as[TypeOperator].?[TypeOperator](Or)) diff --git a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/files/FilesSpec.scala b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/files/FilesSpec.scala index 1349c28362..12b5902b45 100644 --- a/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/files/FilesSpec.scala +++ b/tests/src/test/scala/ch/epfl/bluebrain/nexus/tests/kg/files/FilesSpec.scala @@ -82,9 +82,9 @@ class FilesSpec extends BaseIntegrationSpec { } private def queryForFilesWithKeywords(keywords: (String, String)*): IO[List[Json]] = { - val metadata = UrlUtils.encode(Json.obj("keywords" := keywords.toMap.asJson).noSpaces) + val encodedKeywords = UrlUtils.encode(keywords.toMap.asJson.noSpaces) deltaClient - .getJson[Json](s"/files/$projectRef?metadata=$metadata", Writer) + .getJson[Json](s"/files/$projectRef?keywords=$encodedKeywords", Writer) .map { json => json.hcursor.downField("_results").as[List[Json]].rightValue }