From ac31baea6819654fed3e349899d50c2fce0ece57 Mon Sep 17 00:00:00 2001 From: Jonas Natten Date: Thu, 2 Jan 2025 15:36:02 +0100 Subject: [PATCH] search-api: Include more data in the grep search To allow us to completely skip calling the udir grep api from the frontend/graphql we need more data! This patch includes everything(?) we need to stop calling the grep api directly from elsewhere. --- .../main/scala/no/ndla/common/CirceUtil.scala | 9 +- .../ndla/searchapi/integration/ZipUtil.scala | 5 + .../searchapi/model/api/DescriptionDTO.scala | 27 +++ .../model/api/grep/GrepResultDTO.scala | 171 +++++++++++++++++- .../searchapi/model/grep/GrepElement.scala | 84 +++++++-- .../ndla/searchapi/model/grep/GrepTitle.scala | 18 +- .../model/search/SearchableGrepElement.scala | 4 +- .../service/search/GrepIndexService.scala | 4 +- .../service/search/GrepSearchService.scala | 19 +- .../search/SearchConverterService.scala | 23 +-- .../scala/no/ndla/searchapi/TestData.scala | 44 ++--- .../search/GrepSearchServiceTest.scala | 74 ++++---- .../search/SearchConverterServiceTest.scala | 30 +-- typescript/types-backend/search-api.ts | 58 +++++- 14 files changed, 428 insertions(+), 142 deletions(-) create mode 100644 search-api/src/main/scala/no/ndla/searchapi/model/api/DescriptionDTO.scala diff --git a/common/src/main/scala/no/ndla/common/CirceUtil.scala b/common/src/main/scala/no/ndla/common/CirceUtil.scala index 14ed2cd7a..9f1bdcc8c 100644 --- a/common/src/main/scala/no/ndla/common/CirceUtil.scala +++ b/common/src/main/scala/no/ndla/common/CirceUtil.scala @@ -16,9 +16,12 @@ import scala.util.{Failure, Try} object CirceUtil { // NOTE: Circe's `DecodingFailure` does not include a stack trace, so we wrap it in our own exception // to make it more like other failures. - case class CirceFailure(message: String) extends RuntimeException(message) + case class CirceFailure(message: String, jsonString: String) extends RuntimeException(message) object CirceFailure { - def apply(reason: Throwable): Throwable = new CirceFailure(reason.getMessage).initCause(reason) + def apply(jsonString: String, reason: Throwable): Throwable = { + val message = s"${reason.getMessage}\n$jsonString" + new CirceFailure(message, jsonString).initCause(reason) + } } def tryParseAs[T](str: String)(implicit d: Decoder[T]): Try[T] = { @@ -26,7 +29,7 @@ object CirceUtil { .parse(str) .toTry .flatMap(_.as[T].toTry) - .recoverWith { ex => Failure(CirceFailure(ex)) } + .recoverWith { ex => Failure(CirceFailure(str, ex)) } } /** This might throw an exception! Use with care, probably only use this in tests */ diff --git a/search-api/src/main/scala/no/ndla/searchapi/integration/ZipUtil.scala b/search-api/src/main/scala/no/ndla/searchapi/integration/ZipUtil.scala index 767f93909..1245bf8fa 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/integration/ZipUtil.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/integration/ZipUtil.scala @@ -25,8 +25,13 @@ object ZipUtil { .continually(zis.read(buffer)) .takeWhile(_ != -1) .foreach(fout.write(buffer, 0, _)) + + fout.close() } + zis.close() + fis.close() + if (deleteArchive) zipFile.delete() targetDir diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/api/DescriptionDTO.scala b/search-api/src/main/scala/no/ndla/searchapi/model/api/DescriptionDTO.scala new file mode 100644 index 000000000..31d044fa3 --- /dev/null +++ b/search-api/src/main/scala/no/ndla/searchapi/model/api/DescriptionDTO.scala @@ -0,0 +1,27 @@ +/* + * Part of NDLA search-api + * Copyright (C) 2018 NDLA + * + * See LICENSE + */ + +package no.ndla.searchapi.model.api + +import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} +import io.circe.{Decoder, Encoder} +import no.ndla.language.model.LanguageField +import sttp.tapir.Schema.annotations.description + +@description("Title of resource") +case class DescriptionDTO( + @description("The freetext description of the resource") description: String, + @description("ISO 639-1 code that represents the language used in title") language: String +) extends LanguageField[String] { + override def value: String = description + override def isEmpty: Boolean = description.isEmpty +} + +object DescriptionDTO { + implicit val encoder: Encoder[DescriptionDTO] = deriveEncoder + implicit val decoder: Decoder[DescriptionDTO] = deriveDecoder +} diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/api/grep/GrepResultDTO.scala b/search-api/src/main/scala/no/ndla/searchapi/model/api/grep/GrepResultDTO.scala index 57ce3faea..c5eb38010 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/api/grep/GrepResultDTO.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/api/grep/GrepResultDTO.scala @@ -8,19 +8,170 @@ package no.ndla.searchapi.model.api.grep -import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} -import io.circe.{Decoder, Encoder} -import no.ndla.searchapi.model.api.TitleDTO +import cats.implicits.* +import io.circe.generic.auto.* +import sttp.tapir.generic.auto.* +import io.circe.syntax.* +import io.circe.{Decoder, Encoder, Json} +import no.ndla.language.Language +import no.ndla.language.Language.findByLanguageOrBestEffort +import no.ndla.search.model.LanguageValue +import no.ndla.searchapi.model.api.{DescriptionDTO, TitleDTO} +import no.ndla.searchapi.model.grep.{ + GrepKjerneelement, + GrepKompetansemaal, + GrepKompetansemaalSett, + GrepLaererplan, + GrepTitle, + GrepTverrfagligTema +} +import no.ndla.searchapi.model.search.SearchableGrepElement +import sttp.tapir.Schema import sttp.tapir.Schema.annotations.description +import scala.util.{Success, Try} + @description("Information about a single grep search result entry") -case class GrepResultDTO( - @description("The grep code") code: String, - @description("The greps title") title: TitleDTO, - @description("The grep laereplan") laereplanCode: Option[String] -) +sealed trait GrepResultDTO { + @description("The grep code") val code: String + @description("The greps title") val title: TitleDTO +} object GrepResultDTO { - implicit val encoder: Encoder[GrepResultDTO] = deriveEncoder - implicit val decoder: Decoder[GrepResultDTO] = deriveDecoder + implicit val encoder: Encoder[GrepResultDTO] = Encoder.instance[GrepResultDTO] { result => + val json = result match { + case x: GrepKjerneelementDTO => x.asJson + case x: GrepKompetansemaalDTO => x.asJson + case x: GrepKompetansemaalSettDTO => x.asJson + case x: GrepLaererplanDTO => x.asJson + case x: GrepTverrfagligTemaDTO => x.asJson + } + // NOTE: Adding the discriminator field that scala-tsi generates in the typescript type. + // Useful for guarding the type of the object in the frontend. + json.mapObject(_.add("type", Json.fromString(result.getClass.getSimpleName))) + } + + implicit val decoder: Decoder[GrepResultDTO] = List[Decoder[GrepResultDTO]]( + Decoder[GrepKjerneelementDTO].widen, + Decoder[GrepKompetansemaalDTO].widen, + Decoder[GrepKompetansemaalSettDTO].widen, + Decoder[GrepLaererplanDTO].widen, + Decoder[GrepTverrfagligTemaDTO].widen + ).reduceLeft(_ or _) + + implicit val s: Schema[GrepResultDTO] = Schema.oneOfWrapped[GrepResultDTO] + def fromSearchable(searchable: SearchableGrepElement, language: String): Try[GrepResultDTO] = { + val titleLv = findByLanguageOrBestEffort(searchable.title.languageValues, language) + .getOrElse(LanguageValue(Language.DefaultLanguage, "")) + val title = TitleDTO(title = titleLv.value, language = titleLv.language) + + searchable.domainObject match { + case core: GrepKjerneelement => + val descriptionLvs = GrepTitle.convertTitles(core.beskrivelse.tekst.toSeq) + val descriptionLv: LanguageValue[String] = + findByLanguageOrBestEffort(descriptionLvs, language) + .getOrElse(LanguageValue(Language.DefaultLanguage, "")) + val description = DescriptionDTO(description = descriptionLv.value, language = descriptionLv.language) + + Success( + GrepKjerneelementDTO( + code = core.kode, + title = title, + description = description, + laereplan = GrepLaererplanDTO( + code = core.`tilhoerer-laereplan`.kode, + title = TitleDTO(core.`tilhoerer-laereplan`.tittel, Language.DefaultLanguage) + ) + ) + ) + case goal: GrepKompetansemaal => + Success( + GrepKompetansemaalDTO( + code = goal.kode, + title = title, + laereplan = GrepLaererplanDTO( + code = goal.`tilhoerer-laereplan`.kode, + title = TitleDTO(goal.`tilhoerer-laereplan`.tittel, Language.DefaultLanguage) + ), + kompetansemaalSett = GrepReferencedKompetansemaalSettDTO( + code = goal.`tilhoerer-kompetansemaalsett`.kode, + title = goal.`tilhoerer-kompetansemaalsett`.tittel + ), + tverrfagligeTemaer = goal.`tilknyttede-tverrfaglige-temaer`.map { crossTopic => + GrepTverrfagligTemaDTO( + code = crossTopic.referanse.kode, + title = TitleDTO(crossTopic.referanse.tittel, Language.DefaultLanguage) + ) + }, + kjerneelementer = goal.`tilknyttede-kjerneelementer`.map { core => + GrepReferencedKjerneelementDTO( + code = core.referanse.kode, + title = core.referanse.tittel + ) + } + ) + ) + case goalSet: GrepKompetansemaalSett => + Success( + GrepKompetansemaalSettDTO( + code = goalSet.kode, + title = title, + kompetansemaal = goalSet.kompetansemaal.map { goal => + GrepReferencedKompetansemaalDTO( + code = goal.kode, + title = goal.tittel + ) + } + ) + ) + case curriculum: GrepLaererplan => + Success( + GrepLaererplanDTO( + code = curriculum.kode, + title = title + ) + ) + case crossTopic: GrepTverrfagligTema => + Success( + GrepTverrfagligTemaDTO( + code = crossTopic.kode, + title = title + ) + ) + } + } } + +case class GrepReferencedKjerneelementDTO(code: String, title: String) +case class GrepReferencedKompetansemaalDTO(code: String, title: String) +case class GrepKjerneelementDTO( + code: String, + title: TitleDTO, + description: DescriptionDTO, + laereplan: GrepLaererplanDTO +) extends GrepResultDTO +case class GrepKompetansemaalDTO( + code: String, + title: TitleDTO, + laereplan: GrepLaererplanDTO, + kompetansemaalSett: GrepReferencedKompetansemaalSettDTO, + tverrfagligeTemaer: List[GrepTverrfagligTemaDTO], + kjerneelementer: List[GrepReferencedKjerneelementDTO] +) extends GrepResultDTO +case class GrepReferencedKompetansemaalSettDTO( + code: String, + title: String +) +case class GrepKompetansemaalSettDTO( + code: String, + title: TitleDTO, + kompetansemaal: List[GrepReferencedKompetansemaalDTO] +) extends GrepResultDTO +case class GrepLaererplanDTO( + code: String, + title: TitleDTO +) extends GrepResultDTO +case class GrepTverrfagligTemaDTO( + code: String, + title: TitleDTO +) extends GrepResultDTO diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepElement.scala b/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepElement.scala index 6b8dd65c9..3bcb7e162 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepElement.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepElement.scala @@ -7,26 +7,50 @@ package no.ndla.searchapi.model.grep +import cats.implicits.* import io.circe.{Decoder, Encoder} import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} +import io.circe.syntax.EncoderOps sealed trait GrepElement { val kode: String def getTitle: Seq[GrepTitle] } +object GrepElement { + implicit val decoder: Decoder[GrepElement] = + List[Decoder[GrepElement]]( + Decoder[GrepKjerneelement].widen, + Decoder[GrepKompetansemaal].widen, + Decoder[GrepKompetansemaalSett].widen, + Decoder[GrepLaererplan].widen, + Decoder[GrepTverrfagligTema].widen + ).reduceLeft(_ or _) + + implicit val encoder: Encoder[GrepElement] = Encoder.instance { + case x: GrepKjerneelement => x.asJson + case x: GrepKompetansemaal => x.asJson + case x: GrepKompetansemaalSett => x.asJson + case x: GrepLaererplan => x.asJson + case x: GrepTverrfagligTema => x.asJson + } +} sealed trait BelongsToLaerePlan { val `tilhoerer-laereplan`: BelongsToObj } -case class TitleObj(tekst: List[GrepTitle]) -object TitleObj { - implicit val encoder: Encoder[TitleObj] = deriveEncoder - implicit val decoder: Decoder[TitleObj] = deriveDecoder +case class GrepTextObj(tekst: List[GrepTitle]) +object GrepTextObj { + implicit val encoder: Encoder[GrepTextObj] = deriveEncoder + implicit val decoder: Decoder[GrepTextObj] = deriveDecoder } -case class GrepKjerneelement(kode: String, tittel: TitleObj, `tilhoerer-laereplan`: BelongsToObj) - extends GrepElement +case class GrepKjerneelement( + kode: String, + tittel: GrepTextObj, + beskrivelse: GrepTextObj, + `tilhoerer-laereplan`: BelongsToObj +) extends GrepElement with BelongsToLaerePlan { override def getTitle: Seq[GrepTitle] = tittel.tekst } @@ -35,14 +59,38 @@ object GrepKjerneelement { implicit val decoder: Decoder[GrepKjerneelement] = deriveDecoder } -case class BelongsToObj(kode: String) +case class BelongsToObj( + kode: String, + tittel: String +) object BelongsToObj { implicit val encoder: Encoder[BelongsToObj] = deriveEncoder implicit val decoder: Decoder[BelongsToObj] = deriveDecoder } -case class GrepKompetansemaal(kode: String, tittel: TitleObj, `tilhoerer-laereplan`: BelongsToObj) - extends GrepElement +case class ReferenceObj( + kode: String, + tittel: String +) +object ReferenceObj { + implicit val encoder: Encoder[ReferenceObj] = deriveEncoder + implicit val decoder: Decoder[ReferenceObj] = deriveDecoder +} + +case class ReferenceWrapperObj(referanse: ReferenceObj) +object ReferenceWrapperObj { + implicit val encoder: Encoder[ReferenceWrapperObj] = deriveEncoder + implicit val decoder: Decoder[ReferenceWrapperObj] = deriveDecoder +} + +case class GrepKompetansemaal( + kode: String, + tittel: GrepTextObj, + `tilhoerer-laereplan`: BelongsToObj, + `tilhoerer-kompetansemaalsett`: BelongsToObj, + `tilknyttede-tverrfaglige-temaer`: List[ReferenceWrapperObj], + `tilknyttede-kjerneelementer`: List[ReferenceWrapperObj] +) extends GrepElement with BelongsToLaerePlan { override def getTitle: Seq[GrepTitle] = tittel.tekst } @@ -51,8 +99,12 @@ object GrepKompetansemaal { implicit val decoder: Decoder[GrepKompetansemaal] = deriveDecoder } -case class GrepKompetansemaalSett(kode: String, tittel: TitleObj, `tilhoerer-laereplan`: BelongsToObj) - extends GrepElement +case class GrepKompetansemaalSett( + kode: String, + tittel: GrepTextObj, + `tilhoerer-laereplan`: BelongsToObj, + kompetansemaal: List[ReferenceObj] +) extends GrepElement with BelongsToLaerePlan { override def getTitle: Seq[GrepTitle] = tittel.tekst } @@ -61,7 +113,10 @@ object GrepKompetansemaalSett { implicit val decoder: Decoder[GrepKompetansemaalSett] = deriveDecoder } -case class GrepLaererplan(kode: String, tittel: TitleObj) extends GrepElement { +case class GrepLaererplan( + kode: String, + tittel: GrepTextObj +) extends GrepElement { override def getTitle: Seq[GrepTitle] = tittel.tekst } object GrepLaererplan { @@ -69,7 +124,10 @@ object GrepLaererplan { implicit val decoder: Decoder[GrepLaererplan] = deriveDecoder } -case class GrepTverrfagligTema(kode: String, tittel: Seq[GrepTitle]) extends GrepElement { +case class GrepTverrfagligTema( + kode: String, + tittel: Seq[GrepTitle] +) extends GrepElement { override def getTitle: Seq[GrepTitle] = tittel } object GrepTverrfagligTema { diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepTitle.scala b/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepTitle.scala index 5448d3de9..39d763d49 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepTitle.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/grep/GrepTitle.scala @@ -7,12 +7,28 @@ package no.ndla.searchapi.model.grep +import com.typesafe.scalalogging.StrictLogging import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} import io.circe.{Decoder, Encoder} +import no.ndla.mapping.ISO639 +import no.ndla.search.model.LanguageValue case class GrepTitle(spraak: String, verdi: String) -object GrepTitle { +object GrepTitle extends StrictLogging { implicit val encoder: Encoder[GrepTitle] = deriveEncoder implicit val decoder: Decoder[GrepTitle] = deriveDecoder + + def convertTitles(titles: Seq[GrepTitle]): Seq[LanguageValue[String]] = { + titles.flatMap(gt => { + ISO639.get6391CodeFor6392Code(gt.spraak) match { + case Some(convertedLanguage) => + Some(LanguageValue(language = convertedLanguage, value = gt.verdi.trim)) + case None if gt.spraak == "default" => None + case None => + logger.warn(s"Could not convert language code '${gt.spraak}'") + None + } + }) + } } diff --git a/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableGrepElement.scala b/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableGrepElement.scala index 7f03e9cdf..c2727aacf 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableGrepElement.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/model/search/SearchableGrepElement.scala @@ -11,12 +11,14 @@ package no.ndla.searchapi.model.search import io.circe.{Decoder, Encoder} import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} import no.ndla.search.model.SearchableLanguageValues +import no.ndla.searchapi.model.grep.GrepElement case class SearchableGrepElement( code: String, title: SearchableLanguageValues, defaultTitle: Option[String], - laereplanCode: Option[String] + laereplanCode: Option[String], + domainObject: GrepElement ) object SearchableGrepElement { diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepIndexService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepIndexService.scala index 8d5a5f8b1..8bf57860a 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepIndexService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepIndexService.scala @@ -11,6 +11,7 @@ package no.ndla.searchapi.service.search import cats.implicits.toTraverseOps import no.ndla.common.implicits.TryQuestionMark import com.sksamuel.elastic4s.ElasticDsl.* +import com.sksamuel.elastic4s.fields.ObjectField import com.sksamuel.elastic4s.requests.indexes.IndexRequest import com.sksamuel.elastic4s.requests.mappings.MappingDefinition import com.typesafe.scalalogging.StrictLogging @@ -37,7 +38,8 @@ trait GrepIndexService { val fields = List( keywordField("defaultTitle"), keywordField("code").normalizer("lower"), - keywordField("laereplanCode").normalizer("lower") + keywordField("laereplanCode").normalizer("lower"), + ObjectField("domainObject", enabled = Some(false)) ) val dynamics = generateLanguageSupportedDynamicTemplates("title", keepRaw = true) diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepSearchService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepSearchService.scala index ebd4dc103..4562f5dfa 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepSearchService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/GrepSearchService.scala @@ -17,19 +17,16 @@ import com.sksamuel.elastic4s.requests.searches.sort.SortOrder.{Asc, Desc} import com.sksamuel.elastic4s.requests.searches.{SearchHit, SearchResponse} import no.ndla.common.CirceUtil import no.ndla.common.implicits.TryQuestionMark -import no.ndla.language.Language -import no.ndla.language.Language.{AllLanguages, findByLanguageOrBestEffort} +import no.ndla.language.Language.AllLanguages import no.ndla.language.model.Iso639 -import no.ndla.search.model.LanguageValue import no.ndla.search.{BaseIndexService, Elastic4sClient} import no.ndla.searchapi.Props import no.ndla.searchapi.controller.parameters.GrepSearchInputDTO -import no.ndla.searchapi.model.api.TitleDTO import no.ndla.searchapi.model.api.grep.GrepSortDTO.* import no.ndla.searchapi.model.api.grep.{GrepResultDTO, GrepSearchResultsDTO, GrepSortDTO} import no.ndla.searchapi.model.search.{SearchType, SearchableGrepElement} -import scala.util.{Success, Try} +import scala.util.Try trait GrepSearchService { this: Props & SearchService & GrepIndexService & BaseIndexService & Elastic4sClient & SearchConverterService => @@ -153,17 +150,7 @@ trait GrepSearchService { private def hitToResult(hit: SearchHit, language: String): Try[GrepResultDTO] = { val jsonString = hit.sourceAsString val searchable = CirceUtil.tryParseAs[SearchableGrepElement](jsonString).? - val titleLv = findByLanguageOrBestEffort(searchable.title.languageValues, language) - .getOrElse(LanguageValue(Language.DefaultLanguage, "")) - val title = TitleDTO(title = titleLv.value, language = titleLv.language) - - Success( - GrepResultDTO( - code = searchable.code, - title = title, - laereplanCode = searchable.laereplanCode - ) - ) + GrepResultDTO.fromSearchable(searchable, language) } private def getGrepHits(response: RequestSuccess[SearchResponse], language: String): Try[List[GrepResultDTO]] = { diff --git a/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala b/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala index 8274eee21..5f21da900 100644 --- a/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala +++ b/search-api/src/main/scala/no/ndla/searchapi/service/search/SearchConverterService.scala @@ -261,32 +261,15 @@ trait SearchConverterService { case _ => None } val defaultTitle = grepElement.getTitle.find(_.spraak == "default") - val titles = grepElement.getTitle.flatMap(gt => { - ISO639.get6391CodeFor6392Code(gt.spraak) match { - case Some(convertedLanguage) => - Some(LanguageValue(language = convertedLanguage, value = gt.verdi.trim)) - case None if gt.spraak == "default" => None - case None => - logger.warn(s"Could not convert language code '${gt.spraak}' for grep code '${grepElement.kode}'") - None - } - }) - - def asSearchableGrep(grepElement: GrepElement): Try[SearchableGrepElement] = { - val laererplan = grepElement match { - case lp: BelongsToLaerePlan => Some(lp.tilhoerer_laereplan.kode) - case _ => None - } - val defaultTitle = grepElement.tittel.find(_.spraak == "default") - val titles = convertGrepTitleToLanguageValue(grepElement) + val titles = GrepTitle.convertTitles(grepElement.getTitle) val title = SearchableLanguageValues.fromFields(titles) - Success( SearchableGrepElement( code = grepElement.kode, title = title, defaultTitle = defaultTitle.map(_.verdi), - laereplanCode = laererplan + laereplanCode = laererplan, + domainObject = grepElement ) ) } diff --git a/search-api/src/test/scala/no/ndla/searchapi/TestData.scala b/search-api/src/test/scala/no/ndla/searchapi/TestData.scala index 6a2cbda2f..ed586a706 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/TestData.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/TestData.scala @@ -58,7 +58,7 @@ import no.ndla.searchapi.model.grep.{ GrepLaererplan, GrepTitle, GrepTverrfagligTema, - TitleObj + GrepTextObj } import no.ndla.searchapi.model.search.* import no.ndla.searchapi.model.search.settings.{MultiDraftSearchSettings, SearchSettings} @@ -1587,27 +1587,27 @@ object TestData { ) val grepBundle: GrepBundle = emptyGrepBundle.copy( - kjerneelementer = List( - GrepKjerneelement( - "KE12", - TitleObj(List(GrepTitle("default", "Utforsking og problemløysing"))), - BelongsToObj("LP1") - ), - GrepKjerneelement( - "KE34", - TitleObj(List(GrepTitle("default", "Abstraksjon og generalisering"))), - BelongsToObj("LP1") - ) - ), - kompetansemaal = List( - GrepKompetansemaal( - "KM123", - TitleObj(List(GrepTitle("default", "bruke ulike kilder på en kritisk, hensiktsmessig og etterrettelig måte"))), - BelongsToObj("LP1") - ) - ), - tverrfagligeTemaer = List(GrepTverrfagligTema("TT2", Seq(GrepTitle("default", "Demokrati og medborgerskap")))), - laereplaner = List(GrepLaererplan("LP1", TitleObj(List(GrepTitle("default", "Læreplan i norsk (NOR01-04)"))))) +// kjerneelementer = List( +// GrepKjerneelement( +// "KE12", +// GrepTextObj(List(GrepTitle("default", "Utforsking og problemløysing"))), +// BelongsToObj("LP1") +// ), +// GrepKjerneelement( +// "KE34", +// GrepTextObj(List(GrepTitle("default", "Abstraksjon og generalisering"))), +// BelongsToObj("LP1") +// ) +// ), +// kompetansemaal = List( +// GrepKompetansemaal( +// "KM123", +// GrepTextObj(List(GrepTitle("default", "bruke ulike kilder på en kritisk, hensiktsmessig og etterrettelig måte"))), +// BelongsToObj("LP1") +// ) +// ), +// tverrfagligeTemaer = List(GrepTverrfagligTema("TT2", Seq(GrepTitle("default", "Demokrati og medborgerskap")))), +// laereplaner = List(GrepLaererplan("LP1", GrepTextObj(List(GrepTitle("default", "Læreplan i norsk (NOR01-04)"))))) ) val searchSettings: SearchSettings = SearchSettings( diff --git a/search-api/src/test/scala/no/ndla/searchapi/service/search/GrepSearchServiceTest.scala b/search-api/src/test/scala/no/ndla/searchapi/service/search/GrepSearchServiceTest.scala index ad6e6d072..70386fd51 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/service/search/GrepSearchServiceTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/service/search/GrepSearchServiceTest.scala @@ -21,7 +21,7 @@ import no.ndla.searchapi.model.grep.{ GrepLaererplan, GrepTitle, GrepTverrfagligTema, - TitleObj + GrepTextObj } class GrepSearchServiceTest extends IntegrationSuite(EnableElasticsearchContainer = true) with TestEnvironment { @@ -48,49 +48,49 @@ class GrepSearchServiceTest extends IntegrationSuite(EnableElasticsearchContaine val grepTestBundle: GrepBundle = GrepBundle( kjerneelementer = List( - GrepKjerneelement( - "KE12", - TitleObj( - List(GrepTitle("default", "Utforsking og problemløysing"), GrepTitle("nob", "Utforsking og problemløsning")) - ), - BelongsToObj("LP1") - ), - GrepKjerneelement( - "KE34", - TitleObj( - List(GrepTitle("default", "Abstraksjon og generalisering"), GrepTitle("nob", "Abstraksjon og generalisering")) - ), - BelongsToObj("LP2") - ) +// GrepKjerneelement( +// "KE12", +// GrepTextObj( +// List(GrepTitle("default", "Utforsking og problemløysing"), GrepTitle("nob", "Utforsking og problemløsning")) +// ), +// BelongsToObj("LP1") +// ), +// GrepKjerneelement( +// "KE34", +// GrepTextObj( +// List(GrepTitle("default", "Abstraksjon og generalisering"), GrepTitle("nob", "Abstraksjon og generalisering")) +// ), +// BelongsToObj("LP2") +// ) ), kompetansemaal = List( - GrepKompetansemaal( - "KM123", - TitleObj( - List( - GrepTitle("default", "bruke ulike kilder på en kritisk, hensiktsmessig og etterrettelig måte"), - GrepTitle("nob", "bruke ulike kilder på en kritisk, hensiktsmessig og etterrettelig måte") - ) - ), - BelongsToObj("LP2") - ) +// GrepKompetansemaal( +// "KM123", +// GrepTextObj( +// List( +// GrepTitle("default", "bruke ulike kilder på en kritisk, hensiktsmessig og etterrettelig måte"), +// GrepTitle("nob", "bruke ulike kilder på en kritisk, hensiktsmessig og etterrettelig måte") +// ) +// ), +// BelongsToObj("LP2") +// ) ), kompetansemaalsett = List.empty, tverrfagligeTemaer = List( - GrepTverrfagligTema( - "TT2", - Seq(GrepTitle("default", "Demokrati og medborgerskap"), GrepTitle("nob", "Demokrati og medborgerskap")) - ) +// GrepTverrfagligTema( +// "TT2", +// Seq(GrepTitle("default", "Demokrati og medborgerskap"), GrepTitle("nob", "Demokrati og medborgerskap")) +// ) ), laereplaner = List( - GrepLaererplan( - "LP1", - TitleObj(List(GrepTitle("default", "Læreplan i norsk"), GrepTitle("nob", "Læreplan i norsk"))) - ), - GrepLaererplan( - "LP2", - TitleObj(List(GrepTitle("default", "Læreplan i engelsk"), GrepTitle("nob", "Læreplan i engelsk"))) - ) +// GrepLaererplan( +// "LP1", +// GrepTextObj(List(GrepTitle("default", "Læreplan i norsk"), GrepTitle("nob", "Læreplan i norsk"))) +// ), +// GrepLaererplan( +// "LP2", +// GrepTextObj(List(GrepTitle("default", "Læreplan i engelsk"), GrepTitle("nob", "Læreplan i engelsk"))) +// ) ) ) diff --git a/search-api/src/test/scala/no/ndla/searchapi/service/search/SearchConverterServiceTest.scala b/search-api/src/test/scala/no/ndla/searchapi/service/search/SearchConverterServiceTest.scala index 6b3d8446b..af8657a81 100644 --- a/search-api/src/test/scala/no/ndla/searchapi/service/search/SearchConverterServiceTest.scala +++ b/search-api/src/test/scala/no/ndla/searchapi/service/search/SearchConverterServiceTest.scala @@ -19,7 +19,7 @@ import no.ndla.searchapi.model.grep.{ GrepKompetansemaal, GrepTitle, GrepTverrfagligTema, - TitleObj + GrepTextObj } import no.ndla.searchapi.model.search.{SearchTrait, SearchableArticle, SearchableGrepContext} import no.ndla.searchapi.model.taxonomy.* @@ -496,13 +496,13 @@ class SearchConverterServiceTest extends UnitSuite with TestEnvironment { test("That asSearchableDraft converts grepContexts correctly based on grepBundle if draft has grepCodes") { val draft = TestData.emptyDomainDraft.copy(id = Some(99), grepCodes = Seq("KE12", "KM123", "TT2")) val grepBundle = TestData.emptyGrepBundle.copy( - kjerneelementer = List( - GrepKjerneelement("KE12", TitleObj(List(GrepTitle("default", "tittel12"))), BelongsToObj("LP123")), - GrepKjerneelement("KE34", TitleObj(List(GrepTitle("default", "tittel34"))), BelongsToObj("LP123")) - ), - kompetansemaal = - List(GrepKompetansemaal("KM123", TitleObj(List(GrepTitle("default", "tittel123"))), BelongsToObj("LP123"))), - tverrfagligeTemaer = List(GrepTverrfagligTema("TT2", Seq(GrepTitle("default", "tittel2")))) +// kjerneelementer = List( +// GrepKjerneelement("KE12", GrepTextObj(List(GrepTitle("default", "tittel12"))), BelongsToObj("LP123")), +// GrepKjerneelement("KE34", GrepTextObj(List(GrepTitle("default", "tittel34"))), BelongsToObj("LP123")) +// ), +// kompetansemaal = +// List(GrepKompetansemaal("KM123", GrepTextObj(List(GrepTitle("default", "tittel123"))), BelongsToObj("LP123"))), +// tverrfagligeTemaer = List(GrepTverrfagligTema("TT2", Seq(GrepTitle("default", "tittel2")))) ) val grepContexts = List( SearchableGrepContext("KE12", Some("tittel12")), @@ -517,13 +517,13 @@ class SearchConverterServiceTest extends UnitSuite with TestEnvironment { test("That asSearchableDraft converts grepContexts correctly based on grepBundle if draft has no grepCodes") { val draft = TestData.emptyDomainDraft.copy(id = Some(99), grepCodes = Seq.empty) val grepBundle = TestData.emptyGrepBundle.copy( - kjerneelementer = List( - GrepKjerneelement("KE12", TitleObj(List(GrepTitle("default", "tittel12"))), BelongsToObj("LP123")), - GrepKjerneelement("KE34", TitleObj(List(GrepTitle("default", "tittel34"))), BelongsToObj("LP123")) - ), - kompetansemaal = - List(GrepKompetansemaal("KM123", TitleObj(List(GrepTitle("default", "tittel123"))), BelongsToObj("LP123"))), - tverrfagligeTemaer = List(GrepTverrfagligTema("TT2", List(GrepTitle("default", "tittel2")))) +// kjerneelementer = List( +// GrepKjerneelement("KE12", GrepTextObj(List(GrepTitle("default", "tittel12"))), BelongsToObj("LP123")), +// GrepKjerneelement("KE34", GrepTextObj(List(GrepTitle("default", "tittel34"))), BelongsToObj("LP123")) +// ), +// kompetansemaal = +// List(GrepKompetansemaal("KM123", GrepTextObj(List(GrepTitle("default", "tittel123"))), BelongsToObj("LP123"))), +// tverrfagligeTemaer = List(GrepTverrfagligTema("TT2", List(GrepTitle("default", "tittel2")))) ) val grepContexts = List.empty diff --git a/typescript/types-backend/search-api.ts b/typescript/types-backend/search-api.ts index b6f089ca7..783450b0d 100644 --- a/typescript/types-backend/search-api.ts +++ b/typescript/types-backend/search-api.ts @@ -1,5 +1,7 @@ // DO NOT EDIT: generated file by scala-tsi +export type GrepResultDTO = (IGrepKompetansemaalDTO | IGrepKjerneelementDTO | IGrepLaererplanDTO | IGrepTverrfagligTemaDTO | IGrepKompetansemaalSettDTO) + export type GrepSort = ("-relevance" | "relevance" | "-title" | "title" | "-code" | "code") export interface IApiTaxonomyContextDTO { @@ -67,6 +69,11 @@ export interface ICommentDTO { solved: boolean } +export interface IDescriptionDTO { + description: string + language: string +} + export interface IDraftResponsibleDTO { responsibleId: string lastUpdated: string @@ -110,10 +117,50 @@ export interface IDraftSearchParamsDTO { resultTypes?: SearchType[] } -export interface IGrepResultDTO { +export interface IGrepKjerneelementDTO { + code: string + title: ITitleDTO + description: IDescriptionDTO + laereplan: IGrepLaererplanDTO + type: "GrepKjerneelementDTO" +} + +export interface IGrepKompetansemaalDTO { + code: string + title: ITitleDTO + laereplan: IGrepLaererplanDTO + kompetansemaalSett: IGrepReferencedKompetansemaalSettDTO + tverrfagligeTemaer: IGrepTverrfagligTemaDTO[] + kjerneelementer: IGrepReferencedKjerneelementDTO[] + type: "GrepKompetansemaalDTO" +} + +export interface IGrepKompetansemaalSettDTO { + code: string + title: ITitleDTO + kompetansemaal: IGrepReferencedKompetansemaalDTO[] + type: "GrepKompetansemaalSettDTO" +} + +export interface IGrepLaererplanDTO { code: string title: ITitleDTO - laereplanCode?: string + type: "GrepLaererplanDTO" +} + +export interface IGrepReferencedKjerneelementDTO { + code: string + title: string +} + +export interface IGrepReferencedKompetansemaalDTO { + code: string + title: string +} + +export interface IGrepReferencedKompetansemaalSettDTO { + code: string + title: string } export interface IGrepSearchInputDTO { @@ -131,7 +178,12 @@ export interface IGrepSearchResultsDTO { page: number pageSize: number language: string - results: IGrepResultDTO[] + results: GrepResultDTO[] +} + +export interface IGrepTverrfagligTemaDTO { + code: string + title: ITitleDTO } export interface IGroupSearchResultDTO {