diff --git a/article-api/src/main/scala/no/ndla/articleapi/model/domain/DBArticle.scala b/article-api/src/main/scala/no/ndla/articleapi/model/domain/DBArticle.scala index 48538d9d87..ab0e967f5f 100644 --- a/article-api/src/main/scala/no/ndla/articleapi/model/domain/DBArticle.scala +++ b/article-api/src/main/scala/no/ndla/articleapi/model/domain/DBArticle.scala @@ -16,8 +16,8 @@ import scalikejdbc.* class DBArticle(using props: Props) { object Article extends SQLSyntaxSupport[Article] { - override val tableName = "contentdata" - override lazy val schemaName: Option[String] = Some(props.MetaSchema) + override val tableName = "contentdata" + override val schemaName: Option[String] = Some(props.MetaSchema) def fromResultSet(lp: SyntaxProvider[Article])(rs: WrappedResultSet): ArticleRow = fromResultSet(lp.resultName)(rs) diff --git a/audio-api/src/main/scala/no/ndla/audioapi/ComponentRegistry.scala b/audio-api/src/main/scala/no/ndla/audioapi/ComponentRegistry.scala index 8a41b71b8c..6d2e28bc02 100644 --- a/audio-api/src/main/scala/no/ndla/audioapi/ComponentRegistry.scala +++ b/audio-api/src/main/scala/no/ndla/audioapi/ComponentRegistry.scala @@ -11,6 +11,7 @@ package no.ndla.audioapi import no.ndla.audioapi.controller.* import no.ndla.audioapi.db.migrationwithdependencies.{V5__AddAgreementToAudio, V6__TranslateUntranslatedAuthors} import no.ndla.audioapi.integration.{NDLAS3Client, TranscribeS3Client} +import no.ndla.audioapi.model.domain.{DBAudioMetaInformation, DBSeries} import no.ndla.audioapi.repository.{AudioRepository, SeriesRepository} import no.ndla.audioapi.service.* import no.ndla.audioapi.service.search.* @@ -24,14 +25,16 @@ import no.ndla.network.tapir.{ErrorHelpers, Routes, SwaggerController, TapirAppl import no.ndla.search.{Elastic4sClientFactory, NdlaE4sClient, SearchLanguage} class ComponentRegistry(properties: AudioApiProperties) extends TapirApplication[AudioApiProperties] { - given props: AudioApiProperties = properties - given dataSource: DataSource = DataSource.getDataSource - given clock: Clock = new Clock - given migrator: DBMigrator = DBMigrator(new V5__AddAgreementToAudio, new V6__TranslateUntranslatedAuthors) - given errorHelpers: ErrorHelpers = new ErrorHelpers - given errorHandling: ControllerErrorHandling = new ControllerErrorHandling - given searchLanguage: SearchLanguage = new SearchLanguage - given dbUtility: DBUtility = new DBUtility + given props: AudioApiProperties = properties + given dataSource: DataSource = DataSource.getDataSource + given clock: Clock = new Clock + given migrator: DBMigrator = DBMigrator(new V5__AddAgreementToAudio, new V6__TranslateUntranslatedAuthors) + given errorHelpers: ErrorHelpers = new ErrorHelpers + given errorHandling: ControllerErrorHandling = new ControllerErrorHandling + given searchLanguage: SearchLanguage = new SearchLanguage + given dbUtility: DBUtility = new DBUtility + given dbAudioMetaInformation: DBAudioMetaInformation = new DBAudioMetaInformation + given dbSeries: DBSeries = new DBSeries given s3Client: NDLAS3Client = new NDLAS3Client(props.StorageName, props.StorageRegion) given s3TranscribeClient: TranscribeS3Client = diff --git a/audio-api/src/main/scala/no/ndla/audioapi/model/domain/AudioMetaInformation.scala b/audio-api/src/main/scala/no/ndla/audioapi/model/domain/AudioMetaInformation.scala index efadc723c7..6ff5d3c5a5 100644 --- a/audio-api/src/main/scala/no/ndla/audioapi/model/domain/AudioMetaInformation.scala +++ b/audio-api/src/main/scala/no/ndla/audioapi/model/domain/AudioMetaInformation.scala @@ -15,6 +15,7 @@ import no.ndla.common.CirceUtil import no.ndla.common.model.NDLADate import no.ndla.common.model.domain.article.Copyright import no.ndla.common.model.domain.{Tag, Title} +import no.ndla.audioapi.Props import no.ndla.language.Language.getSupportedLanguages import no.ndla.language.model.LanguageField import scalikejdbc.* @@ -69,8 +70,7 @@ object Audio { implicit val decoder: Decoder[Audio] = deriveDecoder } -object AudioMetaInformation extends SQLSyntaxSupport[AudioMetaInformation] { - override val tableName = "audiodata" +object AudioMetaInformation { implicit val encoder: Encoder[AudioMetaInformation] = deriveEncoder implicit val decoder: Decoder[AudioMetaInformation] = deriveDecoder @@ -94,3 +94,8 @@ object AudioMetaInformation extends SQLSyntaxSupport[AudioMetaInformation] { rs.longOpt(au.c("id")).map(_ => fromResultSet(au)(rs)) } } + +class DBAudioMetaInformation(using props: Props) extends SQLSyntaxSupport[AudioMetaInformation] { + override val tableName: String = "audiodata" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/audio-api/src/main/scala/no/ndla/audioapi/model/domain/Series.scala b/audio-api/src/main/scala/no/ndla/audioapi/model/domain/Series.scala index cc63956c27..c212dd77ce 100644 --- a/audio-api/src/main/scala/no/ndla/audioapi/model/domain/Series.scala +++ b/audio-api/src/main/scala/no/ndla/audioapi/model/domain/Series.scala @@ -13,6 +13,7 @@ import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} import no.ndla.common.CirceUtil import no.ndla.common.model.NDLADate import no.ndla.common.model.domain.Title +import no.ndla.audioapi.Props import no.ndla.language.Language.getSupportedLanguages import scalikejdbc.* @@ -59,8 +60,7 @@ case class Series( ) } -object Series extends SQLSyntaxSupport[Series] { - override val tableName = "seriesdata" +object Series { implicit val encoder: Encoder[Series] = deriveEncoder implicit val decoder: Decoder[Series] = deriveDecoder @@ -88,3 +88,8 @@ object Series extends SQLSyntaxSupport[Series] { meta.map(m => fromId(id = rs.long(s.c("id")), revision = rs.int(s.c("revision")), series = m)) } } + +class DBSeries(using props: Props) extends SQLSyntaxSupport[Series] { + override val tableName: String = "seriesdata" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/audio-api/src/main/scala/no/ndla/audioapi/repository/AudioRepository.scala b/audio-api/src/main/scala/no/ndla/audioapi/repository/AudioRepository.scala index ee03b5c8a6..54ad12eb06 100644 --- a/audio-api/src/main/scala/no/ndla/audioapi/repository/AudioRepository.scala +++ b/audio-api/src/main/scala/no/ndla/audioapi/repository/AudioRepository.scala @@ -10,7 +10,7 @@ package no.ndla.audioapi.repository import com.typesafe.scalalogging.StrictLogging import no.ndla.audioapi.model.api.OptimisticLockException -import no.ndla.audioapi.model.domain.{AudioMetaInformation, Series} +import no.ndla.audioapi.model.domain.{AudioMetaInformation, DBAudioMetaInformation, DBSeries, Series} import no.ndla.common.CirceUtil import no.ndla.network.tapir.ErrorHelpers import org.postgresql.util.PGobject @@ -20,11 +20,15 @@ import no.ndla.database.implicits.* import scala.util.{Failure, Success, Try} -class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) - extends StrictLogging +class AudioRepository(using + errorHelpers: ErrorHelpers, + dbUtility: DBUtility, + dbAudioMetaInformation: DBAudioMetaInformation, + dbSeries: DBSeries, +) extends StrictLogging with Repository[AudioMetaInformation] { def audioCount(implicit session: DBSession = dbUtility.readOnlySession): Long = - tsql"select count(*) from ${AudioMetaInformation.table}" + tsql"select count(*) from ${dbAudioMetaInformation.table}" .map(rs => rs.long("count")) .runSingle() .map(_.getOrElse(0L)) @@ -105,7 +109,7 @@ class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) session: DBSession = dbUtility.autoSession ): Try[Long] = { tsql""" - update ${AudioMetaInformation.table} + update ${dbAudioMetaInformation.table} set series_id = $seriesId where id = $audioMetaId """.update().map(_ => audioMetaId) @@ -125,7 +129,7 @@ class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) } def deleteAudio(audioId: Long)(implicit session: DBSession = dbUtility.autoSession): Int = { - tsql"delete from ${AudioMetaInformation.table} where id=$audioId".update().get + tsql"delete from ${dbAudioMetaInformation.table} where id=$audioId".update().get } override def documentsWithIdBetween(min: Long, max: Long): Try[List[AudioMetaInformation]] = { @@ -135,12 +139,12 @@ class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) private def audioMetaInformationWhere( whereClause: SQLSyntax )(implicit session: DBSession): Option[AudioMetaInformation] = { - val au = AudioMetaInformation.syntax("au") - val se = Series.syntax("se") + val au = dbAudioMetaInformation.syntax("au") + val se = dbSeries.syntax("se") tsql""" select ${au.result.*}, ${se.result.*} - from ${AudioMetaInformation.as(au)} - left join ${Series.as(se)} on ${au.seriesId} = ${se.id} + from ${dbAudioMetaInformation.as(au)} + left join ${dbSeries.as(se)} on ${au.seriesId} = ${se.id} where $whereClause """ .map { rs => @@ -156,12 +160,12 @@ class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) private def audioMetaInformationsWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Try[List[AudioMetaInformation]] = { - val au = AudioMetaInformation.syntax("au") - val se = Series.syntax("se") + val au = dbAudioMetaInformation.syntax("au") + val se = dbSeries.syntax("se") tsql""" select ${au.result.*}, ${se.result.*} - from ${AudioMetaInformation.as(au)} - left join ${Series.as(se)} on ${au.seriesId} = ${se.id} + from ${dbAudioMetaInformation.as(au)} + left join ${dbSeries.as(se)} on ${au.seriesId} = ${se.id} where $whereClause """ .map { rs => @@ -173,8 +177,8 @@ class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) } def getRandomAudio()(implicit session: DBSession = dbUtility.readOnlySession): Option[AudioMetaInformation] = { - val au = AudioMetaInformation.syntax("au") - tsql"select ${au.result.*} from ${AudioMetaInformation.as(au)} tablesample public.system_rows(1)" + val au = dbAudioMetaInformation.syntax("au") + tsql"select ${au.result.*} from ${dbAudioMetaInformation.as(au)} tablesample public.system_rows(1)" .map(AudioMetaInformation.fromResultSet(au)) .runSingle() .get @@ -183,10 +187,10 @@ class AudioRepository(using errorHelpers: ErrorHelpers, dbUtility: DBUtility) def getByPage(pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession ): Seq[AudioMetaInformation] = { - val au = AudioMetaInformation.syntax("au") + val au = dbAudioMetaInformation.syntax("au") tsql""" select ${au.result.*} - from ${AudioMetaInformation.as(au)} + from ${dbAudioMetaInformation.as(au)} where document is not null order by id offset $offset diff --git a/audio-api/src/main/scala/no/ndla/audioapi/repository/SeriesRepository.scala b/audio-api/src/main/scala/no/ndla/audioapi/repository/SeriesRepository.scala index 38bea4154f..38d73ac621 100644 --- a/audio-api/src/main/scala/no/ndla/audioapi/repository/SeriesRepository.scala +++ b/audio-api/src/main/scala/no/ndla/audioapi/repository/SeriesRepository.scala @@ -9,7 +9,7 @@ package no.ndla.audioapi.repository import com.typesafe.scalalogging.StrictLogging -import no.ndla.audioapi.model.domain.{AudioMetaInformation, Series} +import no.ndla.audioapi.model.domain.{AudioMetaInformation, DBAudioMetaInformation, DBSeries, Series} import no.ndla.audioapi.model.domain import org.postgresql.util.PGobject import scalikejdbc.* @@ -23,8 +23,12 @@ import no.ndla.database.DBUtility import scala.util.{Failure, Success, Try} -class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) - extends StrictLogging +class SeriesRepository(using + helpers: ErrorHelpers, + dbUtility: DBUtility, + dbSeries: DBSeries, + dbAudioMetaInformation: DBAudioMetaInformation, +) extends StrictLogging with Repository[Series] { /** Method to fetch single series from database @@ -43,7 +47,7 @@ class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) def deleteWithId(id: Long)(implicit session: DBSession = dbUtility.autoSession): Try[Int] = { tsql""" - delete from ${Series.table} + delete from ${dbSeries.table} where id=$id """.update() } @@ -56,7 +60,7 @@ class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) val newRevision = series.revision + 1 tsql""" - update ${Series.table} + update ${dbSeries.table} set document=$dataObject, revision=$newRevision where id=${series.id} and revision=${series.revision} """ @@ -82,13 +86,13 @@ class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) dataObject.setValue(CirceUtil.toJsonString(newSeries)) tsql""" - insert into ${Series.table}(document, revision) + insert into ${dbSeries.table}(document, revision) values ($dataObject, $startRevision) """.updateAndReturnGeneratedKey().map(id => Series.fromId(id, startRevision, newSeries)) } override def minMaxId(implicit session: DBSession = dbUtility.readOnlySession): Try[(Long, Long)] = { - tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${Series.table}" + tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${dbSeries.table}" .map(rs => (rs.long("mi"), rs.long("ma"))) .runSingle() .map(_.getOrElse((0L, 0L))) @@ -101,11 +105,11 @@ class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) private def serieWhereNoEpisodes( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Series]] = { - val se = Series.syntax("se") + val se = dbSeries.syntax("se") tsql""" select ${se.result.*} - from ${Series.as(se)} + from ${dbSeries.as(se)} where $whereClause """.map(Series.fromResultSet(se.resultName)).runSingle().map(_.sequence).flatten } @@ -113,13 +117,13 @@ class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) private def serieWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Series]] = { - val se = Series.syntax("se") - val au = AudioMetaInformation.syntax("au") + val se = dbSeries.syntax("se") + val au = dbAudioMetaInformation.syntax("au") tsql""" select ${se.result.*}, ${au.result.*} - from ${Series.as(se)} - left join ${AudioMetaInformation.as(au)} on ${se.id} = ${au.seriesId} + from ${dbSeries.as(se)} + left join ${dbAudioMetaInformation.as(au)} on ${se.id} = ${au.seriesId} where $whereClause """ .one(Series.fromResultSet(se.resultName)) @@ -133,13 +137,13 @@ class SeriesRepository(using helpers: ErrorHelpers, dbUtility: DBUtility) private def seriesWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Try[List[Series]] = { - val se = Series.syntax("se") - val au = AudioMetaInformation.syntax("au") + val se = dbSeries.syntax("se") + val au = dbAudioMetaInformation.syntax("au") tsql""" select ${se.result.*}, ${au.result.*} - from ${Series.as(se)} - left join ${AudioMetaInformation.as(au)} on ${se.id} = ${au.seriesId} + from ${dbSeries.as(se)} + left join ${dbAudioMetaInformation.as(au)} on ${se.id} = ${au.seriesId} where $whereClause """ .one(Series.fromResultSet(se.resultName)) diff --git a/audio-api/src/test/scala/no/ndla/audioapi/TestEnvironment.scala b/audio-api/src/test/scala/no/ndla/audioapi/TestEnvironment.scala index 424920a445..3fb7015eef 100644 --- a/audio-api/src/test/scala/no/ndla/audioapi/TestEnvironment.scala +++ b/audio-api/src/test/scala/no/ndla/audioapi/TestEnvironment.scala @@ -10,6 +10,7 @@ package no.ndla.audioapi import no.ndla.audioapi.controller.{AudioController, ControllerErrorHandling, InternController, SeriesController} import no.ndla.audioapi.integration.{NDLAS3Client, TranscribeS3Client} +import no.ndla.audioapi.model.domain.{DBAudioMetaInformation, DBSeries} import no.ndla.audioapi.repository.{AudioRepository, SeriesRepository} import no.ndla.audioapi.service.* import no.ndla.audioapi.service.search.* @@ -41,10 +42,12 @@ trait TestEnvironment extends TapirApplication[AudioApiProperties] with MockitoS implicit lazy val services: List[TapirController] = List.empty implicit lazy val searchLanguage: SearchLanguage = mock[SearchLanguage] - implicit lazy val dataSource: DataSource = mock[DataSource] - implicit lazy val audioRepository: AudioRepository = mock[AudioRepository] - implicit lazy val seriesRepository: SeriesRepository = mock[SeriesRepository] - implicit lazy val dbUtility: DBUtility = new DBUtility + implicit lazy val dataSource: DataSource = mock[DataSource] + implicit lazy val audioRepository: AudioRepository = mock[AudioRepository] + implicit lazy val seriesRepository: SeriesRepository = mock[SeriesRepository] + implicit lazy val dbUtility: DBUtility = new DBUtility + implicit lazy val dbAudioMetaInformation: DBAudioMetaInformation = new DBAudioMetaInformation + implicit lazy val dbSeries: DBSeries = new DBSeries implicit lazy val s3Client: NDLAS3Client = mock[NDLAS3Client] implicit lazy val brightcoveClient: NdlaBrightcoveClient = mock[NdlaBrightcoveClient] diff --git a/common/src/main/scala/no/ndla/common/model/domain/config/ConfigMeta.scala b/common/src/main/scala/no/ndla/common/model/domain/config/ConfigMeta.scala index 9632e7a3bb..25a7286e1f 100644 --- a/common/src/main/scala/no/ndla/common/model/domain/config/ConfigMeta.scala +++ b/common/src/main/scala/no/ndla/common/model/domain/config/ConfigMeta.scala @@ -79,8 +79,7 @@ case class ConfigMeta(key: ConfigKey, value: ConfigMetaValue, updatedAt: NDLADat } } -object ConfigMeta extends SQLSyntaxSupport[ConfigMeta] with StrictLogging { - override val tableName = "configtable" +object ConfigMeta extends StrictLogging { def fromResultSet(c: SyntaxProvider[ConfigMeta])(rs: WrappedResultSet): Try[ConfigMeta] = fromResultSet(c.resultName)(rs) diff --git a/concept-api/src/main/scala/no/ndla/conceptapi/ComponentRegistry.scala b/concept-api/src/main/scala/no/ndla/conceptapi/ComponentRegistry.scala index 1ed410cad0..3ce2a27d4f 100644 --- a/concept-api/src/main/scala/no/ndla/conceptapi/ComponentRegistry.scala +++ b/concept-api/src/main/scala/no/ndla/conceptapi/ComponentRegistry.scala @@ -9,6 +9,7 @@ package no.ndla.conceptapi import no.ndla.conceptapi.controller.* +import no.ndla.conceptapi.model.domain.{DBConcept, PublishedConcept} import no.ndla.conceptapi.repository.{DraftConceptRepository, PublishedConceptRepository} import no.ndla.conceptapi.service.search.* import no.ndla.conceptapi.service.* @@ -33,7 +34,9 @@ import sttp.tapir.stringToPath import no.ndla.network.tapir.auth.Permission class ComponentRegistry(properties: ConceptApiProperties) extends TapirApplication[ConceptApiProperties] { - given props: ConceptApiProperties = properties + given props: ConceptApiProperties = properties + given dbConcept: DBConcept = new DBConcept + given publishedConcept: PublishedConcept = new PublishedConcept given clock: Clock = new Clock given e4sClient: NdlaE4sClient = Elastic4sClientFactory.getClient(props.SearchServer) diff --git a/concept-api/src/main/scala/no/ndla/conceptapi/model/domain/DBConcept.scala b/concept-api/src/main/scala/no/ndla/conceptapi/model/domain/DBConcept.scala index a2cabef7f0..35425ff3f1 100644 --- a/concept-api/src/main/scala/no/ndla/conceptapi/model/domain/DBConcept.scala +++ b/concept-api/src/main/scala/no/ndla/conceptapi/model/domain/DBConcept.scala @@ -10,10 +10,12 @@ package no.ndla.conceptapi.model.domain import no.ndla.common.CirceUtil import no.ndla.common.model.domain.concept.Concept +import no.ndla.conceptapi.Props import scalikejdbc.* -object DBConcept extends SQLSyntaxSupport[Concept] { - override val tableName = "conceptdata" +class DBConcept(using props: Props) extends SQLSyntaxSupport[Concept] { + override val tableName = "conceptdata" + override val schemaName: Option[String] = Some(props.MetaSchema) def fromResultSet(lp: SyntaxProvider[Concept])(rs: WrappedResultSet): Concept = fromResultSet(lp.resultName)(rs) @@ -45,6 +47,7 @@ object DBConcept extends SQLSyntaxSupport[Concept] { } } -object PublishedConcept extends SQLSyntaxSupport[Concept] { - override val tableName = "publishedconceptdata" +class PublishedConcept(using props: Props) extends SQLSyntaxSupport[Concept] { + override val tableName = "publishedconceptdata" + override val schemaName: Option[String] = Some(props.MetaSchema) } diff --git a/concept-api/src/main/scala/no/ndla/conceptapi/repository/DraftConceptRepository.scala b/concept-api/src/main/scala/no/ndla/conceptapi/repository/DraftConceptRepository.scala index a87754ed8a..62a4fa8cbf 100644 --- a/concept-api/src/main/scala/no/ndla/conceptapi/repository/DraftConceptRepository.scala +++ b/concept-api/src/main/scala/no/ndla/conceptapi/repository/DraftConceptRepository.scala @@ -23,7 +23,7 @@ import no.ndla.database.implicits.* import scala.util.{Failure, Success, Try} -class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbUtility: DBUtility) +class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbUtility: DBUtility, dbConcept: DBConcept) extends StrictLogging with Repository[Concept] { def insert(concept: Concept)(implicit session: DBSession = dbUtility.autoSession): Concept = { @@ -34,7 +34,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU val newRevision = 1 val conceptId: Long = tsql""" - insert into ${DBConcept.table} (document, revision) + insert into ${dbConcept.table} (document, revision) values ($dataObject, $newRevision) """.updateAndReturnGeneratedKey().get @@ -52,7 +52,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU val newRevision = 1 val conceptId: Long = tsql""" - insert into ${DBConcept.table} (listing_id, document, revision) + insert into ${dbConcept.table} (listing_id, document, revision) values ($listingId, $dataObject, $newRevision) """.updateAndReturnGeneratedKey().get @@ -68,7 +68,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU dataObject.setValue(CirceUtil.toJsonString(concept)) tsql""" - update ${DBConcept.table} + update ${dbConcept.table} set document=$dataObject where listing_id=$listingId """.updateAndReturnGeneratedKey() match { @@ -82,7 +82,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU def everyTagFromEveryConcept(implicit session: DBSession = dbUtility.readOnlySession): List[List[Tag]] = { tsql""" select distinct id, document#>'{tags}' as tags - from ${DBConcept.table} + from ${dbConcept.table} where jsonb_array_length(document#>'{tags}') > 0 order by id """ @@ -106,7 +106,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU val newRevision = 1 tsql""" - insert into ${DBConcept.table} (id, document, revision) + insert into ${dbConcept.table} (id, document, revision) values ($id, $dataObject, $newRevision) """ .update() @@ -130,13 +130,13 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU val oldRevision = concept.revision tsql""" - update ${DBConcept.table} + update ${dbConcept.table} set document=$dataObject, revision=$newRevision where id=$conceptId and revision=$oldRevision - and revision=(select max(revision) from ${DBConcept.table} where id=$conceptId) + and revision=(select max(revision) from ${dbConcept.table} where id=$conceptId) """ .update() .flatMap(updatedRows => failIfRevisionMismatch(updatedRows, concept, newRevision)) @@ -161,18 +161,18 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU def withId(id: Long): Option[Concept] = conceptWhere(sqls"co.id=${id.toInt} ORDER BY revision DESC LIMIT 1") def exists(id: Long)(implicit session: DBSession = dbUtility.autoSession): Boolean = { - tsql"select id from ${DBConcept.table} where id=$id".map(rs => rs.long("id")).runSingle().get.isDefined + tsql"select id from ${dbConcept.table} where id=$id".map(rs => rs.long("id")).runSingle().get.isDefined } def getIdFromExternalId(externalId: String)(implicit session: DBSession = dbUtility.autoSession): Option[Long] = { - tsql"select id from ${DBConcept.table} where $externalId = any(external_id)" + tsql"select id from ${dbConcept.table} where $externalId = any(external_id)" .map(rs => rs.long("id")) .runSingle() .get } override def minMaxId(implicit session: DBSession = dbUtility.autoSession): (Long, Long) = { - tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${DBConcept.table}" + tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${dbConcept.table}" .map(rs => (rs.long("mi"), rs.long("ma"))) .runSingle() .map(_.getOrElse((0L, 0L))) @@ -185,9 +185,9 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU private def conceptWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Option[Concept] = { - val co = DBConcept.syntax("co") - tsql"select ${co.result.*} from ${DBConcept.as(co)} where co.document is not NULL and $whereClause" - .map(DBConcept.fromResultSet(co)) + val co = dbConcept.syntax("co") + tsql"select ${co.result.*} from ${dbConcept.as(co)} where co.document is not NULL and $whereClause" + .map(dbConcept.fromResultSet(co)) .runSingle() .get } @@ -195,18 +195,18 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU private def conceptsWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): List[Concept] = { - val co = DBConcept.syntax("co") - tsql"select ${co.result.*} from ${DBConcept.as(co)} where co.document is not NULL and $whereClause" - .map(DBConcept.fromResultSet(co)) + val co = dbConcept.syntax("co") + tsql"select ${co.result.*} from ${dbConcept.as(co)} where co.document is not NULL and $whereClause" + .map(dbConcept.fromResultSet(co)) .runList() .get } def conceptCount(implicit session: DBSession = dbUtility.readOnlySession): Long = - tsql"select count(*) from ${DBConcept.table}".map(rs => rs.long("count")).runSingle().map(_.getOrElse(0L)).get + tsql"select count(*) from ${dbConcept.table}".map(rs => rs.long("count")).runSingle().map(_.getOrElse(0L)).get private def getHighestId(implicit session: DBSession = dbUtility.readOnlySession): Long = - tsql"select id from ${DBConcept.table} order by id desc limit 1" + tsql"select id from ${dbConcept.table} order by id desc limit 1" .map(rs => rs.long("id")) .runSingle() .map(_.getOrElse(0L)) @@ -219,7 +219,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU ).toString ) val sequenceName = - SQLSyntax.createUnsafely(s"${DBConcept.schemaName.getOrElse(props.MetaSchema)}.${DBConcept.tableName}_id_seq") + SQLSyntax.createUnsafely(s"${dbConcept.schemaName.getOrElse(props.MetaSchema)}.${dbConcept.tableName}_id_seq") val _ = tsql"alter sequence $sequenceName restart with $idToStartAt;".execute() } @@ -235,7 +235,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU val tags = tsql"""select tags from (select distinct JSONB_ARRAY_ELEMENTS_TEXT(tagObj->'tags') tags from - (select JSONB_ARRAY_ELEMENTS(document#>'{tags}') tagObj from ${DBConcept.table}) _ + (select JSONB_ARRAY_ELEMENTS(document#>'{tags}') tagObj from ${dbConcept.table}) _ where tagObj->>'language' like $langOrAll order by tags) sorted_tags where sorted_tags.tags ilike ${sanitizedInput + '%'} @@ -246,7 +246,7 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU val tagsCount = tsql""" select count(*) from (select distinct JSONB_ARRAY_ELEMENTS_TEXT(tagObj->'tags') tags from - (select JSONB_ARRAY_ELEMENTS(document#>'{tags}') tagObj from ${DBConcept.table}) _ + (select JSONB_ARRAY_ELEMENTS(document#>'{tags}') tagObj from ${dbConcept.table}) _ where tagObj->>'language' like $langOrAll) all_tags where all_tags.tags ilike ${sanitizedInput + '%'}; """.map(rs => rs.int("count")).runSingle().map(_.getOrElse(0)).get @@ -256,14 +256,14 @@ class DraftConceptRepository(using props: Props, errorHelpers: ErrorHelpers, dbU } def getByPage(pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession): Seq[Concept] = { - val co = DBConcept.syntax("co") + val co = dbConcept.syntax("co") tsql""" select ${co.result.*}, ${co.revision} as revision - from ${DBConcept.as(co)} + from ${dbConcept.as(co)} where document is not null order by ${co.id} offset $offset limit $pageSize - """.map(DBConcept.fromResultSet(co)).runList().get + """.map(dbConcept.fromResultSet(co)).runList().get } } diff --git a/concept-api/src/main/scala/no/ndla/conceptapi/repository/PublishedConceptRepository.scala b/concept-api/src/main/scala/no/ndla/conceptapi/repository/PublishedConceptRepository.scala index 30acc03560..06ed1c81c0 100644 --- a/concept-api/src/main/scala/no/ndla/conceptapi/repository/PublishedConceptRepository.scala +++ b/concept-api/src/main/scala/no/ndla/conceptapi/repository/PublishedConceptRepository.scala @@ -21,14 +21,16 @@ import no.ndla.database.implicits.* import scala.util.{Failure, Success, Try} -class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLogging with Repository[Concept] { +class PublishedConceptRepository(using dbUtility: DBUtility, dbConcept: DBConcept, publishedConcept: PublishedConcept) + extends StrictLogging + with Repository[Concept] { def insertOrUpdate(concept: Concept)(implicit session: DBSession = dbUtility.autoSession): Try[Concept] = { val dataObject = new PGobject() dataObject.setType("jsonb") dataObject.setValue(CirceUtil.toJsonString(concept)) - tsql"""update ${PublishedConcept.table} + tsql"""update ${publishedConcept.table} set document=$dataObject, revision=${concept.revision} @@ -40,7 +42,7 @@ class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLoggi case Success(_) => logger.info(s"No published concept with id ${concept.id} exists, creating...") tsql""" - insert into ${PublishedConcept.table} (id, document, revision) + insert into ${publishedConcept.table} (id, document, revision) values (${concept.id}, $dataObject, ${concept.revision}) """.updateAndReturnGeneratedKey().map(_ => concept) case Failure(ex) => Failure(ex) @@ -49,7 +51,7 @@ class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLoggi def delete(id: Long)(implicit session: DBSession = dbUtility.autoSession): Try[?] = { tsql""" - delete from ${PublishedConcept.table} + delete from ${publishedConcept.table} where id=$id """.update() match { case Success(count) if count > 0 => Success(id) @@ -63,7 +65,7 @@ class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLoggi def everyTagFromEveryConcept(implicit session: DBSession = dbUtility.readOnlySession): List[List[Tag]] = { tsql""" select distinct id, document#>'{tags}' as tags - from ${PublishedConcept.table} + from ${publishedConcept.table} where jsonb_array_length(document#>'{tags}') > 0 order by id """ @@ -78,15 +80,15 @@ class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLoggi private def conceptWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Option[Concept] = { - val co = PublishedConcept.syntax("co") - tsql"select ${co.result.*} from ${PublishedConcept.as(co)} where co.document is not NULL and $whereClause" - .map(DBConcept.fromResultSet(co)) + val co = publishedConcept.syntax("co") + tsql"select ${co.result.*} from ${publishedConcept.as(co)} where co.document is not NULL and $whereClause" + .map(dbConcept.fromResultSet(co)) .runSingle() .get } def conceptCount(implicit session: DBSession = dbUtility.readOnlySession): Long = - tsql"select count(*) from ${PublishedConcept.table}" + tsql"select count(*) from ${publishedConcept.table}" .map(rs => rs.long("count")) .runSingle() .map(_.getOrElse(0L)) @@ -96,7 +98,7 @@ class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLoggi conceptsWhere(sqls"co.id between $min and $max") override def minMaxId(implicit session: DBSession = dbUtility.autoSession): (Long, Long) = { - tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${PublishedConcept.table}" + tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${publishedConcept.table}" .map(rs => (rs.long("mi"), rs.long("ma"))) .runSingle() .map(_.getOrElse((0L, 0L))) @@ -106,22 +108,22 @@ class PublishedConceptRepository(using dbUtility: DBUtility) extends StrictLoggi private def conceptsWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): List[Concept] = { - val co = PublishedConcept.syntax("co") - tsql"select ${co.result.*} from ${PublishedConcept.as(co)} where co.document is not NULL and $whereClause" - .map(DBConcept.fromResultSet(co)) + val co = publishedConcept.syntax("co") + tsql"select ${co.result.*} from ${publishedConcept.as(co)} where co.document is not NULL and $whereClause" + .map(dbConcept.fromResultSet(co)) .runList() .get } def getByPage(pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession): Seq[Concept] = { - val co = PublishedConcept.syntax("co") + val co = publishedConcept.syntax("co") tsql""" select ${co.result.*} - from ${PublishedConcept.as(co)} + from ${publishedConcept.as(co)} where document is not null order by ${co.id} offset $offset limit $pageSize - """.map(DBConcept.fromResultSet(co)).runList().get + """.map(dbConcept.fromResultSet(co)).runList().get } } diff --git a/concept-api/src/test/scala/no/ndla/conceptapi/TestEnvironment.scala b/concept-api/src/test/scala/no/ndla/conceptapi/TestEnvironment.scala index 744478ce27..924998d6eb 100644 --- a/concept-api/src/test/scala/no/ndla/conceptapi/TestEnvironment.scala +++ b/concept-api/src/test/scala/no/ndla/conceptapi/TestEnvironment.scala @@ -16,6 +16,7 @@ import no.ndla.conceptapi.controller.{ InternController, PublishedConceptController, } +import no.ndla.conceptapi.model.domain.{DBConcept, PublishedConcept} import no.ndla.conceptapi.repository.{DraftConceptRepository, PublishedConceptRepository} import no.ndla.conceptapi.service.* import no.ndla.conceptapi.service.search.* @@ -39,6 +40,8 @@ trait TestEnvironment extends TapirApplication[ConceptApiProperties] with Mockit implicit lazy val props: ConceptApiProperties = new ConceptApiProperties { override def IntroductionHtmlTags: Set[String] = Set("br", "code", "em", "p", "span", "strong", "sub", "sup") } + implicit lazy val dbConcept: DBConcept = new DBConcept + implicit lazy val publishedConcept: PublishedConcept = new PublishedConcept implicit lazy val migrator: DBMigrator = mock[DBMigrator] implicit lazy val draftConceptRepository: DraftConceptRepository = mock[DraftConceptRepository] diff --git a/concept-api/src/test/scala/no/ndla/conceptapi/repository/PublishedConceptRepositoryTest.scala b/concept-api/src/test/scala/no/ndla/conceptapi/repository/PublishedConceptRepositoryTest.scala index 4b7fc23bd0..a07679c3e0 100644 --- a/concept-api/src/test/scala/no/ndla/conceptapi/repository/PublishedConceptRepositoryTest.scala +++ b/concept-api/src/test/scala/no/ndla/conceptapi/repository/PublishedConceptRepositoryTest.scala @@ -12,7 +12,6 @@ import no.ndla.common.model.{NDLADate, domain as common} import no.ndla.common.model.domain.concept import no.ndla.common.model.domain.concept.ConceptContent import no.ndla.conceptapi.* -import no.ndla.conceptapi.model.domain.PublishedConcept import no.ndla.database.{DBMigrator, DBUtility, DataSource} import no.ndla.scalatestsuite.DatabaseIntegrationSuite import scalikejdbc.* @@ -29,7 +28,7 @@ class PublishedConceptRepositoryTest extends DatabaseIntegrationSuite with TestE def emptyTestDatabase: Boolean = { dbUtility.writeSession(implicit session => { - sql"delete from ${PublishedConcept.table};".execute()(using session) + sql"delete from publishedconceptdata;".execute()(using session) }) } diff --git a/draft-api/src/main/scala/no/ndla/draftapi/ComponentRegistry.scala b/draft-api/src/main/scala/no/ndla/draftapi/ComponentRegistry.scala index ddc4b0d7de..6079d3d5bd 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/ComponentRegistry.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/ComponentRegistry.scala @@ -18,6 +18,7 @@ import no.ndla.draftapi.controller.* import no.ndla.draftapi.db.migrationwithdependencies.* import no.ndla.draftapi.integration.* import no.ndla.draftapi.model.api.DraftErrorHelpers +import no.ndla.draftapi.model.domain.{DBArticle, DBUserData} import no.ndla.draftapi.repository.{DraftRepository, UserDataRepository} import no.ndla.draftapi.service.* import no.ndla.draftapi.service.search.* @@ -53,6 +54,8 @@ class ComponentRegistry(properties: DraftApiProperties) extends TapirApplication implicit lazy val learningpathApiClient: LearningpathApiClient = new LearningpathApiClient implicit lazy val h5pApiClient: H5PApiClient = new H5PApiClient implicit lazy val imageApiClient: ImageApiClient = new ImageApiClient + implicit lazy val dbArticle: DBArticle = new DBArticle + implicit lazy val dbUserData: DBUserData = new DBUserData implicit lazy val draftRepository: DraftRepository = new DraftRepository implicit lazy val userDataRepository: UserDataRepository = new UserDataRepository implicit lazy val contentValidator: ContentValidator = new ContentValidator() diff --git a/draft-api/src/main/scala/no/ndla/draftapi/model/domain/Content.scala b/draft-api/src/main/scala/no/ndla/draftapi/model/domain/Content.scala index fa8be8d2eb..417a9b2e60 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/model/domain/Content.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/model/domain/Content.scala @@ -12,6 +12,7 @@ import io.circe.{Decoder, Encoder} import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} import no.ndla.common.CirceUtil import no.ndla.common.model.domain.draft.Draft +import no.ndla.draftapi.Props import no.ndla.draftapi.model.api.SavedSearchDTO import scalikejdbc.* @@ -25,8 +26,9 @@ case class UserData( favoriteSubjects: Option[Seq[String]], ) -object DBArticle extends SQLSyntaxSupport[Draft] { - override val tableName = "articledata" +class DBArticle(using props: Props) extends SQLSyntaxSupport[Draft] { + override val tableName = "articledata" + override val schemaName: Option[String] = Some(props.MetaSchema) def fromResultSet(lp: SyntaxProvider[Draft])(rs: WrappedResultSet): Draft = fromResultSet(lp.resultName)(rs) @@ -37,8 +39,7 @@ object DBArticle extends SQLSyntaxSupport[Draft] { } } -object UserData extends SQLSyntaxSupport[UserData] { - override val tableName = "userdata" +object UserData { implicit val encoder: Encoder[UserData] = deriveEncoder implicit val decoder: Decoder[UserData] = deriveDecoder @@ -50,3 +51,8 @@ object UserData extends SQLSyntaxSupport[UserData] { userData.copy(id = Some(rs.long(lp.c("id")))) } } + +class DBUserData(using props: Props) extends SQLSyntaxSupport[UserData] { + override val tableName: String = "userdata" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/draft-api/src/main/scala/no/ndla/draftapi/repository/DraftRepository.scala b/draft-api/src/main/scala/no/ndla/draftapi/repository/DraftRepository.scala index 3df558ab10..3198f95801 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/repository/DraftRepository.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/repository/DraftRepository.scala @@ -27,7 +27,7 @@ import scalikejdbc.* import java.util.UUID import scala.util.{Failure, Success, Try} -class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) +class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock, dbArticle: DBArticle) extends StrictLogging with Repository[Draft] { import draftErrorHelpers.* @@ -40,7 +40,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) val slug = article.slug.map(_.toLowerCase) tsql""" - insert into ${DBArticle.table} (document, revision, article_id, slug) + insert into ${dbArticle.table} (document, revision, article_id, slug) values ($dataObject, $startRevision, ${article.id}, $slug) """ .updateAndReturnGeneratedKey() @@ -92,7 +92,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) uuid = Try(importId.map(UUID.fromString)).toOption.flatten slug = article.slug.map(_.toLowerCase) _ <- tsql""" - insert into ${DBArticle.table} (external_id, external_subject_id, document, revision, import_id, article_id, slug) + insert into ${dbArticle.table} (external_id, external_subject_id, document, revision, import_id, article_id, slug) values (ARRAY[$externalIds]::text[], ARRAY[$externalSubjectIds]::text[], $dataObject, @@ -143,13 +143,13 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) val whereClause = sqls""" where article_id=${article.id} and revision=$oldRevision - and revision=(select max(revision) from ${DBArticle.table} where article_id=${article.id}) + and revision=(select max(revision) from ${dbArticle.table} where article_id=${article.id}) """ for { oldNotes <- tsql""" select document->'notes' as notes - from ${DBArticle.table} + from ${dbArticle.table} $whereClause for update """.map(editorNotesFromRS).runSingle() @@ -158,7 +158,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) case None => article.notes } count <- tsql""" - update ${DBArticle.table} + update ${dbArticle.table} set document=jsonb_set($dataObject,'{notes}',(${CirceUtil.toJsonString(notes.distinct)}::jsonb)), revision=$newRevision, slug=$slug @@ -178,10 +178,10 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) dataObject.setValue(CirceUtil.toJsonString(notes)) tsql""" - update ${DBArticle.table} + update ${dbArticle.table} set document=jsonb_set(document, '{notes}',(document -> 'notes') || $dataObject) where article_id=$articleId - and revision=(select max(revision) from ${DBArticle.table} where article_id=$articleId) + and revision=(select max(revision) from ${dbArticle.table} where article_id=$articleId) """ .update() .flatMap { @@ -197,41 +197,41 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) """) def withIds(articleIds: List[Long], offset: Long, pageSize: Long)(using session: DBSession): Try[Seq[Draft]] = { - val ar = DBArticle.syntax("ar") - val ar2 = DBArticle.syntax("ar2") + val ar = dbArticle.syntax("ar") + val ar2 = dbArticle.syntax("ar2") tsql""" select ${ar.result.*} - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where ar.document is not NULL and ar.article_id in ($articleIds) and ar.revision = ( select max(revision) - from ${DBArticle.as(ar2)} + from ${dbArticle.as(ar2)} where ar2.article_id = ar.article_id ) offset $offset limit $pageSize - """.map(DBArticle.fromResultSet(ar)).runList() + """.map(dbArticle.fromResultSet(ar)).runList() } def idsWithStatus(status: DraftStatus)(using session: DBSession): Try[List[ArticleIds]] = { - val ar = DBArticle.syntax("ar") + val ar = dbArticle.syntax("ar") tsql""" select article_id, external_id - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where ar.document is not NULL and ar.document#>>'{status,current}' = ${status.toString} """.map(rs => ArticleIds(rs.long("article_id"), externalIdsFromResultSet(rs))).runList() } def exists(id: Long)(using session: DBSession): Try[Boolean] = { - tsql"select article_id from ${DBArticle.table} where article_id=$id order by revision desc limit 1" + tsql"select article_id from ${dbArticle.table} where article_id=$id order by revision desc limit 1" .map(rs => rs.long("article_id")) .runSingle() .map(_.isDefined) } def deleteArticle(articleId: Long)(using session: DBSession): Try[Long] = { - tsql"delete from ${DBArticle.table} where article_id = $articleId" + tsql"delete from ${dbArticle.table} where article_id = $articleId" .update() .flatMap { case 1 => Success(articleId) @@ -240,7 +240,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) } def deleteArticleRevision(articleId: Long, revision: Int)(using session: DBSession): Try[Unit] = - tsql"delete from ${DBArticle.table} where article_id = $articleId and revision = $revision" + tsql"delete from ${dbArticle.table} where article_id = $articleId and revision = $revision" .update() .flatMap { case 1 => Success(()) @@ -248,15 +248,15 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) } def getCurrentAndPreviousRevision(articleId: Long)(using session: DBSession): Try[(Draft, Draft)] = { - val ar = DBArticle.syntax("ar") + val ar = dbArticle.syntax("ar") tsql""" select ${ar.result.*} - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where ar.article_id = $articleId order by revision desc limit 2 """ - .map(DBArticle.fromResultSet(ar)) + .map(dbArticle.fromResultSet(ar)) .runList() .flatMap { case List(current, previous) => Success((current, previous)) @@ -267,7 +267,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) def getIdFromExternalId(externalId: String)(using session: DBSession): Try[Option[Long]] = { tsql""" select article_id - from ${DBArticle.table} + from ${dbArticle.table} where $externalId = any (external_id) order by revision desc limit 1 @@ -285,7 +285,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) def getExternalIdsFromId(id: Long)(using session: DBSession): Try[List[String]] = { tsql""" select external_id - from ${DBArticle.table} + from ${dbArticle.table} where article_id=${id.toInt} order by revision desc limit 1 @@ -303,7 +303,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) def getExternalSubjectIdsFromId(id: Long)(using session: DBSession): Try[Seq[String]] = { tsql""" select external_subject_id - from ${DBArticle.table} + from ${dbArticle.table} where article_id=${id.toInt} order by revision desc limit 1 @@ -313,7 +313,7 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) def getImportIdFromId(id: Long)(using session: DBSession): Try[Option[String]] = { tsql""" select import_id - from ${DBArticle.table} + from ${dbArticle.table} where article_id=${id.toInt} order by revision desc limit 1 @@ -321,20 +321,20 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) } def getAllIds(using session: DBSession): Try[Seq[ArticleIds]] = { - tsql"select article_id, max(external_id) as external_id from ${DBArticle.table} group by article_id order by article_id asc" + tsql"select article_id, max(external_id) as external_id from ${dbArticle.table} group by article_id order by article_id asc" .map(rs => ArticleIds(rs.long("article_id"), externalIdsFromResultSet(rs))) .runList() } def articleCount(using session: DBSession): Try[Long] = { - tsql"select count(distinct article_id) from ${DBArticle.table} where document is not NULL" + tsql"select count(distinct article_id) from ${dbArticle.table} where document is not NULL" .map(rs => rs.long("count")) .runSingle() .map(_.getOrElse(0)) } def getArticlesByPage(pageSize: Int, offset: Int)(using session: DBSession): Try[Seq[Draft]] = { - val ar = DBArticle.syntax("ar") + val ar = dbArticle.syntax("ar") tsql""" select * from (select @@ -342,68 +342,68 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) ${ar.id} as row_id, ${ar.revision} as revision, max(revision) over (partition by article_id) as max_revision - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where document is not NULL) _ where revision = max_revision order by row_id offset $offset limit $pageSize - """.map(DBArticle.fromResultSet(ar)).runList() + """.map(dbArticle.fromResultSet(ar)).runList() } def minMaxArticleId(using session: DBSession): Try[(Long, Long)] = { - tsql"select coalesce(MIN(article_id),0) as mi, coalesce(MAX(article_id),0) as ma from ${DBArticle.table}" + tsql"select coalesce(MIN(article_id),0) as mi, coalesce(MAX(article_id),0) as ma from ${dbArticle.table}" .map(rs => (rs.long("mi"), rs.long("ma"))) .runSingle() .map(_.getOrElse((0L, 0L))) } override def minMaxId(using session: DBSession): Try[(Long, Long)] = { - tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${DBArticle.table}" + tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${dbArticle.table}" .map(rs => (rs.long("mi"), rs.long("ma"))) .runSingle() .map(_.getOrElse((0L, 0L))) } def documentsWithArticleIdBetween(min: Long, max: Long)(using session: DBSession): Try[List[Draft]] = { - val ar = DBArticle.syntax("ar") - val subquery = DBArticle.syntax("b") + val ar = dbArticle.syntax("ar") + val subquery = dbArticle.syntax("b") tsql""" select ${ar.result.*} - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where ar.document is not NULL and ar.article_id between $min and $max and ar.document#>>'{status,current}' <> ${DraftStatus.ARCHIVED.toString} and ar.revision = ( select max(b.revision) - from ${DBArticle.as(subquery)} + from ${dbArticle.as(subquery)} where b.article_id = ar.article_id ) - """.map(DBArticle.fromResultSet(ar)).runList() + """.map(dbArticle.fromResultSet(ar)).runList() } override def documentsWithIdBetween(min: Long, max: Long)(using session: DBSession): Try[List[Draft]] = { - val ar = DBArticle.syntax("ar") - val subquery = DBArticle.syntax("b") + val ar = dbArticle.syntax("ar") + val subquery = dbArticle.syntax("b") tsql""" select ${ar.result.*} - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where ar.document is not NULL and ar.id between $min and $max and ar.document#>>'{status,current}' <> ${DraftStatus.ARCHIVED.toString} and ar.revision = ( select max(b.revision) - from ${DBArticle.as(subquery)} + from ${dbArticle.as(subquery)} where b.article_id = ar.article_id ) - """.map(DBArticle.fromResultSet(ar)).runList() + """.map(dbArticle.fromResultSet(ar)).runList() } private def articleWhere(whereClause: SQLSyntax)(using session: DBSession): Try[Option[Draft]] = { - val ar = DBArticle.syntax("ar") + val ar = dbArticle.syntax("ar") - tsql"select ${ar.result.*} from ${DBArticle.as(ar)} where ar.document is not NULL and $whereClause " - .map(DBArticle.fromResultSet(ar)) + tsql"select ${ar.result.*} from ${dbArticle.as(ar)} where ar.document is not NULL and $whereClause " + .map(dbArticle.fromResultSet(ar)) .runSingle() } @@ -411,16 +411,16 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) articlesWhere(sqls"ar.article_id = $articleId").map(_.toList) private def articlesWhere(whereClause: SQLSyntax)(using session: DBSession): Try[Seq[Draft]] = { - val ar = DBArticle.syntax("ar") - tsql"select ${ar.result.*} from ${DBArticle.as(ar)} where ar.document is not NULL and $whereClause" - .map(DBArticle.fromResultSet(ar)) + val ar = dbArticle.syntax("ar") + tsql"select ${ar.result.*} from ${dbArticle.as(ar)} where ar.document is not NULL and $whereClause" + .map(dbArticle.fromResultSet(ar)) .runList() } def importIdOfArticle(externalId: String)(using session: DBSession): Try[Option[ImportId]] = { - val ar = DBArticle.syntax("ar") + val ar = dbArticle.syntax("ar") tsql"""select ${ar.result.*}, import_id, external_id - from ${DBArticle.as(ar)} + from ${dbArticle.as(ar)} where ar.document is not NULL and $externalId = any (ar.external_id)""" .map(rs => ImportId(rs.stringOpt("import_id"))) .runSingle() @@ -431,9 +431,9 @@ class DraftRepository(using draftErrorHelpers: DraftErrorHelpers, clock: Clock) def slugExists(slug: String, articleId: Option[Long])(using session: DBSession): Try[Boolean] = { val sq = articleId match { - case None => tsql"select count(*) from ${DBArticle.table} where slug = ${slug.toLowerCase}" + case None => tsql"select count(*) from ${dbArticle.table} where slug = ${slug.toLowerCase}" case Some(id) => - tsql"select count(*) from ${DBArticle.table} where slug = ${slug.toLowerCase} and article_id != $id" + tsql"select count(*) from ${dbArticle.table} where slug = ${slug.toLowerCase} and article_id != $id" } sq.map(rs => rs.long("count")).runSingle().map(_.exists(_ > 0)) } diff --git a/draft-api/src/main/scala/no/ndla/draftapi/repository/UserDataRepository.scala b/draft-api/src/main/scala/no/ndla/draftapi/repository/UserDataRepository.scala index 3a42137592..b4ea46d578 100644 --- a/draft-api/src/main/scala/no/ndla/draftapi/repository/UserDataRepository.scala +++ b/draft-api/src/main/scala/no/ndla/draftapi/repository/UserDataRepository.scala @@ -11,20 +11,20 @@ package no.ndla.draftapi.repository import com.typesafe.scalalogging.StrictLogging import no.ndla.common.CirceUtil import no.ndla.database.implicits.* -import no.ndla.draftapi.model.domain.UserData +import no.ndla.draftapi.model.domain.{DBUserData, UserData} import org.postgresql.util.PGobject import scalikejdbc.* import scala.util.Try -class UserDataRepository extends StrictLogging { +class UserDataRepository(using dbUserData: DBUserData) extends StrictLogging { def insert(userData: UserData)(using DBSession): Try[UserData] = { val dataObject = new PGobject() dataObject.setType("jsonb") dataObject.setValue(CirceUtil.toJsonString(userData)) tsql""" - insert into ${UserData.table} (user_id, document) values (${userData.userId}, $dataObject) + insert into ${dbUserData.table} (user_id, document) values (${userData.userId}, $dataObject) """ .updateAndReturnGeneratedKey() .map { userDataId => @@ -39,7 +39,7 @@ class UserDataRepository extends StrictLogging { dataObject.setValue(CirceUtil.toJsonString(userData)) tsql""" - update ${UserData.table} + update ${dbUserData.table} set document=$dataObject where user_id=${userData.userId} """ @@ -55,8 +55,8 @@ class UserDataRepository extends StrictLogging { def withUserId(userId: String)(using DBSession): Try[Option[UserData]] = userDataWhere(sqls"ud.user_id=$userId") private def userDataWhere(whereClause: SQLSyntax)(using DBSession): Try[Option[UserData]] = { - val ud = UserData.syntax("ud") - tsql"select ${ud.result.*} from ${UserData.as(ud)} where $whereClause".map(UserData.fromResultSet(ud)).runSingle() + val ud = dbUserData.syntax("ud") + tsql"select ${ud.result.*} from ${dbUserData.as(ud)} where $whereClause".map(UserData.fromResultSet(ud)).runSingle() } } diff --git a/draft-api/src/test/scala/no/ndla/draftapi/TestEnvironment.scala b/draft-api/src/test/scala/no/ndla/draftapi/TestEnvironment.scala index 08a1e8c1d3..1525288cbc 100644 --- a/draft-api/src/test/scala/no/ndla/draftapi/TestEnvironment.scala +++ b/draft-api/src/test/scala/no/ndla/draftapi/TestEnvironment.scala @@ -17,6 +17,7 @@ import no.ndla.draftapi.caching.MemoizeHelpers import no.ndla.draftapi.controller.* import no.ndla.draftapi.integration.* import no.ndla.draftapi.model.api.DraftErrorHelpers +import no.ndla.draftapi.model.domain.{DBArticle, DBUserData} import no.ndla.draftapi.repository.{DraftRepository, UserDataRepository} import no.ndla.draftapi.service.* import no.ndla.draftapi.service.search.* @@ -36,6 +37,8 @@ trait TestEnvironment extends TapirApplication[DraftApiProperties] with MockitoS implicit lazy val migrator: DBMigrator = mock[DBMigrator] implicit lazy val dbUtility: DBUtility = DBUtilityStub() + implicit lazy val dbArticle: DBArticle = new DBArticle + implicit lazy val dbUserData: DBUserData = new DBUserData implicit lazy val uuidUtil: UUIDUtil = mock[UUIDUtil] implicit lazy val memoizeHelpers: MemoizeHelpers = mock[MemoizeHelpers] implicit lazy val searchLanguage: SearchLanguage = mock[SearchLanguage] diff --git a/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/DBSubjectPage.scala b/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/DBSubjectPage.scala index 94d79504a7..c9ac5f9dd8 100644 --- a/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/DBSubjectPage.scala +++ b/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/DBSubjectPage.scala @@ -8,7 +8,6 @@ package no.ndla.frontpageapi.model.domain -import cats.implicits.catsSyntaxOptionId import no.ndla.common.model.domain.frontpage.SubjectPage import no.ndla.frontpageapi.Props import scalikejdbc.* @@ -19,7 +18,7 @@ class DBSubjectPage(using props: Props) { object DBSubjectPage extends SQLSyntaxSupport[SubjectPage] { override val tableName = "subjectpage" - override val schemaName: Option[String] = props.MetaSchema.toString.some + override val schemaName: Option[String] = Some(props.MetaSchema) def fromDb(lp: SyntaxProvider[SubjectPage])(rs: WrappedResultSet): Try[SubjectPage] = fromDb(lp.resultName)(rs) diff --git a/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FilmFrontPage.scala b/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FilmFrontPage.scala index f77d0b3d5f..3976f24c76 100644 --- a/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FilmFrontPage.scala +++ b/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FilmFrontPage.scala @@ -8,7 +8,6 @@ package no.ndla.frontpageapi.model.domain -import cats.implicits.* import io.circe.generic.semiauto.* import io.circe.parser.* import io.circe.{Decoder, Encoder} @@ -43,7 +42,7 @@ class DBFilmFrontPage(using props: Props) { object DBFilmFrontPageData extends SQLSyntaxSupport[FilmFrontPage] { override val tableName = "filmfrontpage" - override val schemaName: Option[String] = props.MetaSchema.toString.some + override val schemaName: Option[String] = Some(props.MetaSchema) def fromDb(lp: SyntaxProvider[FilmFrontPage])(rs: WrappedResultSet): Try[FilmFrontPage] = fromDb(lp.resultName)(rs) diff --git a/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FrontPage.scala b/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FrontPage.scala index f82fd81df1..67cecf798f 100644 --- a/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FrontPage.scala +++ b/frontpage-api/src/main/scala/no/ndla/frontpageapi/model/domain/FrontPage.scala @@ -14,7 +14,6 @@ import io.circe.parser.* import no.ndla.frontpageapi.Props import scalikejdbc.WrappedResultSet import scalikejdbc.* -import cats.implicits.* import scala.util.Try @@ -39,7 +38,7 @@ class DBFrontPage(using props: Props) { object DBFrontPageData extends SQLSyntaxSupport[FrontPage] { override val tableName = "mainfrontpage" - override val schemaName: Option[String] = props.MetaSchema.toString.some + override val schemaName: Option[String] = Some(props.MetaSchema) def fromResultSet(lp: SyntaxProvider[FrontPage])(rs: WrappedResultSet): Try[FrontPage] = fromResultSet(lp.resultName)(rs) diff --git a/image-api/src/main/scala/no/ndla/imageapi/ComponentRegistry.scala b/image-api/src/main/scala/no/ndla/imageapi/ComponentRegistry.scala index 6abb434cf4..728776d85c 100644 --- a/image-api/src/main/scala/no/ndla/imageapi/ComponentRegistry.scala +++ b/image-api/src/main/scala/no/ndla/imageapi/ComponentRegistry.scala @@ -17,6 +17,7 @@ import no.ndla.imageapi.db.migrationwithdependencies.{ V6__AddAgreementToImages, V7__TranslateUntranslatedAuthors, } +import no.ndla.imageapi.model.domain.DBImageMetaInformation import no.ndla.imageapi.repository.ImageRepository import no.ndla.imageapi.service.* import no.ndla.imageapi.service.search.{ @@ -49,6 +50,7 @@ class ComponentRegistry(properties: ImageApiProperties) extends TapirApplication given myndlaApiClient: MyNDLAApiClient = new MyNDLAApiClient given searchConverterService: SearchConverterService = new SearchConverterService given dbUtility: DBUtility = new DBUtility + given dbImageMetaInformation: DBImageMetaInformation = new DBImageMetaInformation given imageRepository: ImageRepository = new ImageRepository given imageIndexService: ImageIndexService = new ImageIndexService given imageSearchService: ImageSearchService = new ImageSearchService diff --git a/image-api/src/main/scala/no/ndla/imageapi/model/domain/ImageMetaInformation.scala b/image-api/src/main/scala/no/ndla/imageapi/model/domain/ImageMetaInformation.scala index 741dbbc6fc..3ebccb79dd 100644 --- a/image-api/src/main/scala/no/ndla/imageapi/model/domain/ImageMetaInformation.scala +++ b/image-api/src/main/scala/no/ndla/imageapi/model/domain/ImageMetaInformation.scala @@ -14,6 +14,7 @@ import no.ndla.common.CirceUtil import no.ndla.common.model.NDLADate import no.ndla.common.model.domain.Tag import no.ndla.common.model.domain.article.Copyright +import no.ndla.imageapi.Props import scalikejdbc.* import scala.util.Try @@ -35,8 +36,7 @@ case class ImageMetaInformation( inactive: Boolean, ) -object ImageMetaInformation extends SQLSyntaxSupport[ImageMetaInformation] { - override val tableName: String = "imagemetadata" +object ImageMetaInformation { implicit val encoder: Encoder[ImageMetaInformation] = deriveEncoder[ImageMetaInformation] implicit val decoder: Decoder[ImageMetaInformation] = deriveDecoder[ImageMetaInformation] @@ -50,3 +50,8 @@ object ImageMetaInformation extends SQLSyntaxSupport[ImageMetaInformation] { CirceUtil.tryParseAs[ImageMetaInformation](jsonString).map(_.copy(Some(id))) } } + +class DBImageMetaInformation(using props: Props) extends SQLSyntaxSupport[ImageMetaInformation] { + override val tableName: String = "imagemetadata" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/image-api/src/main/scala/no/ndla/imageapi/repository/ImageRepository.scala b/image-api/src/main/scala/no/ndla/imageapi/repository/ImageRepository.scala index 875a02f3c6..1b6d9b2193 100644 --- a/image-api/src/main/scala/no/ndla/imageapi/repository/ImageRepository.scala +++ b/image-api/src/main/scala/no/ndla/imageapi/repository/ImageRepository.scala @@ -20,9 +20,13 @@ import no.ndla.database.implicits.* import scala.util.{Failure, Success, Try} -class ImageRepository(using dbUtility: DBUtility) extends StrictLogging { +class ImageRepository(using dbUtility: DBUtility, dbImageMetaInformation: DBImageMetaInformation) + extends StrictLogging { def imageCount(implicit session: DBSession = dbUtility.readOnlySession): Try[Long] = - tsql"select count(*) from ${ImageMetaInformation.table}".map(rs => rs.long("count")).runSingle().map(_.getOrElse(0)) + tsql"select count(*) from ${dbImageMetaInformation.table}" + .map(rs => rs.long("count")) + .runSingle() + .map(_.getOrElse(0)) def withId(id: Long): Try[Option[ImageMetaInformation]] = dbUtility.readOnly { implicit session => imageMetaInformationWhere(sqls"im.id = $id") @@ -83,10 +87,10 @@ class ImageRepository(using dbUtility: DBUtility) extends StrictLogging { private def imageMetaInformationWhere( whereClause: SQLSyntax )(implicit session: DBSession): Try[Option[ImageMetaInformation]] = { - val im = ImageMetaInformation.syntax("im") + val im = dbImageMetaInformation.syntax("im") tsql""" SELECT ${im.result.*} - FROM ${ImageMetaInformation.as(im)} + FROM ${dbImageMetaInformation.as(im)} WHERE $whereClause """.map(ImageMetaInformation.fromResultSet(im.resultName)).runSingleFlat() } @@ -94,10 +98,10 @@ class ImageRepository(using dbUtility: DBUtility) extends StrictLogging { private def imageMetaInformationsWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Try[List[ImageMetaInformation]] = { - val im = ImageMetaInformation.syntax("im") + val im = dbImageMetaInformation.syntax("im") tsql""" SELECT ${im.result.*} - FROM ${ImageMetaInformation.as(im)} + FROM ${dbImageMetaInformation.as(im)} WHERE $whereClause """.map(ImageMetaInformation.fromResultSet(im.resultName)).runListFlat() } @@ -123,25 +127,25 @@ class ImageRepository(using dbUtility: DBUtility) extends StrictLogging { } def minMaxId(implicit session: DBSession = dbUtility.autoSession): Try[(Long, Long)] = - tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${ImageMetaInformation.table}" + tsql"select coalesce(MIN(id),0) as mi, coalesce(MAX(id),0) as ma from ${dbImageMetaInformation.table}" .map(rs => (rs.long("mi"), rs.long("ma"))) .runSingle() .map(_.getOrElse((0L, 0L))) def getRandomImage()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[ImageMetaInformation]] = { - val im = ImageMetaInformation.syntax("im") + val im = dbImageMetaInformation.syntax("im") tsql"""SELECT ${im.result.*} - FROM ${ImageMetaInformation.as(im)} TABLESAMPLE public.system_rows(1) + FROM ${dbImageMetaInformation.as(im)} TABLESAMPLE public.system_rows(1) LIMIT 1""".map(ImageMetaInformation.fromResultSet(im)).runSingle().map(_.sequence).flatten } def getByPage(pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession ): Try[Seq[ImageMetaInformation]] = { - val im = ImageMetaInformation.syntax("im") + val im = dbImageMetaInformation.syntax("im") tsql""" select ${im.result.*} - from ${ImageMetaInformation.as(im)} + from ${dbImageMetaInformation.as(im)} where metadata is not null order by ${im.id} offset $offset @@ -151,7 +155,7 @@ class ImageRepository(using dbUtility: DBUtility) extends StrictLogging { // TODO: Remove this after completing variants migration of existing images def getImageFileBatched(batchSize: Long): Try[Iterator[Seq[ImageMetaInformation]]] = - val im = ImageMetaInformation.syntax("im") + val im = dbImageMetaInformation.syntax("im") val total = imageCount match { case Success(count) => count case Failure(ex) => return Failure(ex) @@ -173,7 +177,7 @@ class ImageRepository(using dbUtility: DBUtility) extends StrictLogging { dbUtility.readOnly { implicit session => tsql""" select ${im.result.*} - from ${ImageMetaInformation.as(im)} + from ${dbImageMetaInformation.as(im)} where metadata is not null order by ${im.id} offset $cursor diff --git a/image-api/src/test/scala/no/ndla/imageapi/TestEnvironment.scala b/image-api/src/test/scala/no/ndla/imageapi/TestEnvironment.scala index 18b554380c..7b272c7144 100644 --- a/image-api/src/test/scala/no/ndla/imageapi/TestEnvironment.scala +++ b/image-api/src/test/scala/no/ndla/imageapi/TestEnvironment.scala @@ -12,6 +12,7 @@ import no.ndla.common.Clock import no.ndla.common.aws.{NdlaCloudFrontClient, NdlaS3Client} import no.ndla.database.{DBMigrator, DBUtility, DataSource} import no.ndla.imageapi.controller.{ImageControllerV2, ImageControllerV3, InternController, RawController} +import no.ndla.imageapi.model.domain.DBImageMetaInformation import no.ndla.imageapi.repository.* import no.ndla.imageapi.service.* import no.ndla.imageapi.service.search.{ @@ -45,11 +46,12 @@ trait TestEnvironment extends TapirApplication[ImageApiProperties] with MockitoS val TestData: TestData = new TestData - implicit lazy val migrator: DBMigrator = mock[DBMigrator] - implicit lazy val s3Client: NdlaS3Client = mock[NdlaS3Client] - implicit lazy val cloudFrontClient: NdlaCloudFrontClient = mock[NdlaCloudFrontClient] - implicit lazy val dataSource: DataSource = mock[DataSource] - implicit lazy val dbUtility: DBUtility = new DBUtility + implicit lazy val migrator: DBMigrator = mock[DBMigrator] + implicit lazy val s3Client: NdlaS3Client = mock[NdlaS3Client] + implicit lazy val cloudFrontClient: NdlaCloudFrontClient = mock[NdlaCloudFrontClient] + implicit lazy val dataSource: DataSource = mock[DataSource] + implicit lazy val dbUtility: DBUtility = new DBUtility + implicit lazy val dbImageMetaInformation: DBImageMetaInformation = new DBImageMetaInformation implicit lazy val imageIndexService: ImageIndexService = mock[ImageIndexService] implicit lazy val imageSearchService: ImageSearchService = mock[ImageSearchService] diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/ComponentRegistry.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/ComponentRegistry.scala index 24f8adf4a7..11e5446aba 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/ComponentRegistry.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/ComponentRegistry.scala @@ -27,6 +27,7 @@ import no.ndla.learningpathapi.db.migrationwithdependencies.{ V33__AiDefaultEnabledOrgs, } import no.ndla.learningpathapi.integration.* +import no.ndla.learningpathapi.model.domain.DBLearningPath import no.ndla.learningpathapi.repository.LearningPathRepository import no.ndla.learningpathapi.service.* import no.ndla.learningpathapi.service.search.{SearchConverterServiceComponent, SearchIndexService, SearchService} @@ -53,6 +54,7 @@ import no.ndla.database.DBUtility class ComponentRegistry(properties: LearningpathApiProperties) extends TapirApplication[LearningpathApiProperties] { given props: LearningpathApiProperties = properties + given dbLearningPath: DBLearningPath = new DBLearningPath given dataSource: DataSource = DataSource.getDataSource implicit lazy val clock: Clock = new Clock given uuidUtil: UUIDUtil = new UUIDUtil diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/DBLearningPath.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/DBLearningPath.scala index 44bc1030b8..8ac8b6aba1 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/DBLearningPath.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/model/domain/DBLearningPath.scala @@ -10,10 +10,12 @@ package no.ndla.learningpathapi.model.domain import no.ndla.common.CirceUtil import no.ndla.common.model.domain.learningpath.LearningPath +import no.ndla.learningpathapi.Props import scalikejdbc.* -object DBLearningPath extends SQLSyntaxSupport[LearningPath] { - override val tableName = "learningpaths" +class DBLearningPath(using props: Props) extends SQLSyntaxSupport[LearningPath] { + override val tableName = "learningpaths" + override val schemaName: Option[String] = Some(props.MetaSchema) def fromResultSet(lp: SyntaxProvider[LearningPath])(rs: WrappedResultSet): LearningPath = fromResultSet(lp.resultName)(rs) diff --git a/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala b/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala index 7ea0ad1c02..108a4c4eed 100644 --- a/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala +++ b/learningpath-api/src/main/scala/no/ndla/learningpathapi/repository/LearningPathRepository.scala @@ -21,7 +21,7 @@ import no.ndla.database.implicits.* import java.util.UUID import scala.util.{Failure, Success, Try} -class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { +class LearningPathRepository(using dbUtility: DBUtility, dbLearningPath: DBLearningPath) extends StrictLogging { def inTransaction[A](work: DBSession => A)(implicit session: DBSession = null): A = { Option(session) match { @@ -65,9 +65,9 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { def learningStepsFor( learningPathId: Long )(implicit session: DBSession = dbUtility.readOnlySession): Seq[LearningStep] = { - val lp = DBLearningPath.syntax("lp") - tsql"select ${lp.result.*} from ${DBLearningPath.as(lp)} where ${lp.id} = $learningPathId" - .map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs).learningsteps) + val lp = dbLearningPath.syntax("lp") + tsql"select ${lp.result.*} from ${dbLearningPath.as(lp)} where ${lp.id} = $learningPathId" + .map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs).learningsteps) .runSingle() .get .getOrElse(Seq.empty) @@ -211,14 +211,14 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { def learningPathsWithIdBetween(min: Long, max: Long)(implicit session: DBSession = dbUtility.readOnlySession ): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") val status = LearningPathStatus.PUBLISHED.toString tsql"""select ${lp.result.*} - from ${DBLearningPath.as(lp)} + from ${dbLearningPath.as(lp)} where lp.document->>'status' = $status and lp.id between $min and $max - """.map(DBLearningPath.fromResultSet(lp.resultName)).runList().get + """.map(dbLearningPath.fromResultSet(lp.resultName)).runList().get } def minMaxId(implicit session: DBSession = dbUtility.readOnlySession): (Long, Long) = { @@ -268,9 +268,9 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { private def learningPathsWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") - tsql"select ${lp.result.*} from ${DBLearningPath.as(lp)} where $whereClause" - .map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps) + val lp = dbLearningPath.syntax("lp") + tsql"select ${lp.result.*} from ${dbLearningPath.as(lp)} where $whereClause" + .map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps) .runList() .get } @@ -278,9 +278,9 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { private def learningPathsWhereWithInactive( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") - tsql"select ${lp.result.*} from ${DBLearningPath.as(lp)} where $whereClause" - .map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs)) + val lp = dbLearningPath.syntax("lp") + tsql"select ${lp.result.*} from ${dbLearningPath.as(lp)} where $whereClause" + .map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs)) .runList() .get } @@ -288,9 +288,9 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { private def learningPathWhere( whereClause: SQLSyntax )(implicit session: DBSession = dbUtility.readOnlySession): Option[LearningPath] = { - val lp = DBLearningPath.syntax("lp") - tsql"select ${lp.result.*} from ${DBLearningPath.as(lp)} where $whereClause" - .map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps) + val lp = dbLearningPath.syntax("lp") + tsql"select ${lp.result.*} from ${dbLearningPath.as(lp)} where $whereClause" + .map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps) .runSingle() .get } @@ -298,32 +298,32 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { def pageWithIds(ids: Seq[Long], pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession ): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") tsql""" select ${lp.resultAll} - from ${DBLearningPath.as(lp)} + from ${dbLearningPath.as(lp)} where ${lp.c("id")} in ($ids) order by ${lp.id} limit $pageSize offset $offset - """.map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps).runList().get + """.map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps).runList().get } def getAllLearningPathsByPage(pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession ): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") tsql""" select ${lp.resultAll}, ${lp.id} as row_id - from ${DBLearningPath.as(lp)} + from ${dbLearningPath.as(lp)} order by row_id limit $pageSize offset $offset - """.map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps).runList().get + """.map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps).runList().get } def getExternalLinkStepSamples()(implicit session: DBSession = dbUtility.readOnlySession): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") tsql""" WITH candidates AS ( SELECT DISTINCT clp.id @@ -346,25 +346,25 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { ) SELECT ${lp.result.*} FROM matched_ids ids - JOIN ${DBLearningPath.as(lp)} ON ${lp.id} = ids.id - """.map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps).runList().get + JOIN ${dbLearningPath.as(lp)} ON ${lp.id} = ids.id + """.map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs).withOnlyActiveSteps).runList().get } def getPublishedLearningPathByPage(pageSize: Int, offset: Int)(implicit session: DBSession = dbUtility.readOnlySession ): List[LearningPath] = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") val lps = SubQuery.syntax("lps").include(lp) tsql""" select ${lps.resultAll} from (select ${lp.resultAll}, ${lp.id} as row_id - from ${DBLearningPath.as(lp)} + from ${dbLearningPath.as(lp)} where document#>>'{status}' = ${LearningPathStatus.PUBLISHED.toString} order by ${lp.id} limit $pageSize offset $offset) lps order by row_id - """.map(rs => DBLearningPath.fromResultSet(lps(lp).resultName)(rs).withOnlyActiveSteps).runList().get + """.map(rs => dbLearningPath.fromResultSet(lps(lp).resultName)(rs).withOnlyActiveSteps).runList().get } def learningPathsWithStatus( @@ -374,8 +374,8 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { } def publishedLearningPathCount(implicit session: DBSession = dbUtility.readOnlySession): Long = { - val lp = DBLearningPath.syntax("lp") - tsql"select count(*) from ${DBLearningPath.as(lp)} where document#>>'{status}' = ${LearningPathStatus.PUBLISHED.toString}" + val lp = dbLearningPath.syntax("lp") + tsql"select count(*) from ${dbLearningPath.as(lp)} where document#>>'{status}' = ${LearningPathStatus.PUBLISHED.toString}" .map(rs => rs.long("count")) .runSingle() .get @@ -383,22 +383,22 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { } def learningPathCount(implicit session: DBSession = dbUtility.readOnlySession): Long = { - val lp = DBLearningPath.syntax("lp") - tsql"select count(*) from ${DBLearningPath.as(lp)}".map(rs => rs.long("count")).runSingle().get.getOrElse(0) + val lp = dbLearningPath.syntax("lp") + tsql"select count(*) from ${dbLearningPath.as(lp)}".map(rs => rs.long("count")).runSingle().get.getOrElse(0) } def myNdlaLearningPathCount(implicit session: DBSession = dbUtility.readOnlySession): Long = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") tsql""" - select count(*) from ${DBLearningPath.as(lp)} + select count(*) from ${dbLearningPath.as(lp)} where document@>'{"isMyNDLAOwner": true}' and document->>'status' != ${LearningPathStatus.DELETED.toString} """.map(rs => rs.long("count")).runSingle().get.getOrElse(0) } def myNdlaLearningPathOwnerCount(implicit session: DBSession = dbUtility.readOnlySession): Long = { - val lp = DBLearningPath.syntax("lp") + val lp = dbLearningPath.syntax("lp") tsql""" - select count(distinct document ->> 'owner') from ${DBLearningPath.as(lp)} + select count(distinct document ->> 'owner') from ${dbLearningPath.as(lp)} where document@>'{"isMyNDLAOwner": true}' and document->>'status' != ${LearningPathStatus.DELETED.toString} """.map(rs => rs.long("count")).runSingle().get.getOrElse(0) } @@ -445,9 +445,9 @@ class LearningPathRepository(using dbUtility: DBUtility) extends StrictLogging { private[repository] def learningPathWhereWithInactiveSteps( whereClause: SQLSyntax )(implicit session: DBSession = ReadOnlyAutoSession): Option[LearningPath] = { - val lp = DBLearningPath.syntax("lp") - tsql"select ${lp.result.*} from ${DBLearningPath.as(lp)} where $whereClause" - .map(rs => DBLearningPath.fromResultSet(lp.resultName)(rs)) + val lp = dbLearningPath.syntax("lp") + tsql"select ${lp.result.*} from ${dbLearningPath.as(lp)} where $whereClause" + .map(rs => dbLearningPath.fromResultSet(lp.resultName)(rs)) .runSingle() .get } diff --git a/learningpath-api/src/test/scala/no/ndla/learningpathapi/TestEnvironment.scala b/learningpath-api/src/test/scala/no/ndla/learningpathapi/TestEnvironment.scala index 3e17dfd07d..bc51a64523 100644 --- a/learningpath-api/src/test/scala/no/ndla/learningpathapi/TestEnvironment.scala +++ b/learningpath-api/src/test/scala/no/ndla/learningpathapi/TestEnvironment.scala @@ -13,6 +13,7 @@ import no.ndla.common.{Clock, UUIDUtil} import no.ndla.database.{DBMigrator, DataSource} import no.ndla.learningpathapi.controller.{InternController, LearningpathControllerV2, StatsController} import no.ndla.learningpathapi.integration.* +import no.ndla.learningpathapi.model.domain.DBLearningPath import no.ndla.learningpathapi.repository.LearningPathRepository import no.ndla.learningpathapi.service.* import no.ndla.learningpathapi.service.search.{SearchConverterServiceComponent, SearchIndexService, SearchService} @@ -37,6 +38,7 @@ import no.ndla.scalatestsuite.DBUtilityStub trait TestEnvironment extends TapirApplication[LearningpathApiProperties] with MockitoSugar { implicit lazy val props: LearningpathApiProperties = new LearningpathApiProperties + implicit lazy val dbLearningPath: DBLearningPath = new DBLearningPath implicit lazy val migrator: DBMigrator = mock[DBMigrator] implicit lazy val dataSource: DataSource = mock[DataSource] diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/ComponentRegistry.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/ComponentRegistry.scala index a5631c0a12..393a40db9c 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/ComponentRegistry.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/ComponentRegistry.scala @@ -28,6 +28,15 @@ import no.ndla.myndlaapi.integration.{ TaxonomyApiClient, } import no.ndla.myndlaapi.integration.nodebb.NodeBBClient +import no.ndla.myndlaapi.model.domain.{ + DBConfigMeta, + DBMyNDLAUser, + DBFolder, + DBResource, + DBResourceConnection, + DBRobotDefinition, + DBSavedSharedFolder, +} import no.ndla.myndlaapi.repository.{ConfigRepository, FolderRepository, RobotRepository, UserRepository} import no.ndla.myndlaapi.service.{ ConfigService, @@ -49,11 +58,18 @@ import no.ndla.network.tapir.{ } class ComponentRegistry(properties: MyNdlaApiProperties) extends TapirApplication[MyNdlaApiProperties] { - given props: MyNdlaApiProperties = properties - implicit lazy val clock: Clock = new Clock - given dataSource: DataSource = DataSource.getDataSource - given migrator: DBMigrator = DBMigrator(v16__MigrateResourcePaths) - given dbUtil: DBUtility = new DBUtility + given props: MyNdlaApiProperties = properties + implicit lazy val clock: Clock = new Clock + given dataSource: DataSource = DataSource.getDataSource + given migrator: DBMigrator = DBMigrator(v16__MigrateResourcePaths) + given dbUtil: DBUtility = new DBUtility + given dbConfigMeta: DBConfigMeta = new DBConfigMeta + given dbMyNDLAUser: DBMyNDLAUser = new DBMyNDLAUser + given dbResourceConnection: DBResourceConnection = new DBResourceConnection + given dbResource: DBResource = new DBResource + given dbFolder: DBFolder = new DBFolder + given dbSavedSharedFolder: DBSavedSharedFolder = new DBSavedSharedFolder + given dbRobotDefinition: DBRobotDefinition = new DBRobotDefinition given ndlaClient: NdlaClient = new NdlaClient implicit lazy val myndlaApiClient: InternalMyNDLAApiClient = new InternalMyNDLAApiClient diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBConfigMeta.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBConfigMeta.scala new file mode 100644 index 0000000000..9b979de649 --- /dev/null +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBConfigMeta.scala @@ -0,0 +1,18 @@ +/* + * Part of NDLA myndla-api + * Copyright (C) 2024 NDLA + * + * See LICENSE + * + */ + +package no.ndla.myndlaapi.model.domain + +import no.ndla.common.model.domain.config.ConfigMeta +import no.ndla.myndlaapi.Props +import scalikejdbc.SQLSyntaxSupport + +class DBConfigMeta(using props: Props) extends SQLSyntaxSupport[ConfigMeta] { + override val tableName: String = "configtable" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBMyNDLAUser.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBMyNDLAUser.scala index 6b52dcd44f..ade15d9c99 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBMyNDLAUser.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/DBMyNDLAUser.scala @@ -11,11 +11,13 @@ package no.ndla.myndlaapi.model.domain import no.ndla.common.CirceUtil import no.ndla.common.model.NDLADate import no.ndla.common.model.domain.myndla.{MyNDLAUser, MyNDLAUserDocument} +import no.ndla.myndlaapi.Props import scalikejdbc.* -object DBMyNDLAUser extends SQLSyntaxSupport[MyNDLAUser] { +class DBMyNDLAUser(using props: Props) extends SQLSyntaxSupport[MyNDLAUser] { - override val tableName = "my_ndla_users" + override val tableName = "my_ndla_users" + override val schemaName: Option[String] = Some(props.MetaSchema) def fromResultSet(lp: SyntaxProvider[MyNDLAUser])(rs: WrappedResultSet): MyNDLAUser = fromResultSetWithWrapper((s: String) => lp.resultName.c(s))(rs) diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Folder.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Folder.scala index 3682ac174f..ac4021339c 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Folder.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Folder.scala @@ -10,6 +10,7 @@ package no.ndla.myndlaapi.model.domain import cats.implicits.catsSyntaxOptionId import no.ndla.common.model.NDLADate +import no.ndla.myndlaapi.Props import no.ndla.common.model.domain.myndla.{FolderStatus, MyNDLAUser} import no.ndla.network.model.FeideID import scalikejdbc.* @@ -81,8 +82,7 @@ case class Folder( } } -object Folder extends SQLSyntaxSupport[Folder] { - override val tableName = "folders" +object Folder { def fromResultSet(lp: SyntaxProvider[Folder])(rs: WrappedResultSet): Try[Folder] = { val wrapper: String => String = (s: String) => lp.resultName.c(s) @@ -125,3 +125,8 @@ object Folder extends SQLSyntaxSupport[Folder] { ) } } + +class DBFolder(using props: Props) extends SQLSyntaxSupport[Folder] { + override val tableName: String = "folders" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Resource.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Resource.scala index e13f585d0c..2b494a1f7b 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Resource.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/Resource.scala @@ -14,6 +14,7 @@ import io.circe.{Decoder, Encoder} import no.ndla.common.CirceUtil import no.ndla.common.implicits.* import no.ndla.common.model.NDLADate +import no.ndla.myndlaapi.Props import no.ndla.common.model.domain.ResourceType import no.ndla.network.model.FeideID import scalikejdbc.* @@ -63,8 +64,7 @@ case class Resource( override val rank: Option[Int] = sortRank } -object Resource extends SQLSyntaxSupport[Resource] { - override val tableName = "resources" +object Resource { implicit val encoder: Encoder[Resource] = deriveEncoder implicit val decoder: Decoder[Resource] = deriveDecoder @@ -122,3 +122,8 @@ object Resource extends SQLSyntaxSupport[Resource] { } yield metaData.toFullResource(id, path, resourceType, feideId, created, connection) } } + +class DBResource(using props: Props) extends SQLSyntaxSupport[Resource] { + override val tableName: String = "resources" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/ResourceConnection.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/ResourceConnection.scala index 5f43fe4878..602e38d97f 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/ResourceConnection.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/ResourceConnection.scala @@ -10,6 +10,7 @@ package no.ndla.myndlaapi.model.domain import io.circe.{Decoder, Encoder} import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} +import no.ndla.myndlaapi.Props import no.ndla.common.model.NDLADate import scalikejdbc.* @@ -22,12 +23,10 @@ case class ResourceConnection(folderId: Option[UUID], resourceId: UUID, rank: In override val sortRank: Option[Int] = Some(rank) } -object ResourceConnection extends SQLSyntaxSupport[ResourceConnection] { +object ResourceConnection { implicit val encoder: Encoder[ResourceConnection] = deriveEncoder implicit val decoder: Decoder[ResourceConnection] = deriveDecoder - override val tableName = "resource_connections" - def fromResultSet(lp: SyntaxProvider[ResourceConnection])(rs: WrappedResultSet): Try[ResourceConnection] = fromResultSet(s => lp.resultName.c(s), rs) @@ -42,3 +41,8 @@ object ResourceConnection extends SQLSyntaxSupport[ResourceConnection] { } } + +class DBResourceConnection(using props: Props) extends SQLSyntaxSupport[ResourceConnection] { + override val tableName: String = "resource_connections" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/RobotDefinition.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/RobotDefinition.scala index dc4901f5b3..751e95fc4c 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/RobotDefinition.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/RobotDefinition.scala @@ -14,6 +14,7 @@ import no.ndla.common.CirceUtil import no.ndla.common.errors.{AccessDeniedException, NotFoundException} import no.ndla.common.implicits.* import no.ndla.common.model.NDLADate +import no.ndla.myndlaapi.Props import no.ndla.myndlaapi.model.api.robot.RobotConfigurationDTO import no.ndla.network.model.FeideID import scalikejdbc.* @@ -76,8 +77,7 @@ object RobotConfiguration { } -object RobotDefinition extends SQLSyntaxSupport[RobotDefinition] { - override val tableName: String = "robot_definitions" +object RobotDefinition { def fromResultSet(sp: SyntaxProvider[RobotDefinition])(rs: WrappedResultSet): Try[RobotDefinition] = { val wrapper: String => String = (s: String) => sp.resultName.c(s) @@ -115,3 +115,8 @@ object RobotDefinition extends SQLSyntaxSupport[RobotDefinition] { } } + +class DBRobotDefinition(using props: Props) extends SQLSyntaxSupport[RobotDefinition] { + override val tableName: String = "robot_definitions" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/SavedSharedFolder.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/SavedSharedFolder.scala index 5a77198189..9e1e4886d8 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/SavedSharedFolder.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/model/domain/SavedSharedFolder.scala @@ -10,6 +10,7 @@ package no.ndla.myndlaapi.model.domain import io.circe.{Decoder, Encoder} import io.circe.generic.semiauto.{deriveDecoder, deriveEncoder} +import no.ndla.myndlaapi.Props import no.ndla.network.model.FeideID import scalikejdbc.* @@ -18,12 +19,10 @@ import scala.util.Try case class SavedSharedFolder(folderId: UUID, feideId: FeideID, rank: Int) {} -object SavedSharedFolder extends SQLSyntaxSupport[SavedSharedFolder] { +object SavedSharedFolder { implicit val encoder: Encoder[SavedSharedFolder] = deriveEncoder implicit val decoder: Decoder[SavedSharedFolder] = deriveDecoder - override val tableName = "saved_shared_folder" - def fromResultSet(sp: SyntaxProvider[SavedSharedFolder], rs: WrappedResultSet): Try[SavedSharedFolder] = { fromResultSet((s: String) => sp.resultName.c(s))(rs) } @@ -37,3 +36,8 @@ object SavedSharedFolder extends SQLSyntaxSupport[SavedSharedFolder] { } yield SavedSharedFolder(folderId = folderId, feideId = feideId, rank = rank) } } + +class DBSavedSharedFolder(using props: Props) extends SQLSyntaxSupport[SavedSharedFolder] { + override val tableName: String = "saved_shared_folder" + override val schemaName: Option[String] = Some(props.MetaSchema) +} diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/ConfigRepository.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/ConfigRepository.scala index 80f75376af..f34aef86ba 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/ConfigRepository.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/ConfigRepository.scala @@ -13,13 +13,14 @@ import io.circe.syntax.* import no.ndla.common.model.domain.config.{ConfigKey, ConfigMeta} import no.ndla.database.DBUtility import no.ndla.database.implicits.* +import no.ndla.myndlaapi.model.domain.DBConfigMeta import org.postgresql.util.PGobject import scalikejdbc.* import sqls.count import scala.util.{Success, Try} -class ConfigRepository(using dbUtility: DBUtility) extends StrictLogging { +class ConfigRepository(using dbUtility: DBUtility, dbConfigMeta: DBConfigMeta) extends StrictLogging { import ConfigMeta.* implicit val configValueParameterBinderFactory: ParameterBinderFactory[ConfigMeta] = @@ -33,26 +34,26 @@ class ConfigRepository(using dbUtility: DBUtility) extends StrictLogging { } def configCount(implicit session: DBSession = dbUtility.readOnlySession): Int = { - val c = ConfigMeta.syntax("c") + val c = dbConfigMeta.syntax("c") withSQL { - select(count(c.column("configkey"))).from(ConfigMeta as c) + select(count(c.column("configkey"))).from(dbConfigMeta as c) }.map(_.int(1)).single().getOrElse(0) } def updateConfigParam(config: ConfigMeta)(implicit session: DBSession = dbUtility.autoSession): Try[ConfigMeta] = { val updatedCount = withSQL { - update(ConfigMeta) - .set(ConfigMeta.column.column("value") -> config) + update(dbConfigMeta) + .set(dbConfigMeta.column.column("value") -> config) .where - .eq(ConfigMeta.column.column("configkey"), config.key.entryName) + .eq(dbConfigMeta.column.column("configkey"), config.key.entryName) }.update() if (updatedCount != 1) { logger.info(s"No existing value for ${config.key}, inserting the value.") val _ = withSQL { - insertInto(ConfigMeta).namedValues( - ConfigMeta.column.c("configkey") -> config.key.entryName, - ConfigMeta.column.c("value") -> config, + insertInto(dbConfigMeta).namedValues( + dbConfigMeta.column.c("configkey") -> config.key.entryName, + dbConfigMeta.column.c("value") -> config, ) }.update() Success(config) @@ -66,10 +67,10 @@ class ConfigRepository(using dbUtility: DBUtility) extends StrictLogging { session: DBSession = dbUtility.readOnlySession ): Try[Option[ConfigMeta]] = val keyName = key.entryName - val c = ConfigMeta.syntax("c") + val c = dbConfigMeta.syntax("c") tsql""" select ${c.result.*} - from ${ConfigMeta.as(c)} + from ${dbConfigMeta.as(c)} where configkey = $keyName; """.map(ConfigMeta.fromResultSet(c)).runSingleFlat() } diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/FolderRepository.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/FolderRepository.scala index 6c2c67da2e..69c6e4e574 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/FolderRepository.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/FolderRepository.scala @@ -21,6 +21,10 @@ import no.ndla.myndlaapi.{maybeUuidBinder, uuidBinder, uuidParameterFactory} import no.ndla.myndlaapi.model.domain.{ BulkInserts, DBMyNDLAUser, + DBFolder, + DBResource, + DBResourceConnection, + DBSavedSharedFolder, Folder, ResourceConnection, NDLASQLException, @@ -38,7 +42,15 @@ import java.util.UUID import scala.collection.IndexedSeq.iterableFactory import scala.util.{Failure, Success, Try} -class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictLogging { +class FolderRepository(using + clock: Clock, + dbUtility: DBUtility, + dbMyNDLAUser: DBMyNDLAUser, + dbFolder: DBFolder, + dbResourceConnection: DBResourceConnection, + dbResource: DBResource, + dbSavedSharedFolder: DBSavedSharedFolder, +) extends StrictLogging { def getSession(readOnly: Boolean): DBSession = if (readOnly) dbUtility.readOnlySession else dbUtility.autoSession @@ -55,10 +67,10 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL if (folderData.status == FolderStatus.SHARED) Some(created) else None - val column = Folder.column.c + val column = dbFolder.column.c val _ = withSQL { insert - .into(Folder) + .into(dbFolder) .namedValues( column("id") -> newId, column("parent_id") -> folderData.parentId, @@ -94,11 +106,11 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL document: ResourceDocument, )(implicit session: DBSession = dbUtility.autoSession): Try[Resource] = Try { val newId = UUID.randomUUID() - val column = Resource.column.c + val column = dbResource.column.c val _ = withSQL { insert - .into(Resource) + .into(dbResource) .namedValues( column("id") -> newId, column("feide_id") -> feideId, @@ -118,12 +130,12 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL ): Try[ResourceConnection] = Try { val _ = withSQL { insert - .into(ResourceConnection) + .into(dbResourceConnection) .namedValues( - ResourceConnection.column.folderId -> folderId, - ResourceConnection.column.resourceId -> resourceId, - ResourceConnection.column.rank -> rank, - ResourceConnection.column.favoritedDate -> favoritedDate, + dbResourceConnection.column.folderId -> folderId, + dbResourceConnection.column.resourceId -> resourceId, + dbResourceConnection.column.rank -> rank, + dbResourceConnection.column.favoritedDate -> favoritedDate, ) }.update() logger.info(s"Inserted new folder-resource connection with folder id $folderId and resource id $resourceId") @@ -134,9 +146,9 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def updateFolder(id: UUID, feideId: FeideID, folder: Folder)(implicit session: DBSession = dbUtility.autoSession ): Try[Folder] = Try { - val column = Folder.column.c + val column = dbFolder.column.c withSQL { - update(Folder) + update(dbFolder) .set( column("parent_id") -> folder.parentId, column("name") -> folder.name, @@ -165,9 +177,9 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL val newSharedValue = if (newStatus == FolderStatus.SHARED) Some(clock.now()) else None - val column = Folder.column.c + val column = dbFolder.column.c withSQL { - update(Folder) + update(dbFolder) .set(column("status") -> newStatus.toString, column("shared") -> newSharedValue) .where .in(column("id"), folderIds) @@ -187,7 +199,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL dataObject.setValue(CirceUtil.toJsonString(resource)) tsql""" - update ${Resource.table} + update ${dbResource.table} set document=$dataObject where id=${resource.id} """.update() match { @@ -201,7 +213,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def resourceConnectionCount(resourceId: UUID)(implicit session: DBSession = dbUtility.autoSession): Try[Long] = { - tsql"select count(*) from ${ResourceConnection.table} where resource_id=$resourceId" + tsql"select count(*) from ${dbResourceConnection.table} where resource_id=$resourceId" .map(rs => rs.long("count")) .runSingle() .map(_.getOrElse(0)) @@ -214,7 +226,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL case Some(id) => sqls"folder_id=$id" case None => sqls"folder_id is null" } - tsql"select resource_id, folder_id, rank, favorited_date from ${ResourceConnection.table} where resource_id=$resourceId and $folderClause" + tsql"select resource_id, folder_id, rank, favorited_date from ${dbResourceConnection.table} where resource_id=$resourceId and $folderClause" .map(rs => { val folderId = rs.get[Option[UUID]]("folder_id") for { @@ -235,7 +247,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL case Some(id) => sqls"folder_id=$id" case None => sqls"folder_id is null" } - tsql"select resource_id, folder_id, rank, favorited_date from ${ResourceConnection.table} where $folderClause order by rank ASC" + tsql"select resource_id, folder_id, rank, favorited_date from ${dbResourceConnection.table} where $folderClause order by rank ASC" .map(rs => { val folderId = rs.get[Option[UUID]]("folder_id") for { @@ -249,11 +261,11 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getConnectionsByPath(path: String, feideId: FeideID)(implicit session: DBSession = dbUtility.readOnlySession ): Try[List[ResourceConnection]] = { - val fr = ResourceConnection.syntax("fr") - val r = Resource.syntax("r") + val fr = dbResourceConnection.syntax("fr") + val r = dbResource.syntax("r") - tsql"""select ${fr.result.*} from ${ResourceConnection.as(fr)} - left join ${Resource.as(r)} + tsql"""select ${fr.result.*} from ${dbResourceConnection.as(fr)} + left join ${dbResource.as(r)} on ${fr.resourceId} = ${r.id} where ${r.path} = $path and ${r.feideId} = $feideId order by favorited_date DESC; @@ -261,7 +273,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def deleteFolder(id: UUID)(implicit session: DBSession = dbUtility.autoSession): Try[UUID] = { - tsql"delete from ${Folder.table} where id = $id".update() match { + tsql"delete from ${dbFolder.table} where id = $id".update() match { case Failure(ex) => Failure(ex) case Success(numRows) if numRows != 1 => Failure(NotFoundException(s"Folder with id $id does not exist")) case Success(_) => @@ -271,7 +283,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def deleteResource(id: UUID)(implicit session: DBSession = dbUtility.autoSession): Try[UUID] = { - tsql"delete from ${Resource.table} where id = $id".update() match { + tsql"delete from ${dbResource.table} where id = $id".update() match { case Failure(ex) => Failure(ex) case Success(numRows) if numRows != 1 => Failure(NotFoundException(s"Resource with id $id does not exist")) case Success(_) => @@ -287,7 +299,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL case Some(id) => sqls"folder_id=$id" case None => sqls"folder_id is null" } - tsql"delete from ${ResourceConnection.table} where $folderClause and resource_id=$resourceId".update() match { + tsql"delete from ${dbResourceConnection.table} where $folderClause and resource_id=$resourceId".update() match { case Failure(ex) => Failure(ex) case Success(numRows) if numRows != 1 => Failure( @@ -302,8 +314,8 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getAllFavorites(implicit session: DBSession): Try[Map[String, Map[String, Long]]] = tsql""" select count(*) as count, document->>'resourceId' as resource_id, resource_type - from ${ResourceConnection.table} fr - inner join ${Resource.table} r on fr.resource_id = r.id + from ${dbResourceConnection.table} fr + inner join ${dbResource.table} r on fr.resource_id = r.id group by document->>'resourceId',resource_type """.foldLeft(Map.empty[String, Map[String, Long]]) { case (acc, rs) => val count = rs.long("count") @@ -320,16 +332,16 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getRecentFavorited(size: Option[Int], excludeResourceTypes: List[ResourceType])(implicit session: DBSession = dbUtility.autoSession ): Try[List[Resource]] = { - val fr = ResourceConnection.syntax("fr") - val r = Resource.syntax("r") + val fr = dbResourceConnection.syntax("fr") + val r = dbResource.syntax("r") val where = if (excludeResourceTypes.nonEmpty) { sqls"""where ${r.resourceType} not in (${excludeResourceTypes.map(_.entryName)})""" } else { sqls"" } - tsql"""select ${r.result.*}, ${fr.result.*} from ${ResourceConnection.as(fr)} - left join ${Resource.as(r)} + tsql"""select ${r.result.*}, ${fr.result.*} from ${dbResourceConnection.as(fr)} + left join ${dbResource.as(r)} on ${fr.resourceId} = ${r.id} $where order by favorited_date DESC @@ -346,25 +358,25 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def numberOfFavouritesForResource(resourceId: String, resourceType: String)(implicit session: DBSession): Try[Long] = Try { tsql""" - select count(*) as count from ${ResourceConnection.table} fr - inner join ${Resource.table} r on fr.resource_id = r.id + select count(*) as count from ${dbResourceConnection.table} fr + inner join ${dbResource.table} r on fr.resource_id = r.id where r.document->>'resourceId' = $resourceId and r.resource_type = $resourceType """.map(rs => rs.long("count")).runSingle().map(_.getOrElse(0L)).get } def numberOfUsersWithFavourites(implicit session: DBSession = dbUtility.autoSession): Try[Option[Long]] = tsql""" - select count(distinct feide_id) as count from ${Resource.table} + select count(distinct feide_id) as count from ${dbResource.table} """.map(rs => rs.long("count")).runSingle() def numberOfUsersWithoutFavourites(implicit session: DBSession = dbUtility.autoSession): Try[Option[Long]] = tsql""" - select count(distinct u.feide_id) as count from ${DBMyNDLAUser.table} u - left join ${Resource.table} r on u.feide_id = r.feide_id + select count(distinct u.feide_id) as count from ${dbMyNDLAUser.table} u + left join ${dbResource.table} r on u.feide_id = r.feide_id where r.feide_id is null """.map(rs => rs.long("count")).runSingle() def deleteAllUserFolders(feideId: FeideID)(implicit session: DBSession = dbUtility.autoSession): Try[Int] = { - tsql"delete from ${Folder.table} where feide_id = $feideId".update() match { + tsql"delete from ${dbFolder.table} where feide_id = $feideId".update() match { case Failure(ex) => Failure(ex) case Success(numRows) => logger.info(s"Deleted $numRows folders with feide_id = $feideId") @@ -373,7 +385,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def deleteAllUserResources(feideId: FeideID)(implicit session: DBSession = dbUtility.autoSession): Try[Int] = { - tsql"delete from ${Resource.table} where feide_id = $feideId".update() match { + tsql"delete from ${dbResource.table} where feide_id = $feideId".update() match { case Failure(ex) => Failure(ex) case Success(numRows) => logger.info(s"Deleted $numRows resources with feide_id = $feideId") @@ -465,17 +477,17 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL ): Try[Option[Folder]] = tsql"""-- Big recursive block which fetches the folder with `id` and also its children recursively WITH RECURSIVE childs AS ( SELECT id AS f_id, parent_id AS f_parent_id, feide_id AS f_feide_id, name as f_name, status as f_status, rank AS f_rank, created as f_created, updated as f_updated, shared as f_shared, description as f_description - FROM ${Folder.table} parent + FROM ${dbFolder.table} parent WHERE id = $id UNION ALL SELECT child.id AS f_id, child.parent_id AS f_parent_id, child.feide_id AS f_feide_id, child.name AS f_name, child.status as f_status, child.rank AS f_rank, child.created as f_created, child.updated as f_updated, child.shared as f_shared, child.description as f_description - FROM ${Folder.table} child + FROM ${dbFolder.table} child JOIN childs AS parent ON parent.f_id = child.parent_id $sqlFilterClause ) SELECT * FROM childs LEFT JOIN resource_connections fr ON fr.folder_id = f_id - LEFT JOIN ${Resource.table} r ON r.id = fr.resource_id; + LEFT JOIN ${dbResource.table} r ON r.id = fr.resource_id; """ // We prefix the `folders` columns with `f_` to separate them // from the `resource_connections` columns (both here and in sql). @@ -488,32 +500,32 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL .map(data => buildTreeStructureFromListOfChildren(id, data)) def getSharedFolderAndChildrenSubfoldersWithResources(id: UUID)(implicit session: DBSession): Try[Option[Folder]] = { - val u = DBMyNDLAUser.syntax("u") - val r = Resource.syntax("r") - val fr = ResourceConnection.syntax("fr") - val sfu = SavedSharedFolder.syntax("sfu") + val u = dbMyNDLAUser.syntax("u") + val r = dbResource.syntax("r") + val fr = dbResourceConnection.syntax("fr") + val sfu = dbSavedSharedFolder.syntax("sfu") tsql"""-- Big recursive block which fetches the folder with `id` and also its children recursively WITH RECURSIVE childs AS ( SELECT id AS f_id, parent_id AS f_parent_id, feide_id AS f_feide_id, name as f_name, status as f_status, rank AS f_rank, created as f_created, updated as f_updated, shared as f_shared, description as f_description - FROM ${Folder.table} parent + FROM ${dbFolder.table} parent WHERE id = $id UNION ALL SELECT child.id AS f_id, child.parent_id AS f_parent_id, child.feide_id AS f_feide_id, child.name AS f_name, child.status as f_status, child.rank AS f_rank, child.created as f_created, child.updated as f_updated, child.shared as f_shared, child.description as f_description - FROM ${Folder.table} child + FROM ${dbFolder.table} child JOIN childs AS parent ON parent.f_id = child.parent_id AND child.status = ${FolderStatus.SHARED.toString} ) SELECT childs.*, ${r.resultAll}, ${u.resultAll}, ${fr.resultAll}, ${sfu.resultAll} FROM childs - LEFT JOIN ${ResourceConnection.as(fr)} ON ${fr.folderId} = f_id - LEFT JOIN ${Resource.as(r)} ON ${r.id} = ${fr.resourceId} - LEFT JOIN ${DBMyNDLAUser.as(u)} on ${u.feideId} = f_feide_id - LEFT JOIN ${SavedSharedFolder.as(sfu)} on ${sfu.folderId} = f_id; + LEFT JOIN ${dbResourceConnection.as(fr)} ON ${fr.folderId} = f_id + LEFT JOIN ${dbResource.as(r)} ON ${r.id} = ${fr.resourceId} + LEFT JOIN ${dbMyNDLAUser.as(u)} on ${u.feideId} = f_feide_id + LEFT JOIN ${dbSavedSharedFolder.as(sfu)} on ${sfu.folderId} = f_id; """ .one(rs => Folder.fromResultSet(s => s"f_$s")(rs)) .toManies( rs => Resource.fromResultSetSyntaxProviderWithConnection(r, fr)(rs).sequence, - rs => Try(DBMyNDLAUser.fromResultSet(u)(rs)).toOption, + rs => Try(dbMyNDLAUser.fromResultSet(u)(rs)).toOption, rs => Try(SavedSharedFolder.fromResultSet(sfu, rs)).toOption, ) .map((folder, resources, user, savedSharedFolder) => { @@ -553,11 +565,11 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL tsql"""-- Big recursive block which fetches the folder with `id` and also its children recursively WITH RECURSIVE childs AS ( SELECT parent.* - FROM ${Folder.table} parent + FROM ${dbFolder.table} parent WHERE id = $id UNION ALL SELECT child.* - FROM ${Folder.table} child + FROM ${dbFolder.table} child JOIN childs AS parent ON parent.id = child.parent_id ) SELECT * FROM childs; @@ -569,11 +581,11 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getFoldersDepth(parentId: UUID)(implicit session: DBSession = dbUtility.readOnlySession): Try[Long] = tsql""" WITH RECURSIVE parents AS ( SELECT id AS f_id, parent_id AS f_parent_id, 0 dpth - FROM ${Folder.table} child + FROM ${dbFolder.table} child WHERE id = $parentId UNION ALL SELECT parent.id AS f_id, parent.parent_id AS f_parent_id, dpth +1 - FROM ${Folder.table} parent + FROM ${dbFolder.table} parent JOIN parents AS child ON child.f_parent_id = parent.id ) SELECT * FROM parents ORDER BY parents.dpth DESC @@ -584,11 +596,11 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL ): Try[List[UUID]] = tsql""" WITH RECURSIVE parent (id) as ( SELECT id - FROM ${Folder.table} child + FROM ${dbFolder.table} child WHERE id = $folderId UNION ALL SELECT child.id - FROM ${Folder.table} child, parent + FROM ${dbFolder.table} child, parent WHERE child.parent_id = parent.id ) SELECT * FROM parent @@ -601,10 +613,10 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getRootResources( feideId: FeideID )(implicit session: DBSession = dbUtility.readOnlySession): Try[List[Resource]] = { - val fr = ResourceConnection.syntax("fr") - val r = Resource.syntax("r") - tsql"""select ${r.result.*}, ${fr.result.*} from ${ResourceConnection.as(fr)} - left join ${Resource.as(r)} + val fr = dbResourceConnection.syntax("fr") + val r = dbResource.syntax("r") + tsql"""select ${r.result.*}, ${fr.result.*} from ${dbResourceConnection.as(fr)} + left join ${dbResource.as(r)} on ${fr.resourceId} = ${r.id} where ${r.feideId} = $feideId and ${fr.folderId} is null order by rank ASC; @@ -618,10 +630,10 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getFolderResources( folderId: UUID )(implicit session: DBSession = dbUtility.readOnlySession): Try[List[Resource]] = { - val fr = ResourceConnection.syntax("fr") - val r = Resource.syntax("r") - tsql"""select ${r.result.*}, ${fr.result.*} from ${ResourceConnection.as(fr)} - left join ${Resource.as(r)} + val fr = dbResourceConnection.syntax("fr") + val r = dbResource.syntax("r") + tsql"""select ${r.result.*}, ${fr.result.*} from ${dbResourceConnection.as(fr)} + left join ${dbResource.as(r)} on ${fr.resourceId} = ${r.id} where ${fr.folderId} = $folderId; """ @@ -632,31 +644,31 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } private def folderWhere(whereClause: SQLSyntax)(implicit session: DBSession): Try[Option[Folder]] = { - val f = Folder.syntax("f") - tsql"select ${f.result.*} from ${Folder.as(f)} where $whereClause".map(Folder.fromResultSet(f)).runSingleFlat() + val f = dbFolder.syntax("f") + tsql"select ${f.result.*} from ${dbFolder.as(f)} where $whereClause".map(Folder.fromResultSet(f)).runSingleFlat() } private def foldersWhere(whereClause: SQLSyntax)(implicit session: DBSession): Try[List[Folder]] = { - val f = Folder.syntax("f") - tsql"select ${f.result.*} from ${Folder.as(f)} where $whereClause".map(Folder.fromResultSet(f)).runListFlat() + val f = dbFolder.syntax("f") + tsql"select ${f.result.*} from ${dbFolder.as(f)} where $whereClause".map(Folder.fromResultSet(f)).runListFlat() } private def resourcesWhere(whereClause: SQLSyntax)(implicit session: DBSession): Try[List[Resource]] = { - val r = Resource.syntax("r") - tsql"select ${r.result.*} from ${Resource.as(r)} where $whereClause" + val r = dbResource.syntax("r") + tsql"select ${r.result.*} from ${dbResource.as(r)} where $whereClause" .map(Resource.fromResultSet(r, withConnection = false)) .runListFlat() } private def resourceWhere(whereClause: SQLSyntax)(implicit session: DBSession): Try[Option[Resource]] = { - val r = Resource.syntax("r") - tsql"select ${r.result.*} from ${Resource.as(r)} where $whereClause" + val r = dbResource.syntax("r") + tsql"select ${r.result.*} from ${dbResource.as(r)} where $whereClause" .map(Resource.fromResultSet(r, withConnection = false)) .runSingleFlat() } def setFolderRank(folderId: UUID, rank: Int, feideId: FeideID)(implicit session: DBSession): Try[Unit] = tsql""" - update ${Folder.table} + update ${dbFolder.table} set rank=$rank where id=$folderId and feide_id=$feideId """.update() match { @@ -669,7 +681,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def setSharedFolderRank(folderId: UUID, rank: Int, feideId: FeideID)(implicit session: DBSession): Try[Unit] = tsql""" - update ${SavedSharedFolder.table} + update ${dbSavedSharedFolder.table} set rank=$rank where folder_id=$folderId and feide_id=$feideId """.update() match { @@ -689,7 +701,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL case None => sqls"folder_id is null" } tsql""" - update ${ResourceConnection.table} + update ${dbResourceConnection.table} set rank=$rank where $folderClause and resource_id=$resourceId """.update() match { @@ -702,20 +714,20 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def getDistinctTags(feideId: String)(implicit session: DBSession = dbUtility.readOnlySession): Try[List[String]] = { - tsql"select distinct jsonb_array_elements_text(document->'tags') as tag from ${Resource.table} where feide_id = $feideId" + tsql"select distinct jsonb_array_elements_text(document->'tags') as tag from ${dbResource.table} where feide_id = $feideId" .map(rs => rs.string("tag")) .runList() } def numberOfTags()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = - tsql"select count(tag) from (select distinct jsonb_array_elements_text(document->'tags') from ${Resource.table}) as tag" + tsql"select count(tag) from (select distinct jsonb_array_elements_text(document->'tags') from ${dbResource.table}) as tag" .map(rs => rs.long("count")) .runSingle() def insertResourcesInBulk(bulk: BulkInserts)(implicit session: DBSession): Try[Unit] = { Try { val insertSql = tsql""" - insert into ${Resource.table} (id, feide_id, path, resource_type, created, document) + insert into ${dbResource.table} (id, feide_id, path, resource_type, created, document) values (?, ?, ?, ?, ? ,?) on conflict (feide_id, path, resource_type) do nothing """.underlying @@ -747,7 +759,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL and r.resource_type = ? and r.path = ? ) - insert into ${ResourceConnection.table} (folder_id, resource_id, rank, favorited_date) + insert into ${dbResourceConnection.table} (folder_id, resource_id, rank, favorited_date) select ?, id, ?, ? from rid """.underlying @@ -786,7 +798,7 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def insertFolderInBulk(bulk: BulkInserts)(implicit session: DBSession): Try[Unit] = Try { val insertSql = tsql""" - insert into ${Folder.table} (id, parent_id, feide_id, name, status, rank, created, updated, shared, description) + insert into ${dbFolder.table} (id, parent_id, feide_id, name, status, rank, created, updated, shared, description) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?) """.underlying @@ -811,18 +823,18 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } def numberOfResources()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = - tsql"select count(*) from ${Resource.table}".map(rs => rs.long("count")).runSingle() + tsql"select count(*) from ${dbResource.table}".map(rs => rs.long("count")).runSingle() def numberOfFolders()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = - tsql"select count(*) from ${Folder.table}".map(rs => rs.long("count")).runSingle() + tsql"select count(*) from ${dbFolder.table}".map(rs => rs.long("count")).runSingle() def numberOfSharedFolders()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = - tsql"select count(*) from ${Folder.table} where status = ${FolderStatus.SHARED.toString}" + tsql"select count(*) from ${dbFolder.table} where status = ${FolderStatus.SHARED.toString}" .map(rs => rs.long("count")) .runSingle() def numberOfResourcesGrouped()(implicit session: DBSession = dbUtility.readOnlySession): Try[List[(Long, String)]] = - tsql"select count(*) as antall, resource_type from ${Resource.table} group by resource_type" + tsql"select count(*) as antall, resource_type from ${dbResource.table} group by resource_type" .map(rs => (rs.long("antall"), rs.string("resource_type"))) .runList() @@ -831,11 +843,11 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL ): Try[SavedSharedFolder] = Try { val _ = withSQL { insert - .into(SavedSharedFolder) + .into(dbSavedSharedFolder) .namedValues( - SavedSharedFolder.column.folderId -> folderId, - SavedSharedFolder.column.feideId -> feideId, - SavedSharedFolder.column.rank -> rank, + dbSavedSharedFolder.column.folderId -> folderId, + dbSavedSharedFolder.column.feideId -> feideId, + dbSavedSharedFolder.column.rank -> rank, ) }.update() logger.info(s"Inserted new sharedFolder-user connection with folder id $folderId and feide id $feideId") @@ -846,9 +858,9 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def deleteFolderUserConnections( folderIds: List[UUID] )(implicit session: DBSession = dbUtility.autoSession): Try[List[UUID]] = Try { - val column = SavedSharedFolder.column.c + val column = dbSavedSharedFolder.column.c withSQL { - delete.from(SavedSharedFolder).where.in(column("folder_id"), folderIds) + delete.from(dbSavedSharedFolder).where.in(column("folder_id"), folderIds) }.update() } match { case Failure(ex) => Failure(ex) @@ -873,8 +885,8 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL } private def deleteFolderUserConnectionWhere(whereClause: SQLSyntax)(implicit session: DBSession): Try[Int] = { - val f = SavedSharedFolder.syntax("f") - tsql"DELETE FROM ${SavedSharedFolder.as(f)} WHERE $whereClause".update() match { + val f = dbSavedSharedFolder.syntax("f") + tsql"DELETE FROM ${dbSavedSharedFolder.as(f)} WHERE $whereClause".update() match { case Failure(ex) => Failure(ex) case Success(numRows) => logger.info(s"Deleted $numRows from shared folder user connections") @@ -885,12 +897,12 @@ class FolderRepository(using clock: Clock, dbUtility: DBUtility) extends StrictL def getSavedSharedFolders( feideId: FeideID )(implicit session: DBSession = dbUtility.autoSession): Try[List[Folder]] = { - val f = Folder.syntax("f") - val sfu = SavedSharedFolder.syntax("sfu") + val f = dbFolder.syntax("f") + val sfu = dbSavedSharedFolder.syntax("sfu") tsql""" SELECT ${f.result.*}, ${sfu.result.*} - FROM ${Folder.as(f)} - LEFT JOIN ${SavedSharedFolder.as(sfu)} on sfu.folder_id = f.id + FROM ${dbFolder.as(f)} + LEFT JOIN ${dbSavedSharedFolder.as(sfu)} on sfu.folder_id = f.id WHERE sfu.feide_id = $feideId """ .map(rs => { diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/RobotRepository.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/RobotRepository.scala index 0aec7d2d96..9c69057d94 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/RobotRepository.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/RobotRepository.scala @@ -13,14 +13,14 @@ import no.ndla.common.errors.NotFoundException import no.ndla.database.DBUtility import no.ndla.database.implicits.* import no.ndla.myndlaapi.uuidParameterFactory -import no.ndla.myndlaapi.model.domain.RobotDefinition +import no.ndla.myndlaapi.model.domain.{DBRobotDefinition, RobotDefinition} import no.ndla.network.model.FeideID import scalikejdbc.* import java.util.UUID import scala.util.{Failure, Success, Try} -class RobotRepository(using dbUtility: DBUtility) extends StrictLogging { +class RobotRepository(using dbUtility: DBUtility, dbRobotDefinition: DBRobotDefinition) extends StrictLogging { def getSession(readOnly: Boolean): DBSession = if (readOnly) dbUtility.readOnlySession else dbUtility.autoSession @@ -28,10 +28,10 @@ class RobotRepository(using dbUtility: DBUtility) extends StrictLogging { def withTx[T](func: DBSession => T): T = dbUtility.localTx(func) def updateRobotDefinition(robot: RobotDefinition)(implicit session: DBSession): Try[Unit] = Try { - val column = RobotDefinition.column.c + val column = dbRobotDefinition.column.c val _ = withSQL { - update(RobotDefinition) + update(dbRobotDefinition) .set( column("status") -> robot.status.entryName, column("updated") -> robot.updated, @@ -46,11 +46,11 @@ class RobotRepository(using dbUtility: DBUtility) extends StrictLogging { } def insertRobotDefinition(robot: RobotDefinition)(session: DBSession): Try[RobotDefinition] = Try { - val column = RobotDefinition.column.c + val column = dbRobotDefinition.column.c withSQL { insert - .into(RobotDefinition) + .into(dbRobotDefinition) .namedValues( column("id") -> robot.id, column("feide_id") -> robot.feideId, @@ -68,20 +68,20 @@ class RobotRepository(using dbUtility: DBUtility) extends StrictLogging { } def getRobotsWithFeideId(feideId: FeideID)(implicit session: DBSession): Try[List[RobotDefinition]] = Try { - val r = RobotDefinition.syntax("r") + val r = dbRobotDefinition.syntax("r") tsql""" select ${r.result.*} - from ${RobotDefinition.as(r)} + from ${dbRobotDefinition.as(r)} where feide_id = $feideId order by ${r.updated} desc """.map(RobotDefinition.fromResultSet(r)).runListFlat() }.flatten def getRobotWithId(robotId: UUID)(implicit session: DBSession): Try[Option[RobotDefinition]] = { - val r = RobotDefinition.syntax("r") + val r = dbRobotDefinition.syntax("r") tsql""" select ${r.result.*} - from ${RobotDefinition.as(r)} + from ${dbRobotDefinition.as(r)} where id = $robotId """.map(RobotDefinition.fromResultSet(r)).runSingleFlat() } @@ -89,7 +89,7 @@ class RobotRepository(using dbUtility: DBUtility) extends StrictLogging { def deleteRobotDefinition(robotId: UUID)(implicit session: DBSession): Try[Unit] = { val result = Try { withSQL { - delete.from(RobotDefinition).where.eq(RobotDefinition.column.c("id"), robotId) + delete.from(dbRobotDefinition).where.eq(dbRobotDefinition.column.c("id"), robotId) }.update() } diff --git a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/UserRepository.scala b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/UserRepository.scala index 78bf9e0211..242bbb0c95 100644 --- a/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/UserRepository.scala +++ b/myndla-api/src/main/scala/no/ndla/myndlaapi/repository/UserRepository.scala @@ -22,12 +22,12 @@ import scalikejdbc.* import scala.util.{Failure, Success, Try} -class UserRepository(using dbUtility: DBUtility) extends StrictLogging { +class UserRepository(using dbUtility: DBUtility, dbMyNDLAUser: DBMyNDLAUser) extends StrictLogging { def getUsersPaginated(offset: Long, limit: Long, filterTeachers: Boolean, query: Option[String])(implicit session: DBSession ): Try[(Long, List[MyNDLAUser])] = Try { - val u = DBMyNDLAUser.syntax("u") + val u = dbMyNDLAUser.syntax("u") val teacherClause = Option.when(filterTeachers)(sqls"u.document->>'userRole' = ${UserRole.EMPLOYEE.toString}") val queryClause = query.map(q => { @@ -43,18 +43,18 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { val count: Long = tsql""" select count(*) - from ${DBMyNDLAUser.as(u)} + from ${dbMyNDLAUser.as(u)} $whereClause """.map(rs => rs.long("count")).runSingle().map(_.getOrElse(0L)).get val users = tsql""" select ${u.result.*} - from ${DBMyNDLAUser.as(u)} + from ${dbMyNDLAUser.as(u)} $whereClause order by ${u.id} asc limit $limit offset $offset - """.map(DBMyNDLAUser.fromResultSet(u)).runList().get + """.map(dbMyNDLAUser.fromResultSet(u)).runList().get count -> users } @@ -72,7 +72,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { dataObject.setValue(CirceUtil.toJsonString(document)) tsql""" - update ${DBMyNDLAUser.table} + update ${dbMyNDLAUser.table} set document=$dataObject, last_seen=${NDLADate.parameterBinderFactory(lastSeen)} where feide_id=$feideId """ @@ -89,7 +89,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { dataObject.setValue(CirceUtil.toJsonString(user)) tsql""" - update ${DBMyNDLAUser.table} + update ${dbMyNDLAUser.table} set document=$dataObject where id=$userId """ @@ -110,7 +110,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { dataObject.setValue(CirceUtil.toJsonString(user)) tsql""" - update ${DBMyNDLAUser.table} + update ${dbMyNDLAUser.table} set document=$dataObject, last_seen=${NDLADate.parameterBinderFactory(user.lastSeen)} where feide_id=$feideId @@ -126,7 +126,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { def updateLastSeen(feideId: FeideID, lastSeen: NDLADate)(implicit session: DBSession): Try[NDLADate] = { tsql""" - update ${DBMyNDLAUser.table} + update ${dbMyNDLAUser.table} set last_seen=${NDLADate.parameterBinderFactory(lastSeen)} where feide_id=$feideId """ @@ -142,7 +142,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { ): Try[Option[MyNDLAUser]] = userWhere(sqls"u.document->>'username'=$username") def deleteUser(feideId: FeideID)(implicit session: DBSession = dbUtility.autoSession): Try[FeideID] = { - tsql"delete from ${DBMyNDLAUser.table} where feide_id = $feideId".update() match { + tsql"delete from ${dbMyNDLAUser.table} where feide_id = $feideId".update() match { case Failure(ex) => Failure(ex) case Success(numRows) if numRows != 1 => Failure(NotFoundException(s"User with feide_id $feideId does not exist")) case Success(_) => @@ -152,7 +152,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { } def deleteAllUsers(implicit session: DBSession): Try[Unit] = Try { - val _ = tsql"delete from ${DBMyNDLAUser.table}".execute() + val _ = tsql"delete from ${dbMyNDLAUser.table}".execute() } def resetSequences(implicit session: DBSession): Try[Unit] = Try { @@ -166,9 +166,9 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { def userWithId(userId: Long)(implicit session: DBSession): Try[Option[MyNDLAUser]] = userWhere(sqls"u.id=$userId") private def userWhere(whereClause: SQLSyntax)(implicit session: DBSession): Try[Option[MyNDLAUser]] = { - val u = DBMyNDLAUser.syntax("u") - tsql"select ${u.result.*} from ${DBMyNDLAUser.as(u)} where $whereClause" - .map(DBMyNDLAUser.fromResultSet(u)) + val u = dbMyNDLAUser.syntax("u") + tsql"select ${u.result.*} from ${dbMyNDLAUser.as(u)} where $whereClause" + .map(dbMyNDLAUser.fromResultSet(u)) .runSingle() } @@ -177,7 +177,7 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { val lastSeen = NDLADate.now() tsql""" with inserted as ( - insert into ${DBMyNDLAUser.table} + insert into ${dbMyNDLAUser.table} (feide_id, document, last_seen) values ($feideId, null, ${NDLADate.parameterBinderFactory(lastSeen)}) on conflict do nothing @@ -196,26 +196,26 @@ class UserRepository(using dbUtility: DBUtility) extends StrictLogging { } def numberOfUsers()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = - tsql"select count(*) from ${DBMyNDLAUser.table}".map(rs => rs.long("count")).runSingle() + tsql"select count(*) from ${dbMyNDLAUser.table}".map(rs => rs.long("count")).runSingle() def usersGrouped()(implicit session: DBSession = dbUtility.readOnlySession): Try[Map[UserRole, Long]] = - tsql"select count(*), (document->>'userRole') as rolle from ${DBMyNDLAUser.table} group by rolle" + tsql"select count(*), (document->>'userRole') as rolle from ${dbMyNDLAUser.table} group by rolle" .map(rs => (UserRole.withName(rs.string("rolle")), rs.long("count"))) .runList() .map(_.toMap) def numberOfFavouritedSubjects()(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = - tsql"select count(favoriteSubject) from (select jsonb_array_elements_text(document->'favoriteSubjects') from ${DBMyNDLAUser.table}) as favoriteSubject" + tsql"select count(favoriteSubject) from (select jsonb_array_elements_text(document->'favoriteSubjects') from ${dbMyNDLAUser.table}) as favoriteSubject" .map(rs => rs.long("count")) .runSingle() def numberOfUsersInArena(implicit session: DBSession = dbUtility.readOnlySession): Try[Option[Long]] = tsql""" - select count(*) as count from ${DBMyNDLAUser.table} + select count(*) as count from ${dbMyNDLAUser.table} where (document->'arenaAccepted')::boolean = true """.map(rs => rs.long("count")).runSingle() def getAllUsers(implicit session: DBSession): List[MyNDLAUser] = { - val u = DBMyNDLAUser.syntax("u") - tsql"select ${u.result.*} from ${DBMyNDLAUser.as(u)}".map(DBMyNDLAUser.fromResultSet(u)).runList().get + val u = dbMyNDLAUser.syntax("u") + tsql"select ${u.result.*} from ${dbMyNDLAUser.as(u)}".map(dbMyNDLAUser.fromResultSet(u)).runList().get } } diff --git a/myndla-api/src/test/scala/no/ndla/myndlaapi/TestEnvironment.scala b/myndla-api/src/test/scala/no/ndla/myndlaapi/TestEnvironment.scala index 9d4c6af7f9..b43aae4a43 100644 --- a/myndla-api/src/test/scala/no/ndla/myndlaapi/TestEnvironment.scala +++ b/myndla-api/src/test/scala/no/ndla/myndlaapi/TestEnvironment.scala @@ -20,6 +20,15 @@ import no.ndla.myndlaapi.controller.{ } import no.ndla.myndlaapi.integration.{InternalMyNDLAApiClient, LearningPathApiClient, SearchApiClient} import no.ndla.myndlaapi.integration.nodebb.NodeBBClient +import no.ndla.myndlaapi.model.domain.{ + DBConfigMeta, + DBFolder, + DBMyNDLAUser, + DBResource, + DBResourceConnection, + DBRobotDefinition, + DBSavedSharedFolder, +} import no.ndla.myndlaapi.repository.{ConfigRepository, FolderRepository, RobotRepository, UserRepository} import no.ndla.myndlaapi.service.{ ConfigService, @@ -45,6 +54,13 @@ import org.scalatestplus.mockito.MockitoSugar trait TestEnvironment extends TapirApplication[MyNdlaApiProperties] with MockitoSugar { implicit lazy val props: MyNdlaApiProperties = new MyNdlaApiProperties + implicit lazy val dbConfigMeta: DBConfigMeta = new DBConfigMeta + implicit lazy val dbMyNDLAUser: DBMyNDLAUser = new DBMyNDLAUser + implicit lazy val dbFolder: DBFolder = new DBFolder + implicit lazy val dbResourceConnection: DBResourceConnection = new DBResourceConnection + implicit lazy val dbResource: DBResource = new DBResource + implicit lazy val dbSavedSharedFolder: DBSavedSharedFolder = new DBSavedSharedFolder + implicit lazy val dbRobotDefinition: DBRobotDefinition = new DBRobotDefinition implicit lazy val routes: Routes = mock[Routes] implicit lazy val errorHandling: ControllerErrorHandling = mock[ControllerErrorHandling] implicit lazy val errorHelpers: ErrorHelpers = mock[ErrorHelpers] diff --git a/myndla-api/src/test/scala/no/ndla/myndlaapi/repository/FolderRepositoryTest.scala b/myndla-api/src/test/scala/no/ndla/myndlaapi/repository/FolderRepositoryTest.scala index 02ed4c79bb..d1e7528152 100644 --- a/myndla-api/src/test/scala/no/ndla/myndlaapi/repository/FolderRepositoryTest.scala +++ b/myndla-api/src/test/scala/no/ndla/myndlaapi/repository/FolderRepositoryTest.scala @@ -73,29 +73,29 @@ class FolderRepositoryTest extends DatabaseIntegrationSuite with UnitSuite with } def folderCount(implicit session: DBSession = DBUtil.autoSession): Long = { - sql"select count(id) from ${Folder.table}".map(rs => rs.long("count")).single().getOrElse(0) + sql"select count(id) from folders".map(rs => rs.long("count")).single().getOrElse(0) } def resourceCount(implicit session: DBSession = DBUtil.autoSession): Long = { - sql"select count(id) from ${Resource.table}".map(rs => rs.long("count")).single().getOrElse(0) + sql"select count(id) from resources".map(rs => rs.long("count")).single().getOrElse(0) } def folderResourcesCount(implicit session: DBSession = DBUtil.autoSession): Long = { - sql"select count(resource_id) from ${ResourceConnection.table} where folder_id is not null" + sql"select count(resource_id) from resource_connections where folder_id is not null" .map(rs => rs.long("count")) .single() .getOrElse(0) } def rootResourcesCount(implicit session: DBSession = DBUtil.autoSession): Long = { - sql"select count(resource_id) from ${ResourceConnection.table} where folder_id is null" + sql"select count(resource_id) from resource_connections where folder_id is null" .map(rs => rs.long("count")) .single() .getOrElse(0) } def getAllFolders(implicit session: DBSession = DBUtil.autoSession): List[Folder] = { - sql"select * from ${Folder.table}".map(rs => Folder.fromResultSet(rs)).list().sequence.get + sql"select * from folders".map(rs => Folder.fromResultSet(rs)).list().sequence.get } test("that inserting and retrieving a folder works as expected") {