diff --git a/modules/search-query/src/main/scala/io/renku/search/query/Field.scala b/modules/search-query/src/main/scala/io/renku/search/query/Field.scala index 65d855aa..96ae84a2 100644 --- a/modules/search-query/src/main/scala/io/renku/search/query/Field.scala +++ b/modules/search-query/src/main/scala/io/renku/search/query/Field.scala @@ -30,6 +30,7 @@ enum Field: case Type case Role case Keyword + case Namespace val name: String = Strings.lowerFirst(productPrefix) diff --git a/modules/search-query/src/main/scala/io/renku/search/query/FieldTerm.scala b/modules/search-query/src/main/scala/io/renku/search/query/FieldTerm.scala index 33cf9339..2820821d 100644 --- a/modules/search-query/src/main/scala/io/renku/search/query/FieldTerm.scala +++ b/modules/search-query/src/main/scala/io/renku/search/query/FieldTerm.scala @@ -20,6 +20,7 @@ package io.renku.search.query import cats.data.NonEmptyList +import io.renku.search.model.Namespace import io.renku.search.model.projects.Visibility import io.renku.search.model.{EntityType, Keyword, MemberRole} @@ -39,6 +40,8 @@ enum FieldTerm(val field: Field, val cmp: Comparison): extends FieldTerm(Field.Role, Comparison.Is) case KeywordIs(values: NonEmptyList[Keyword]) extends FieldTerm(Field.Keyword, Comparison.Is) + case NamespaceIs(values: NonEmptyList[Namespace]) + extends FieldTerm(Field.Namespace, Comparison.Is) private[query] def asString = val value = this match @@ -55,6 +58,7 @@ enum FieldTerm(val field: Field, val cmp: Comparison): case CreatedByIs(values) => FieldTerm.nelToString(values) case RoleIs(values) => FieldTerm.nelToString(values.map(_.name)) case KeywordIs(values) => FieldTerm.nelToString(values.map(_.value)) + case NamespaceIs(values) => FieldTerm.nelToString(values.map(_.value)) s"${field.name}${cmp.asString}${value}" diff --git a/modules/search-query/src/main/scala/io/renku/search/query/parse/QueryParser.scala b/modules/search-query/src/main/scala/io/renku/search/query/parse/QueryParser.scala index f19d0b10..6f4b2089 100644 --- a/modules/search-query/src/main/scala/io/renku/search/query/parse/QueryParser.scala +++ b/modules/search-query/src/main/scala/io/renku/search/query/parse/QueryParser.scala @@ -21,8 +21,8 @@ package io.renku.search.query.parse import cats.data.NonEmptyList import cats.parse.{Parser as P, Parser0 as P0} +import io.renku.search.model.* import io.renku.search.model.projects.Visibility -import io.renku.search.model.{EntityType, Keyword, MemberRole} import io.renku.search.query.* private[query] object QueryParser { @@ -106,6 +106,7 @@ private[query] object QueryParser { ((field <* is) ~ values).map { case (f, v) => f match case Field.Name => FieldTerm.NameIs(v) + case Field.Namespace => FieldTerm.NamespaceIs(v.map(Namespace(_))) case Field.Id => FieldTerm.IdIs(v) case Field.Slug => FieldTerm.SlugIs(v) case Field.CreatedBy => FieldTerm.CreatedByIs(v) diff --git a/modules/search-query/src/test/scala/io/renku/search/query/QueryGenerators.scala b/modules/search-query/src/test/scala/io/renku/search/query/QueryGenerators.scala index 264155fb..5ce77a83 100644 --- a/modules/search-query/src/test/scala/io/renku/search/query/QueryGenerators.scala +++ b/modules/search-query/src/test/scala/io/renku/search/query/QueryGenerators.scala @@ -24,8 +24,8 @@ import cats.Order as CatsOrder import cats.data.NonEmptyList import cats.syntax.all.* +import io.renku.search.model.* import io.renku.search.model.projects.Visibility -import io.renku.search.model.{CommonGenerators, MemberRole, ModelGenerators} import io.renku.search.query.parse.QueryUtil import org.scalacheck.Gen import org.scalacheck.cats.implicits.* @@ -121,6 +121,9 @@ object QueryGenerators: val nameTerm: Gen[FieldTerm] = stringValues.map(FieldTerm.NameIs(_)) + val namespaceTerm: Gen[FieldTerm] = + stringValues.map(vs => FieldTerm.NamespaceIs(vs.map(Namespace(_)))) + val slugTerm: Gen[FieldTerm] = stringValues.map(FieldTerm.SlugIs(_)) @@ -157,6 +160,7 @@ object QueryGenerators: Gen.oneOf( projectIdTerm, nameTerm, + namespaceTerm, slugTerm, createdByTerm, visibilityTerm, diff --git a/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/LuceneQueryEncoders.scala b/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/LuceneQueryEncoders.scala index 8673f326..1b75d465 100644 --- a/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/LuceneQueryEncoders.scala +++ b/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/LuceneQueryEncoders.scala @@ -80,6 +80,13 @@ trait LuceneQueryEncoders: ) } + given namespaceIs[F[_]: Applicative]: SolrTokenEncoder[F, FieldTerm.NamespaceIs] = + SolrTokenEncoder.basic { case FieldTerm.NamespaceIs(values) => + SolrQuery( + SolrToken.orFieldIs(SolrField.namespace, values.map(SolrToken.fromNamespace)) + ) + } + given created[F[_]: Monad]: SolrTokenEncoder[F, FieldTerm.Created] = val createdIs = SolrToken.fieldIs(SolrField.creationDate, _) SolrTokenEncoder.create[F, FieldTerm.Created] { diff --git a/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/SolrToken.scala b/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/SolrToken.scala index 3849951b..5cde85e3 100644 --- a/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/SolrToken.scala +++ b/modules/search-solr-client/src/main/scala/io/renku/search/solr/query/SolrToken.scala @@ -64,6 +64,9 @@ object SolrToken: case Comparison.GreaterThan => ">" case Comparison.LowerThan => "<" + def fromNamespace(ns: Namespace): SolrToken = + fromString(ns.value) + def contentAll(text: String): SolrToken = val terms: Seq[SolrToken] = text.split("\\s+").map(_.trim).toSeq s"${SolrField.contentAll.name}:${terms.fuzzy}" @@ -72,7 +75,7 @@ object SolrToken: values.map(fieldIs(field, _)).toList.foldOr def namespaceIs(ns: Namespace): SolrToken = - fieldIs(SolrField.namespace, fromString(ns.value)) + fieldIs(SolrField.namespace, fromNamespace(ns)) def createdDateIs(date: Instant): SolrToken = fieldIs(SolrField.creationDate, fromInstant(date))