diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt index a5f959309..3f491eee3 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfiguration.kt @@ -7,6 +7,7 @@ import org.springframework.boot.jdbc.DataSourceBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Primary +import org.sqlite.SQLiteConfig import org.sqlite.SQLiteDataSource import javax.sql.DataSource @@ -14,18 +15,39 @@ import javax.sql.DataSource class DataSourcesConfiguration( private val komgaProperties: KomgaProperties, ) { - @Bean("sqliteDataSource") + @Bean("sqliteDataSourceRW") @Primary - fun sqliteDataSource(): DataSource = buildDataSource("SqliteMainPool", SqliteUdfDataSource::class.java, komgaProperties.database) - - @Bean("tasksDataSource") - fun tasksDataSource(): DataSource = - buildDataSource("SqliteTasksPool", SQLiteDataSource::class.java, komgaProperties.tasksDb) + fun sqliteDataSourceRW(): DataSource = + buildDataSource("SqliteMainPoolRW", SqliteUdfDataSource::class.java, komgaProperties.database) .apply { - // force pool size to 1 for tasks datasource + // force pool size to 1 if the pool is only used for writes + if (komgaProperties.database.shouldSeparateReadFromWrites()) this.maximumPoolSize = 1 + } + + @Bean("sqliteDataSourceRO") + fun sqliteDataSourceRO(): DataSource = + if (komgaProperties.database.shouldSeparateReadFromWrites()) + buildDataSource("SqliteMainPoolRO", SqliteUdfDataSource::class.java, komgaProperties.database) + else + sqliteDataSourceRW() + + @Bean("tasksDataSourceRW") + fun tasksDataSourceRW(): DataSource = + buildDataSource("SqliteTasksPoolRW", SQLiteDataSource::class.java, komgaProperties.tasksDb) + .apply { + // pool size is always 1: + // - if there's only 1 pool for read and writes, size should be 1 + // - if there's a separate read pool, the write pool size should be 1 this.maximumPoolSize = 1 } + @Bean("tasksDataSourceRO") + fun tasksDataSourceRO(): DataSource = + if (komgaProperties.tasksDb.shouldSeparateReadFromWrites()) + buildDataSource("SqliteTasksPoolRO", SQLiteDataSource::class.java, komgaProperties.tasksDb) + else + tasksDataSourceRW() + private fun buildDataSource( poolName: String, dataSourceClass: Class, @@ -57,7 +79,7 @@ class DataSourcesConfiguration( } val poolSize = - if (databaseProps.file.contains(":memory:") || databaseProps.file.contains("mode=memory")) + if (databaseProps.isMemory()) 1 else if (databaseProps.poolSize != null) databaseProps.poolSize!! @@ -72,4 +94,8 @@ class DataSourcesConfiguration( }, ) } + + fun KomgaProperties.Database.isMemory() = file.contains(":memory:") || file.contains("mode=memory") + + fun KomgaProperties.Database.shouldSeparateReadFromWrites(): Boolean = !isMemory() && journalMode == SQLiteConfig.JournalMode.WAL } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt index 8e0a561f3..d432550e7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/datasource/FlywaySecondaryMigrationInitializer.kt @@ -8,7 +8,7 @@ import javax.sql.DataSource @Component class FlywaySecondaryMigrationInitializer( - @Qualifier("tasksDataSource") + @Qualifier("tasksDataSourceRW") private val tasksDataSource: DataSource, ) : InitializingBean { // by default Spring Boot will perform migration only on the @Primary datasource diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt index a657ffdba..c8b7c3b75 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/KomgaJooqConfiguration.kt @@ -19,17 +19,31 @@ import javax.sql.DataSource // as advised in https://docs.spring.io/spring-boot/docs/3.1.4/reference/htmlsingle/#howto.data-access.configure-jooq-with-multiple-datasources @Configuration class KomgaJooqConfiguration { - @Bean("dslContext") + @Bean("dslContextRW") @Primary - fun mainDslContext( + fun mainDslContextRW( dataSource: DataSource, transactionProvider: ObjectProvider, executeListenerProviders: ObjectProvider, ): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders) - @Bean("tasksDslContext") - fun tasksDslContext( - @Qualifier("tasksDataSource") dataSource: DataSource, + @Bean("dslContextRO") + fun mainDslContextRO( + @Qualifier("sqliteDataSourceRO") dataSource: DataSource, + transactionProvider: ObjectProvider, + executeListenerProviders: ObjectProvider, + ): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders) + + @Bean("tasksDslContextRW") + fun tasksDslContextRW( + @Qualifier("tasksDataSourceRW") dataSource: DataSource, + transactionProvider: ObjectProvider, + executeListenerProviders: ObjectProvider, + ): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders) + + @Bean("tasksDslContextRO") + fun tasksDslContextRO( + @Qualifier("tasksDataSourceRO") dataSource: DataSource, transactionProvider: ObjectProvider, executeListenerProviders: ObjectProvider, ): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt index 815d396fe..0a45be0e8 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/AuthenticationActivityDao.kt @@ -10,6 +10,7 @@ import org.gotson.komga.language.toCurrentTimeZone import org.jooq.Condition import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest @@ -20,7 +21,8 @@ import java.time.LocalDateTime @Component class AuthenticationActivityDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : AuthenticationActivityRepository { private val aa = Tables.AUTHENTICATION_ACTIVITY @@ -52,7 +54,7 @@ class AuthenticationActivityDao( user: KomgaUser, apiKeyId: String?, ): AuthenticationActivity? = - dsl + dslRO .selectFrom(aa) .where(aa.USER_ID.eq(user.id)) .or(aa.EMAIL.eq(user.email)) @@ -66,12 +68,12 @@ class AuthenticationActivityDao( conditions: Condition, pageable: Pageable, ): PageImpl { - val count = dsl.fetchCount(aa, conditions) + val count = dslRO.fetchCount(aa, conditions) val orderBy = pageable.sort.toOrderBy(sorts) val items = - dsl + dslRO .selectFrom(aa) .where(conditions) .orderBy(orderBy) @@ -91,14 +93,14 @@ class AuthenticationActivityDao( } override fun insert(activity: AuthenticationActivity) { - dsl + dslRW .insertInto(aa, aa.USER_ID, aa.EMAIL, aa.API_KEY_ID, aa.API_KEY_COMMENT, aa.IP, aa.USER_AGENT, aa.SUCCESS, aa.ERROR, aa.SOURCE) .values(activity.userId, activity.email, activity.apiKeyId, activity.apiKeyComment, activity.ip, activity.userAgent, activity.success, activity.error, activity.source) .execute() } override fun deleteByUser(user: KomgaUser) { - dsl + dslRW .deleteFrom(aa) .where(aa.USER_ID.eq(user.id)) .or(aa.EMAIL.eq(user.email)) @@ -106,7 +108,7 @@ class AuthenticationActivityDao( } override fun deleteOlderThan(dateTime: LocalDateTime) { - dsl + dslRW .deleteFrom(aa) .where(aa.DATE_TIME.lt(dateTime)) .execute() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt index aca90dd2e..1f0ab1120 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookCommonDao.kt @@ -13,12 +13,13 @@ import org.jooq.impl.DSL import org.jooq.impl.DSL.falseCondition import org.jooq.impl.DSL.name import org.jooq.impl.DSL.select +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import java.time.LocalDateTime @Component class BookCommonDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) { private val b = Tables.BOOK private val m = Tables.MEDIA @@ -77,7 +78,7 @@ class BookCommonDao( val b1 = cteBooks.`as`("b1") val b2 = cteBooks.`as`("b2") val query = - dsl + dslRO .with(cteSeries) .with(cteBooks) .select(*selectFields) @@ -119,7 +120,7 @@ class BookCommonDao( .where(b2.field(cteBooksFieldBookId)!!.isNull) val mostRecentReadDateQuery = - dsl + dslRO .with(cteSeries) .select(DSL.max(cteSeries.field(rs.MOST_RECENT_READ_DATE))) .from(cteSeries) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt index a4901daea..26aaa00eb 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDao.kt @@ -12,15 +12,15 @@ import org.gotson.komga.infrastructure.jooq.toOrderBy import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.BookRecord import org.gotson.komga.language.toCurrentTimeZone -import org.jooq.Condition import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable -import org.springframework.data.domain.Sort +import org.springframework.data.domain.Sort.unsorted import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional import java.math.BigDecimal @@ -30,7 +30,8 @@ import java.time.ZoneId @Component class BookDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : BookRepository { private val b = Tables.BOOK @@ -46,13 +47,18 @@ class BookDao( "number" to b.NUMBER, ) - override fun findByIdOrNull(bookId: String): Book? = findByIdOrNull(dsl, bookId) + override fun findByIdOrNull(bookId: String): Book? = + dslRO + .selectFrom(b) + .where(b.ID.eq(bookId)) + .fetchOneInto(b) + ?.toDomain() override fun findNotDeletedByLibraryIdAndUrlOrNull( libraryId: String, url: URL, ): Book? = - dsl + dslRO .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId).and(b.URL.eq(url.toString()))) .and(b.DELETED_DATE.isNull) @@ -61,18 +67,8 @@ class BookDao( .firstOrNull() ?.toDomain() - private fun findByIdOrNull( - dsl: DSLContext, - bookId: String, - ): Book? = - dsl - .selectFrom(b) - .where(b.ID.eq(bookId)) - .fetchOneInto(b) - ?.toDomain() - override fun findAllBySeriesId(seriesId: String): Collection = - dsl + dslRO .selectFrom(b) .where(b.SERIES_ID.eq(seriesId)) .fetchInto(b) @@ -80,8 +76,8 @@ class BookDao( @Transactional override fun findAllBySeriesIds(seriesIds: Collection): Collection { - dsl.withTempTable(batchSize, seriesIds).use { tempTable -> - return dsl + dslRO.withTempTable(batchSize, seriesIds).use { tempTable -> + return dslRO .selectFrom(b) .where(b.SERIES_ID.`in`(tempTable.selectTempStrings())) .fetchInto(b) @@ -94,9 +90,9 @@ class BookDao( libraryId: String, urls: Collection, ): Collection { - dsl.withTempTable(batchSize, urls.map { it.toString() }).use { tempTable -> + dslRO.withTempTable(batchSize, urls.map { it.toString() }).use { tempTable -> - return dsl + return dslRO .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId)) .and(b.DELETED_DATE.isNull) @@ -107,14 +103,14 @@ class BookDao( } override fun findAllDeletedByFileSize(fileSize: Long): Collection = - dsl + dslRO .selectFrom(b) .where(b.DELETED_DATE.isNotNull.and(b.FILE_SIZE.eq(fileSize))) .fetchInto(b) .map { it.toDomain() } override fun findAll(): Collection = - dsl + dslRO .selectFrom(b) .fetchInto(b) .map { it.toDomain() } @@ -125,20 +121,13 @@ class BookDao( pageable: Pageable, ): Page { val bookCondition = BookSearchHelper(searchContext).toCondition(searchCondition) - return findAll(bookCondition.first, bookCondition.second, pageable) - } - private fun findAll( - conditions: Condition, - joins: Set, - pageable: Pageable, - ): PageImpl { val count = - dsl + dslRO .selectCount() .from(b) .apply { - joins.forEach { join -> + bookCondition.second.forEach { join -> when (join) { RequiredJoin.BookMetadata -> innerJoin(d).on(b.ID.eq(d.BOOK_ID)) RequiredJoin.SeriesMetadata -> innerJoin(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) @@ -153,17 +142,17 @@ class BookDao( is RequiredJoin.Collection -> Unit } } - }.where(conditions) + }.where(bookCondition.first) .fetchOne(0, Long::class.java) ?: 0 val orderBy = pageable.sort.toOrderBy(sorts) val items = - dsl + dslRO .select(*b.fields()) .from(b) .apply { - joins.forEach { join -> + bookCondition.second.forEach { join -> when (join) { RequiredJoin.BookMetadata -> innerJoin(d).on(b.ID.eq(d.BOOK_ID)) RequiredJoin.SeriesMetadata -> innerJoin(sd).on(b.SERIES_ID.eq(sd.SERIES_ID)) @@ -178,13 +167,13 @@ class BookDao( is RequiredJoin.Collection -> Unit } } - }.where(conditions) + }.where(bookCondition.first) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } .fetchInto(b) .map { it.toDomain() } + val pageSort = if (orderBy.isNotEmpty()) pageable.sort else unsorted() - val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted() return PageImpl( items, if (pageable.isPaged) @@ -196,21 +185,21 @@ class BookDao( } override fun getLibraryIdOrNull(bookId: String): String? = - dsl + dslRO .select(b.LIBRARY_ID) .from(b) .where(b.ID.eq(bookId)) .fetchOne(b.LIBRARY_ID) override fun getSeriesIdOrNull(bookId: String): String? = - dsl + dslRO .select(b.SERIES_ID) .from(b) .where(b.ID.eq(bookId)) .fetchOne(b.SERIES_ID) override fun findFirstIdInSeriesOrNull(seriesId: String): String? = - dsl + dslRO .select(b.ID) .from(b) .leftJoin(d) @@ -221,7 +210,7 @@ class BookDao( .fetchOne(b.ID) override fun findLastIdInSeriesOrNull(seriesId: String): String? = - dsl + dslRO .select(b.ID) .from(b) .leftJoin(d) @@ -235,7 +224,7 @@ class BookDao( seriesId: String, userId: String, ): String? = - dsl + dslRO .select(b.ID) .from(b) .leftJoin(d) @@ -250,26 +239,26 @@ class BookDao( .fetchOne(b.ID) override fun findAllIdsBySeriesId(seriesId: String): Collection = - dsl + dslRO .select(b.ID) .from(b) .where(b.SERIES_ID.eq(seriesId)) .fetch(b.ID) override fun findAllIdsByLibraryId(libraryId: String): Collection = - dsl + dslRO .select(b.ID) .from(b) .where(b.LIBRARY_ID.eq(libraryId)) .fetch(b.ID) - override fun existsById(bookId: String): Boolean = dsl.fetchExists(b, b.ID.eq(bookId)) + override fun existsById(bookId: String): Boolean = dslRO.fetchExists(b, b.ID.eq(bookId)) override fun findAllByLibraryIdAndMediaTypes( libraryId: String, mediaTypes: Collection, ): Collection = - dsl + dslRO .select(*b.fields()) .from(b) .leftJoin(m) @@ -284,7 +273,7 @@ class BookDao( mediaType: String, extension: String, ): Collection = - dsl + dslRO .select(*b.fields()) .from(b) .leftJoin(m) @@ -296,7 +285,7 @@ class BookDao( .map { it.toDomain() } override fun findAllByLibraryIdAndWithEmptyHash(libraryId: String): Collection = - dsl + dslRO .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId)) .and(b.FILE_HASH.eq("")) @@ -304,7 +293,7 @@ class BookDao( .map { it.toDomain() } override fun findAllByLibraryIdAndWithEmptyHashKoreader(libraryId: String): Collection = - dsl + dslRO .selectFrom(b) .where(b.LIBRARY_ID.eq(libraryId)) .and(b.FILE_HASH_KOREADER.eq("")) @@ -312,7 +301,7 @@ class BookDao( .map { it.toDomain() } override fun findAllByHashKoreader(hashKoreader: String): Collection = - dsl + dslRO .selectFrom(b) .where(b.FILE_HASH_KOREADER.eq(hashKoreader)) .fetchInto(b) @@ -327,9 +316,9 @@ class BookDao( override fun insert(books: Collection) { if (books.isNotEmpty()) { books.chunked(batchSize).forEach { chunk -> - dsl + dslRW .batch( - dsl + dslRW .insertInto( b, b.ID, @@ -378,7 +367,7 @@ class BookDao( } private fun updateBook(book: Book) { - dsl + dslRW .update(b) .set(b.NAME, book.name) .set(b.URL, book.url.toString()) @@ -397,31 +386,31 @@ class BookDao( } override fun delete(bookId: String) { - dsl.deleteFrom(b).where(b.ID.eq(bookId)).execute() + dslRW.deleteFrom(b).where(b.ID.eq(bookId)).execute() } @Transactional override fun delete(bookIds: Collection) { - dsl.withTempTable(batchSize, bookIds).use { tempTable -> - dsl.deleteFrom(b).where(b.ID.`in`(tempTable.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, bookIds).use { tempTable -> + dslRW.deleteFrom(b).where(b.ID.`in`(tempTable.selectTempStrings())).execute() } } override fun deleteAll() { - dsl.deleteFrom(b).execute() + dslRW.deleteFrom(b).execute() } - override fun count(): Long = dsl.fetchCount(b).toLong() + override fun count(): Long = dslRO.fetchCount(b).toLong() override fun countGroupedByLibraryId(): Map = - dsl + dslRO .select(b.LIBRARY_ID, DSL.count(b.ID)) .from(b) .groupBy(b.LIBRARY_ID) .fetchMap(b.LIBRARY_ID, DSL.count(b.ID)) override fun getFilesizeGroupedByLibraryId(): Map = - dsl + dslRO .select(b.LIBRARY_ID, DSL.sum(b.FILE_SIZE)) .from(b) .groupBy(b.LIBRARY_ID) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt index 6b7c29be9..ab2d3e159 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookDtoDao.kt @@ -39,6 +39,7 @@ import org.jooq.SelectOnConditionStep import org.jooq.impl.DSL import org.jooq.impl.DSL.falseCondition import org.jooq.impl.DSL.noCondition +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl @@ -50,7 +51,7 @@ import java.net.URL @Component class BookDtoDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, private val luceneHelper: LuceneHelper, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, private val bookCommonDao: BookCommonDao, @@ -134,7 +135,7 @@ class BookDtoDao( } // don't use the DSLContext.withTempTable form to control optional creation - TempTable(dsl).use { tempTable -> + TempTable(dslRO).use { tempTable -> val searchCondition = when { @@ -148,8 +149,8 @@ class BookDtoDao( } val count = - dsl.fetchCount( - dsl + dslRO.fetchCount( + dslRO .select(b.ID) .from(b) .leftJoin(m) @@ -184,12 +185,13 @@ class BookDtoDao( ) val dtos = - selectBase(userId, joins) + dslRO + .selectBase(userId, joins) .where(conditions) .and(searchCondition) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } - .fetchAndMap() + .fetchAndMap(dslRO) val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted() return PageImpl( @@ -207,9 +209,10 @@ class BookDtoDao( bookId: String, userId: String, ): BookDto? = - selectBase(userId) + dslRO + .selectBase(userId) .where(b.ID.eq(bookId)) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() override fun findPreviousInSeriesOrNull( @@ -246,12 +249,12 @@ class BookDtoDao( ): Page { val (query, sortField, _) = bookCommonDao.getBooksOnDeckQuery(userId, restrictions, filterOnLibraryIds, onDeckFields) - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) val dtos = query .orderBy(sortField.desc()) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } - .fetchAndMap() + .fetchAndMap(dslRO) return PageImpl( dtos, @@ -268,7 +271,7 @@ class BookDtoDao( pageable: Pageable, ): Page { val hashes = - dsl + dslRO .select(b.FILE_HASH, DSL.count(b.ID)) .from(b) .where(b.FILE_HASH.ne("")) @@ -281,11 +284,12 @@ class BookDtoDao( val orderBy = pageable.sort.toOrderBy(sorts) val dtos = - selectBase(userId) + dslRO + .selectBase(userId) .where(b.FILE_HASH.`in`(hashes.keys)) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } - .fetchAndMap() + .fetchAndMap(dslRO) val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted() return PageImpl( @@ -306,7 +310,7 @@ class BookDtoDao( next: Boolean, ): BookDto? { val record = - dsl + dslRO .select(b.SERIES_ID, d.NUMBER_SORT) .from(b) .leftJoin(d) @@ -316,12 +320,13 @@ class BookDtoDao( val seriesId = record.get(0, String::class.java) val numberSort = record.get(1, Float::class.java) - return selectBase(userId) + return dslRO + .selectBase(userId) .where(b.SERIES_ID.eq(seriesId)) .orderBy(d.NUMBER_SORT.let { if (next) it.asc() else it.desc() }) .seek(numberSort) .limit(1) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() } @@ -335,7 +340,7 @@ class BookDtoDao( ): BookDto? { if (readList.ordered) { val numberSort = - dsl + dslRO .select(rlb.NUMBER) .from(b) .leftJoin(rlb) @@ -345,19 +350,20 @@ class BookDtoDao( .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .fetchOne(rlb.NUMBER) - return selectBase(userId, setOf(RequiredJoin.ReadList(readList.id))) + return dslRO + .selectBase(userId, setOf(RequiredJoin.ReadList(readList.id))) .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .orderBy(rlbAlias(readList.id).NUMBER.let { if (next) it.asc() else it.desc() }) .seek(numberSort) .limit(1) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() } else { // it is too complex to perform a seek by release date as it could be null and could also have multiple occurrences of the same value // instead we pull the whole list of ids, and perform the seek on the list val bookIds = - dsl + dslRO .select(b.ID) .from(b) .leftJoin(rlb) @@ -375,16 +381,17 @@ class BookDtoDao( if (bookIndex == -1) return null val siblingId = bookIds.getOrNull(bookIndex + if (next) 1 else -1) ?: return null - return selectBase(userId) + return dslRO + .selectBase(userId) .where(b.ID.eq(siblingId)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .limit(1) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() } } - private fun selectBase( + private fun DSLContext.selectBase( userId: String, joins: Set = emptySet(), ): SelectOnConditionStep { @@ -397,7 +404,7 @@ class BookDtoDao( sd.TITLE, ) - return dsl + return this .select(selectFields) .from(b) .leftJoin(m) @@ -429,7 +436,7 @@ class BookDtoDao( } } - private fun ResultQuery.fetchAndMap(): MutableList { + private fun ResultQuery.fetchAndMap(dsl: DSLContext): MutableList { val records = fetch() val bookIds = records.getValues(b.ID) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt index 919649c1b..353a8194f 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataAggregationDao.kt @@ -9,6 +9,7 @@ import org.gotson.komga.jooq.main.tables.records.BookMetadataAggregationAuthorRe import org.gotson.komga.jooq.main.tables.records.BookMetadataAggregationRecord import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -17,19 +18,20 @@ import java.time.ZoneId @Component class BookMetadataAggregationDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : BookMetadataAggregationRepository { private val d = Tables.BOOK_METADATA_AGGREGATION private val a = Tables.BOOK_METADATA_AGGREGATION_AUTHOR private val t = Tables.BOOK_METADATA_AGGREGATION_TAG - override fun findById(seriesId: String): BookMetadataAggregation = findOne(listOf(seriesId)).first() + override fun findById(seriesId: String): BookMetadataAggregation = dslRO.findOne(listOf(seriesId)).first() - override fun findByIdOrNull(seriesId: String): BookMetadataAggregation? = findOne(listOf(seriesId)).firstOrNull() + override fun findByIdOrNull(seriesId: String): BookMetadataAggregation? = dslRO.findOne(listOf(seriesId)).firstOrNull() - private fun findOne(seriesIds: Collection) = - dsl + private fun DSLContext.findOne(seriesIds: Collection) = + this .select(*d.fields(), *a.fields()) .from(d) .leftJoin(a) @@ -39,11 +41,11 @@ class BookMetadataAggregationDao( { it.into(d) }, { it.into(a) }, ).map { (dr, ar) -> - dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }, findTags(dr.seriesId)) + dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }, this.findTags(dr.seriesId)) } - private fun findTags(seriesId: String) = - dsl + private fun DSLContext.findTags(seriesId: String) = + this .select(t.TAG) .from(t) .where(t.SERIES_ID.eq(seriesId)) @@ -51,7 +53,7 @@ class BookMetadataAggregationDao( @Transactional override fun insert(metadata: BookMetadataAggregation) { - dsl + dslRW .insertInto(d) .set(d.SERIES_ID, metadata.seriesId) .set(d.RELEASE_DATE, metadata.releaseDate) @@ -59,13 +61,13 @@ class BookMetadataAggregationDao( .set(d.SUMMARY_NUMBER, metadata.summaryNumber) .execute() - insertAuthors(metadata) - insertTags(metadata) + dslRW.insertAuthors(metadata) + dslRW.insertTags(metadata) } @Transactional override fun update(metadata: BookMetadataAggregation) { - dsl + dslRW .update(d) .set(d.SUMMARY, metadata.summary) .set(d.SUMMARY_NUMBER, metadata.summaryNumber) @@ -74,26 +76,26 @@ class BookMetadataAggregationDao( .where(d.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(a) .where(a.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(t) .where(t.SERIES_ID.eq(metadata.seriesId)) .execute() - insertAuthors(metadata) - insertTags(metadata) + dslRW.insertAuthors(metadata) + dslRW.insertTags(metadata) } - private fun insertAuthors(metadata: BookMetadataAggregation) { + private fun DSLContext.insertAuthors(metadata: BookMetadataAggregation) { if (metadata.authors.isNotEmpty()) { metadata.authors.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(a, a.SERIES_ID, a.NAME, a.ROLE) .values(null as String?, null, null), ).also { step -> @@ -105,12 +107,12 @@ class BookMetadataAggregationDao( } } - private fun insertTags(metadata: BookMetadataAggregation) { + private fun DSLContext.insertTags(metadata: BookMetadataAggregation) { if (metadata.tags.isNotEmpty()) { metadata.tags.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(t, t.SERIES_ID, t.TAG) .values(null as String?, null), ).also { step -> @@ -124,21 +126,21 @@ class BookMetadataAggregationDao( @Transactional override fun delete(seriesId: String) { - dsl.deleteFrom(a).where(a.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(t).where(t.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(d).where(d.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(a).where(a.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(t).where(t.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(d).where(d.SERIES_ID.eq(seriesId)).execute() } @Transactional override fun delete(seriesIds: Collection) { - dsl.withTempTable(batchSize, seriesIds).use { - dsl.deleteFrom(a).where(a.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(t).where(t.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(d).where(d.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, seriesIds).use { + dslRW.deleteFrom(a).where(a.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(t).where(t.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(d).where(d.SERIES_ID.`in`(it.selectTempStrings())).execute() } } - override fun count(): Long = dsl.fetchCount(d).toLong() + override fun count(): Long = dslRO.fetchCount(d).toLong() private fun BookMetadataAggregationRecord.toDomain( authors: List, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt index 0aacad065..94de6f249 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/BookMetadataDao.kt @@ -10,6 +10,7 @@ import org.gotson.komga.jooq.main.tables.records.BookMetadataAuthorRecord import org.gotson.komga.jooq.main.tables.records.BookMetadataRecord import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -19,7 +20,8 @@ import java.time.ZoneId @Component class BookMetadataDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : BookMetadataRepository { private val d = Tables.BOOK_METADATA @@ -29,16 +31,15 @@ class BookMetadataDao( private val groupFields = arrayOf(*d.fields(), *a.fields()) - override fun findById(bookId: String): BookMetadata = find(dsl, listOf(bookId)).first() + override fun findById(bookId: String): BookMetadata = dslRO.find(listOf(bookId)).first() - override fun findByIdOrNull(bookId: String): BookMetadata? = find(dsl, listOf(bookId)).firstOrNull() + override fun findByIdOrNull(bookId: String): BookMetadata? = dslRO.find(listOf(bookId)).firstOrNull() - override fun findAllByIds(bookIds: Collection): Collection = find(dsl, bookIds) + override fun findAllByIds(bookIds: Collection): Collection = dslRO.find(bookIds) - private fun find( - dsl: DSLContext, + private fun DSLContext.find( bookIds: Collection, - ) = dsl + ) = this .select(*groupFields) .from(d) .leftJoin(a) @@ -49,18 +50,18 @@ class BookMetadataDao( { it.into(d) }, { it.into(a) }, ).map { (dr, ar) -> - dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }, findTags(dr.bookId), findLinks(dr.bookId)) + dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }, this.findTags(dr.bookId), this.findLinks(dr.bookId)) } - private fun findTags(bookId: String) = - dsl + private fun DSLContext.findTags(bookId: String) = + this .select(bt.TAG) .from(bt) .where(bt.BOOK_ID.eq(bookId)) .fetchSet(bt.TAG) - private fun findLinks(bookId: String) = - dsl + private fun DSLContext.findLinks(bookId: String) = + this .select(bl.LABEL, bl.URL) .from(bl) .where(bl.BOOK_ID.eq(bookId)) @@ -76,9 +77,9 @@ class BookMetadataDao( override fun insert(metadatas: Collection) { if (metadatas.isNotEmpty()) { metadatas.chunked(batchSize).forEach { chunk -> - dsl + dslRW .batch( - dsl + dslRW .insertInto( d, d.BOOK_ID, @@ -122,9 +123,9 @@ class BookMetadataDao( }.execute() } - insertAuthors(metadatas) - insertTags(metadatas) - insertLinks(metadatas) + dslRW.insertAuthors(metadatas) + dslRW.insertTags(metadatas) + dslRW.insertLinks(metadatas) } } @@ -139,7 +140,7 @@ class BookMetadataDao( } private fun updateMetadata(metadata: BookMetadata) { - dsl + dslRW .update(d) .set(d.TITLE, metadata.title) .set(d.TITLE_LOCK, metadata.titleLock) @@ -160,30 +161,30 @@ class BookMetadataDao( .where(d.BOOK_ID.eq(metadata.bookId)) .execute() - dsl + dslRW .deleteFrom(a) .where(a.BOOK_ID.eq(metadata.bookId)) .execute() - dsl + dslRW .deleteFrom(bt) .where(bt.BOOK_ID.eq(metadata.bookId)) .execute() - dsl + dslRW .deleteFrom(bl) .where(bl.BOOK_ID.eq(metadata.bookId)) .execute() - insertAuthors(listOf(metadata)) - insertTags(listOf(metadata)) - insertLinks(listOf(metadata)) + dslRW.insertAuthors(listOf(metadata)) + dslRW.insertTags(listOf(metadata)) + dslRW.insertLinks(listOf(metadata)) } - private fun insertAuthors(metadatas: Collection) { + private fun DSLContext.insertAuthors(metadatas: Collection) { if (metadatas.any { it.authors.isNotEmpty() }) { metadatas.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(a, a.BOOK_ID, a.NAME, a.ROLE) .values(null as String?, null, null), ).also { step -> @@ -197,12 +198,12 @@ class BookMetadataDao( } } - private fun insertTags(metadatas: Collection) { + private fun DSLContext.insertTags(metadatas: Collection) { if (metadatas.any { it.tags.isNotEmpty() }) { metadatas.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(bt, bt.BOOK_ID, bt.TAG) .values(null as String?, null), ).also { step -> @@ -216,12 +217,12 @@ class BookMetadataDao( } } - private fun insertLinks(metadatas: Collection) { + private fun DSLContext.insertLinks(metadatas: Collection) { if (metadatas.any { it.links.isNotEmpty() }) { metadatas.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(bl, bl.BOOK_ID, bl.LABEL, bl.URL) .values(null as String?, null, null), ).also { step -> @@ -237,23 +238,23 @@ class BookMetadataDao( @Transactional override fun delete(bookId: String) { - dsl.deleteFrom(a).where(a.BOOK_ID.eq(bookId)).execute() - dsl.deleteFrom(bt).where(bt.BOOK_ID.eq(bookId)).execute() - dsl.deleteFrom(bl).where(bl.BOOK_ID.eq(bookId)).execute() - dsl.deleteFrom(d).where(d.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(a).where(a.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(bt).where(bt.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(bl).where(bl.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(d).where(d.BOOK_ID.eq(bookId)).execute() } @Transactional override fun delete(bookIds: Collection) { - dsl.withTempTable(batchSize, bookIds).use { - dsl.deleteFrom(a).where(a.BOOK_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(bt).where(bt.BOOK_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(bl).where(bl.BOOK_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(d).where(d.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, bookIds).use { + dslRW.deleteFrom(a).where(a.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(bt).where(bt.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(bl).where(bl.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(d).where(d.BOOK_ID.`in`(it.selectTempStrings())).execute() } } - override fun count(): Long = dsl.fetchCount(d).toLong() + override fun count(): Long = dslRO.fetchCount(d).toLong() private fun BookMetadataRecord.toDomain( authors: List, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ClientSettingsDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ClientSettingsDtoDao.kt index d74c162b0..4ff030c8a 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ClientSettingsDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ClientSettingsDtoDao.kt @@ -3,24 +3,26 @@ package org.gotson.komga.infrastructure.jooq.main import org.gotson.komga.interfaces.api.rest.dto.ClientSettingDto import org.gotson.komga.jooq.main.Tables import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component @Component class ClientSettingsDtoDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) { private val g = Tables.CLIENT_SETTINGS_GLOBAL private val u = Tables.CLIENT_SETTINGS_USER fun findAllGlobal(onlyUnauthorized: Boolean = false): Map = - dsl + dslRO .selectFrom(g) .apply { if (onlyUnauthorized) where(g.ALLOW_UNAUTHORIZED.isTrue) } .fetch() .associate { it.key to ClientSettingDto(it.value, it.allowUnauthorized) } fun findAllUser(userId: String): Map = - dsl + dslRO .selectFrom(u) .where(u.USER_ID.eq(userId)) .fetch() @@ -31,7 +33,7 @@ class ClientSettingsDtoDao( value: String, allowUnauthorized: Boolean, ) { - dsl + dslRW .insertInto(g, g.KEY, g.VALUE, g.ALLOW_UNAUTHORIZED) .values(key, value, allowUnauthorized) .onDuplicateKeyUpdate() @@ -44,7 +46,7 @@ class ClientSettingsDtoDao( key: String, value: String, ) { - dsl + dslRW .insertInto(u, u.USER_ID, u.KEY, u.VALUE) .values(userId, key, value) .onDuplicateKeyUpdate() @@ -53,12 +55,12 @@ class ClientSettingsDtoDao( } fun deleteAll() { - dsl.deleteFrom(g).execute() - dsl.deleteFrom(u).execute() + dslRW.deleteFrom(g).execute() + dslRW.deleteFrom(u).execute() } fun deleteGlobalByKeys(keys: Collection) { - dsl + dslRW .deleteFrom(g) .where(g.KEY.`in`(keys)) .execute() @@ -68,7 +70,7 @@ class ClientSettingsDtoDao( userId: String, keys: Collection, ) { - dsl + dslRW .deleteFrom(u) .where(u.KEY.`in`(keys)) .and(u.USER_ID.eq(userId)) @@ -76,7 +78,7 @@ class ClientSettingsDtoDao( } fun deleteByUserId(userId: String) { - dsl + dslRW .deleteFrom(u) .where(u.USER_ID.eq(userId)) .execute() diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt index c8b4d82e8..9e4f9d829 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDao.kt @@ -9,14 +9,14 @@ import org.springframework.transaction.annotation.Transactional @Component class HistoricalEventDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, ) : HistoricalEventRepository { private val e = Tables.HISTORICAL_EVENT private val ep = Tables.HISTORICAL_EVENT_PROPERTIES @Transactional override fun insert(event: HistoricalEvent) { - dsl + dslRW .insertInto(e) .set(e.ID, event.id) .set(e.TYPE, event.type) @@ -26,9 +26,9 @@ class HistoricalEventDao( .execute() if (event.properties.isNotEmpty()) { - dsl + dslRW .batch( - dsl + dslRW .insertInto(ep, ep.ID, ep.KEY, ep.VALUE) .values(null as String?, null, null), ).also { step -> diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt index e2c468f37..b70a3d89c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/HistoricalEventDtoDao.kt @@ -5,6 +5,7 @@ import org.gotson.komga.interfaces.api.persistence.HistoricalEventDtoRepository import org.gotson.komga.interfaces.api.rest.dto.HistoricalEventDto import org.gotson.komga.jooq.main.Tables import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest @@ -14,7 +15,7 @@ import org.springframework.stereotype.Component @Component class HistoricalEventDtoDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : HistoricalEventDtoRepository { private val e = Tables.HISTORICAL_EVENT private val ep = Tables.HISTORICAL_EVENT_PROPERTIES @@ -28,17 +29,17 @@ class HistoricalEventDtoDao( ) override fun findAll(pageable: Pageable): Page { - val count = dsl.fetchCount(e) + val count = dslRO.fetchCount(e) val orderBy = pageable.sort.toOrderBy(sorts) val items = - dsl + dslRO .selectFrom(e) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } .map { er -> - val epr = dsl.selectFrom(ep).where(ep.ID.eq(er.id)).fetch() + val epr = dslRO.selectFrom(ep).where(ep.ID.eq(er.id)).fetch() HistoricalEventDto( type = er.type, timestamp = er.timestamp, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt index 00299da9d..9d6e2f944 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KoboDtoDao.kt @@ -10,12 +10,13 @@ import org.gotson.komga.interfaces.api.kobo.dto.PublisherDto import org.gotson.komga.interfaces.api.kobo.persistence.KoboDtoRepository import org.gotson.komga.jooq.main.Tables import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import java.time.ZoneId @Component class KoboDtoDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, private val mapper: ObjectMapper, ) : KoboDtoRepository { private val b = Tables.BOOK @@ -29,7 +30,7 @@ class KoboDtoDao( bookIds: Collection, ): Collection { val records = - dsl + dslRO .select( d.BOOK_ID, d.TITLE, @@ -71,7 +72,7 @@ class KoboDtoDao( val mediaExtension = mapper.deserializeMediaExtension(mr.extensionClass, mr.extensionValueBlob) as? MediaExtensionEpub val authors = - dsl + dslRO .selectFrom(a) .where(a.BOOK_ID.`in`(bookIds)) .filter { it.name != null } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt index bb7995c35..49dc7810d 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/KomgaUserDao.kt @@ -13,6 +13,7 @@ import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext import org.jooq.Record import org.jooq.ResultQuery +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional import java.time.LocalDateTime @@ -20,7 +21,8 @@ import java.time.ZoneId @Component class KomgaUserDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : KomgaUserRepository { private val u = Tables.USER private val ur = Tables.USER_ROLE @@ -29,14 +31,15 @@ class KomgaUserDao( private val ar = Tables.ANNOUNCEMENTS_READ private val uak = Tables.USER_API_KEY - override fun count(): Long = dsl.fetchCount(u).toLong() + override fun count(): Long = dslRO.fetchCount(u).toLong() override fun findAll(): Collection = - selectBase() - .fetchAndMap() + dslRO + .selectBase() + .fetchAndMap(dslRO) override fun findApiKeyByUserId(userId: String): Collection = - dsl + dslRO .selectFrom(uak) .where(uak.USER_ID.eq(userId)) .fetchInto(uak) @@ -45,20 +48,20 @@ class KomgaUserDao( } override fun findByIdOrNull(id: String): KomgaUser? = - selectBase() + dslRO + .selectBase() .where(u.ID.equal(id)) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() - private fun selectBase() = - dsl - .select(*u.fields()) + private fun DSLContext.selectBase() = + select(*u.fields()) .select(ul.LIBRARY_ID) .from(u) .leftJoin(ul) .onKey() - private fun ResultQuery.fetchAndMap() = + private fun ResultQuery.fetchAndMap(dsl: DSLContext) = this .fetchGroups({ it.into(u) }, { it.into(ul) }) .map { (userRecord, ulr) -> @@ -97,7 +100,7 @@ class KomgaUserDao( @Transactional override fun insert(user: KomgaUser) { - dsl + dslRW .insertInto(u) .set(u.ID, user.id) .set(u.EMAIL, user.email) @@ -113,13 +116,13 @@ class KomgaUserDao( }, ).execute() - insertRoles(user) - insertSharedLibraries(user) - insertSharingRestrictions(user) + dslRW.insertRoles(user) + dslRW.insertSharedLibraries(user) + dslRW.insertSharingRestrictions(user) } override fun insert(apiKey: ApiKey) { - dsl + dslRW .insertInto(uak) .set(uak.ID, apiKey.id) .set(uak.USER_ID, apiKey.userId) @@ -130,7 +133,7 @@ class KomgaUserDao( @Transactional override fun update(user: KomgaUser) { - dsl + dslRW .update(u) .set(u.EMAIL, user.email) .set(u.PASSWORD, user.password) @@ -147,41 +150,41 @@ class KomgaUserDao( .where(u.ID.eq(user.id)) .execute() - dsl + dslRW .deleteFrom(ur) .where(ur.USER_ID.eq(user.id)) .execute() - dsl + dslRW .deleteFrom(ul) .where(ul.USER_ID.eq(user.id)) .execute() - dsl + dslRW .deleteFrom(us) .where(us.USER_ID.eq(user.id)) .execute() - insertRoles(user) - insertSharedLibraries(user) - insertSharingRestrictions(user) + dslRW.insertRoles(user) + dslRW.insertSharedLibraries(user) + dslRW.insertSharingRestrictions(user) } override fun saveAnnouncementIdsRead( user: KomgaUser, announcementIds: Set, ) { - dsl + dslRW .batch( announcementIds.map { - dsl.insertInto(ar).values(user.id, it).onDuplicateKeyIgnore() + dslRW.insertInto(ar).values(user.id, it).onDuplicateKeyIgnore() }, ).execute() } - private fun insertRoles(user: KomgaUser) { + private fun DSLContext.insertRoles(user: KomgaUser) { user.roles.forEach { - dsl + this .insertInto(ur) .columns(ur.USER_ID, ur.ROLE) .values(user.id, it.name) @@ -189,9 +192,9 @@ class KomgaUserDao( } } - private fun insertSharedLibraries(user: KomgaUser) { + private fun DSLContext.insertSharedLibraries(user: KomgaUser) { user.sharedLibrariesIds.forEach { - dsl + this .insertInto(ul) .columns(ul.USER_ID, ul.LIBRARY_ID) .values(user.id, it) @@ -199,9 +202,9 @@ class KomgaUserDao( } } - private fun insertSharingRestrictions(user: KomgaUser) { + private fun DSLContext.insertSharingRestrictions(user: KomgaUser) { user.restrictions.labelsAllow.forEach { label -> - dsl + this .insertInto(us) .columns(us.USER_ID, us.ALLOW, us.LABEL) .values(user.id, true, label) @@ -209,7 +212,7 @@ class KomgaUserDao( } user.restrictions.labelsExclude.forEach { label -> - dsl + this .insertInto(us) .columns(us.USER_ID, us.ALLOW, us.LABEL) .values(user.id, false, label) @@ -219,29 +222,29 @@ class KomgaUserDao( @Transactional override fun delete(userId: String) { - dsl.deleteFrom(uak).where(uak.USER_ID.equal(userId)).execute() - dsl.deleteFrom(ar).where(ar.USER_ID.equal(userId)).execute() - dsl.deleteFrom(us).where(us.USER_ID.equal(userId)).execute() - dsl.deleteFrom(ul).where(ul.USER_ID.equal(userId)).execute() - dsl.deleteFrom(ur).where(ur.USER_ID.equal(userId)).execute() - dsl.deleteFrom(u).where(u.ID.equal(userId)).execute() + dslRW.deleteFrom(uak).where(uak.USER_ID.equal(userId)).execute() + dslRW.deleteFrom(ar).where(ar.USER_ID.equal(userId)).execute() + dslRW.deleteFrom(us).where(us.USER_ID.equal(userId)).execute() + dslRW.deleteFrom(ul).where(ul.USER_ID.equal(userId)).execute() + dslRW.deleteFrom(ur).where(ur.USER_ID.equal(userId)).execute() + dslRW.deleteFrom(u).where(u.ID.equal(userId)).execute() } @Transactional override fun deleteAll() { - dsl.deleteFrom(uak).execute() - dsl.deleteFrom(ar).execute() - dsl.deleteFrom(us).execute() - dsl.deleteFrom(ul).execute() - dsl.deleteFrom(ur).execute() - dsl.deleteFrom(u).execute() + dslRW.deleteFrom(uak).execute() + dslRW.deleteFrom(ar).execute() + dslRW.deleteFrom(us).execute() + dslRW.deleteFrom(ul).execute() + dslRW.deleteFrom(ur).execute() + dslRW.deleteFrom(u).execute() } override fun deleteApiKeyByIdAndUserId( apiKeyId: String, userId: String, ) { - dsl + dslRW .deleteFrom(uak) .where(uak.ID.eq(apiKeyId)) .and(uak.USER_ID.eq(userId)) @@ -249,19 +252,19 @@ class KomgaUserDao( } override fun deleteApiKeyByUserId(userId: String) { - dsl.deleteFrom(uak).where(uak.USER_ID.eq(userId)).execute() + dslRW.deleteFrom(uak).where(uak.USER_ID.eq(userId)).execute() } override fun findAnnouncementIdsReadByUserId(userId: String): Set = - dsl + dslRO .select(ar.ANNOUNCEMENT_ID) .from(ar) .where(ar.USER_ID.eq(userId)) .fetchSet(ar.ANNOUNCEMENT_ID) override fun existsByEmailIgnoreCase(email: String): Boolean = - dsl.fetchExists( - dsl + dslRO.fetchExists( + dslRO .selectFrom(u) .where(u.EMAIL.equalIgnoreCase(email)), ) @@ -269,30 +272,32 @@ class KomgaUserDao( override fun existsApiKeyByIdAndUserId( apiKeyId: String, userId: String, - ): Boolean = dsl.fetchExists(uak, uak.ID.eq(apiKeyId).and(uak.USER_ID.eq(userId))) + ): Boolean = dslRO.fetchExists(uak, uak.ID.eq(apiKeyId).and(uak.USER_ID.eq(userId))) override fun existsApiKeyByCommentAndUserId( comment: String, userId: String, - ): Boolean = dsl.fetchExists(uak, uak.COMMENT.equalIgnoreCase(comment).and(uak.USER_ID.eq(userId))) + ): Boolean = dslRO.fetchExists(uak, uak.COMMENT.equalIgnoreCase(comment).and(uak.USER_ID.eq(userId))) override fun findByEmailIgnoreCaseOrNull(email: String): KomgaUser? = - selectBase() + dslRO + .selectBase() .where(u.EMAIL.equalIgnoreCase(email)) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() override fun findByApiKeyOrNull(apiKey: String): Pair? { val user = - selectBase() + dslRO + .selectBase() .leftJoin(uak) .on(u.ID.eq(uak.USER_ID)) .where(uak.API_KEY.eq(apiKey)) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() ?: return null val key = - dsl + dslRO .selectFrom(uak) .where(uak.API_KEY.eq(apiKey)) .fetchInto(uak) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt index 89470ea3b..3abaa8048 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/LibraryDao.kt @@ -8,6 +8,7 @@ import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext import org.jooq.Record import org.jooq.ResultQuery +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional import java.net.URL @@ -16,7 +17,8 @@ import java.time.ZoneId @Component class LibraryDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : LibraryRepository { private val l = Tables.LIBRARY private val ul = Tables.USER_LIBRARY_SHARING @@ -33,21 +35,23 @@ class LibraryDao( .first() private fun findOne(libraryId: String) = - selectBase() + dslRO + .selectBase() .where(l.ID.eq(libraryId)) override fun findAll(): Collection = - selectBase() + dslRO + .selectBase() .fetchAndMap() override fun findAllByIds(libraryIds: Collection): Collection = - selectBase() + dslRO + .selectBase() .where(l.ID.`in`(libraryIds)) .fetchAndMap() - private fun selectBase() = - dsl - .select() + private fun DSLContext.selectBase() = + select() .from(l) .leftJoin(le) .onKey() @@ -61,21 +65,21 @@ class LibraryDao( @Transactional override fun delete(libraryId: String) { - dsl.deleteFrom(le).where(le.LIBRARY_ID.eq(libraryId)).execute() - dsl.deleteFrom(ul).where(ul.LIBRARY_ID.eq(libraryId)).execute() - dsl.deleteFrom(l).where(l.ID.eq(libraryId)).execute() + dslRW.deleteFrom(le).where(le.LIBRARY_ID.eq(libraryId)).execute() + dslRW.deleteFrom(ul).where(ul.LIBRARY_ID.eq(libraryId)).execute() + dslRW.deleteFrom(l).where(l.ID.eq(libraryId)).execute() } @Transactional override fun deleteAll() { - dsl.deleteFrom(le).execute() - dsl.deleteFrom(ul).execute() - dsl.deleteFrom(l).execute() + dslRW.deleteFrom(le).execute() + dslRW.deleteFrom(ul).execute() + dslRW.deleteFrom(l).execute() } @Transactional override fun insert(library: Library) { - dsl + dslRW .insertInto(l) .set(l.ID, library.id) .set(l.NAME, library.name) @@ -108,12 +112,12 @@ class LibraryDao( .set(l.UNAVAILABLE_DATE, library.unavailableDate) .execute() - insertDirectoryExclusions(library) + dslRW.insertDirectoryExclusions(library) } @Transactional override fun update(library: Library) { - dsl + dslRW .update(l) .set(l.NAME, library.name) .set(l.ROOT, library.root.toString()) @@ -147,17 +151,17 @@ class LibraryDao( .where(l.ID.eq(library.id)) .execute() - dsl.deleteFrom(le).where(le.LIBRARY_ID.eq(library.id)).execute() - insertDirectoryExclusions(library) + dslRW.deleteFrom(le).where(le.LIBRARY_ID.eq(library.id)).execute() + dslRW.insertDirectoryExclusions(library) } - override fun count(): Long = dsl.fetchCount(l).toLong() + override fun count(): Long = dslRO.fetchCount(l).toLong() - private fun insertDirectoryExclusions(library: Library) { + private fun DSLContext.insertDirectoryExclusions(library: Library) { if (library.scanDirectoryExclusions.isNotEmpty()) { - dsl + this .batch( - dsl + this .insertInto(le, le.LIBRARY_ID, le.EXCLUSION) .values(null as String?, null), ).also { step -> diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt index f3df6ff92..e4a0cc123 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/MediaDao.kt @@ -18,6 +18,7 @@ import org.gotson.komga.jooq.main.tables.records.MediaRecord import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -26,7 +27,8 @@ import java.time.ZoneId @Component class MediaDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, private val mapper: ObjectMapper, ) : MediaRepository { @@ -50,12 +52,12 @@ class MediaDao( *p.fields(), ) - override fun findById(bookId: String): Media = find(dsl, bookId)!! + override fun findById(bookId: String): Media = dslRO.find(bookId)!! - override fun findByIdOrNull(bookId: String): Media? = find(dsl, bookId) + override fun findByIdOrNull(bookId: String): Media? = dslRO.find(bookId) override fun findExtensionByIdOrNull(bookId: String): MediaExtension? = - dsl + dslRO .select(m.EXTENSION_CLASS, m.EXTENSION_VALUE_BLOB) .from(m) .where(m.BOOK_ID.eq(bookId)) @@ -72,7 +74,7 @@ class MediaDao( val neededHash = pageHashing * 2 val neededHashForBook = DSL.`when`(pagesCount.lt(neededHash), pagesCount).otherwise(neededHash) - return dsl + return dslRO .select(b.ID) .from(b) .leftJoin(p) @@ -89,18 +91,17 @@ class MediaDao( } override fun getPagesSizes(bookIds: Collection): Collection> = - dsl + dslRO .select(m.BOOK_ID, m.PAGE_COUNT) .from(m) .where(m.BOOK_ID.`in`(bookIds)) .fetch() .map { Pair(it[m.BOOK_ID], it[m.PAGE_COUNT]) } - private fun find( - dsl: DSLContext, + private fun DSLContext.find( bookId: String, ): Media? = - dsl + this .select(*groupFields) .from(m) .leftJoin(p) @@ -113,7 +114,7 @@ class MediaDao( { it.into(p) }, ).map { (mr, pr) -> val files = - dsl + this .selectFrom(f) .where(f.BOOK_ID.eq(bookId)) .fetchInto(f) @@ -130,9 +131,9 @@ class MediaDao( override fun insert(medias: Collection) { if (medias.isNotEmpty()) { medias.chunked(batchSize).forEach { chunk -> - dsl + dslRW .batch( - dsl + dslRW .insertInto( m, m.BOOK_ID, @@ -162,17 +163,17 @@ class MediaDao( }.execute() } - insertPages(medias) - insertFiles(medias) + dslRW.insertPages(medias) + dslRW.insertFiles(medias) } } - private fun insertPages(medias: Collection) { + private fun DSLContext.insertPages(medias: Collection) { if (medias.any { it.pages.isNotEmpty() }) { medias.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto( p, p.BOOK_ID, @@ -204,12 +205,12 @@ class MediaDao( } } - private fun insertFiles(medias: Collection) { + private fun DSLContext.insertFiles(medias: Collection) { if (medias.any { it.files.isNotEmpty() }) { medias.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto( f, f.BOOK_ID, @@ -237,7 +238,7 @@ class MediaDao( @Transactional override fun update(media: Media) { - dsl + dslRW .update(m) .set(m.STATUS, media.status.toString()) .set(m.MEDIA_TYPE, media.mediaType) @@ -254,37 +255,37 @@ class MediaDao( .where(m.BOOK_ID.eq(media.bookId)) .execute() - dsl + dslRW .deleteFrom(p) .where(p.BOOK_ID.eq(media.bookId)) .execute() - dsl + dslRW .deleteFrom(f) .where(f.BOOK_ID.eq(media.bookId)) .execute() - insertPages(listOf(media)) - insertFiles(listOf(media)) + dslRW.insertPages(listOf(media)) + dslRW.insertFiles(listOf(media)) } @Transactional override fun delete(bookId: String) { - dsl.deleteFrom(p).where(p.BOOK_ID.eq(bookId)).execute() - dsl.deleteFrom(f).where(f.BOOK_ID.eq(bookId)).execute() - dsl.deleteFrom(m).where(m.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(p).where(p.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(f).where(f.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(m).where(m.BOOK_ID.eq(bookId)).execute() } @Transactional override fun delete(bookIds: Collection) { - dsl.withTempTable(batchSize, bookIds).use { - dsl.deleteFrom(p).where(p.BOOK_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(f).where(f.BOOK_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(m).where(m.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, bookIds).use { + dslRW.deleteFrom(p).where(p.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(f).where(f.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(m).where(m.BOOK_ID.`in`(it.selectTempStrings())).execute() } } - override fun count(): Long = dsl.fetchCount(m).toLong() + override fun count(): Long = dslRO.fetchCount(m).toLong() private fun MediaRecord.toDomain( pages: List, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt index 6e4c67776..cac605ad7 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/PageHashDao.kt @@ -11,6 +11,7 @@ import org.gotson.komga.jooq.main.tables.records.PageHashRecord import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest @@ -24,7 +25,8 @@ import java.time.ZoneId @Component class PageHashDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : PageHashRepository { private val p = Tables.MEDIA_PAGE private val b = Tables.BOOK @@ -54,7 +56,7 @@ class PageHashDao( ) override fun findKnown(pageHash: String): PageHashKnown? = - dsl + dslRO .selectFrom(ph) .where(ph.HASH.eq(pageHash)) .fetchOneInto(ph) @@ -65,7 +67,7 @@ class PageHashDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .select(*ph.fields(), DSL.count(p.FILE_HASH).`as`("count")) .from(ph) .leftJoin(p) @@ -73,7 +75,7 @@ class PageHashDao( .apply { actions?.let { where(ph.ACTION.`in`(actions)) } } .groupBy(*ph.fields()) - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) val orderBy = pageable.sort.toOrderBy(sortsKnown) val items = @@ -97,7 +99,7 @@ class PageHashDao( override fun findAllUnknown(pageable: Pageable): Page { val bookCount = DSL.count(p.BOOK_ID) val query = - dsl + dslRO .select( p.FILE_HASH, p.FILE_SIZE, @@ -107,7 +109,7 @@ class PageHashDao( .where(p.FILE_HASH.ne("")) .and( DSL.notExists( - dsl + dslRO .selectOne() .from(ph) .where(ph.HASH.eq(p.FILE_HASH)), @@ -115,7 +117,7 @@ class PageHashDao( ).groupBy(p.FILE_HASH) .having(DSL.count(p.BOOK_ID).gt(1)) - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) val orderBy = pageable.sort.toOrderBy(sortsUnknown) val items = @@ -142,14 +144,14 @@ class PageHashDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .select(p.BOOK_ID, b.URL, p.NUMBER, p.FILE_NAME, p.FILE_SIZE, p.MEDIA_TYPE) .from(p) .leftJoin(b) .on(p.BOOK_ID.eq(b.ID)) .where(p.FILE_HASH.eq(pageHash)) - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) val orderBy = pageable.sort.toOrderBy(sortsUnknown) val items = @@ -182,7 +184,7 @@ class PageHashDao( actions: List?, libraryId: String?, ): Map> = - dsl + dslRO .select(p.BOOK_ID, p.FILE_NAME, p.NUMBER, p.FILE_HASH, p.MEDIA_TYPE, p.FILE_SIZE) .from(p) .innerJoin(ph) @@ -203,7 +205,7 @@ class PageHashDao( .fold(emptyList()) { acc, (_, new) -> acc + new } override fun getKnownThumbnail(pageHash: String): ByteArray? = - dsl + dslRO .select(pht.THUMBNAIL) .from(pht) .where(pht.HASH.eq(pageHash)) @@ -215,7 +217,7 @@ class PageHashDao( pageHash: PageHashKnown, thumbnail: ByteArray?, ) { - dsl + dslRW .insertInto(ph) .set(ph.HASH, pageHash.hash) .set(ph.SIZE, pageHash.size) @@ -223,7 +225,7 @@ class PageHashDao( .execute() if (thumbnail != null) { - dsl + dslRW .insertInto(pht) .set(pht.HASH, pageHash.hash) .set(pht.THUMBNAIL, thumbnail) @@ -232,7 +234,7 @@ class PageHashDao( } override fun update(pageHash: PageHashKnown) { - dsl + dslRW .update(ph) .set(ph.ACTION, pageHash.action.name) .set(ph.SIZE, pageHash.size) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt index d4119f2d5..1c3b0003b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListDao.kt @@ -17,6 +17,7 @@ import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext import org.jooq.Record import org.jooq.ResultQuery +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl @@ -31,7 +32,8 @@ import java.util.SortedMap @Component class ReadListDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, private val luceneHelper: LuceneHelper, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : ReadListRepository { @@ -52,11 +54,12 @@ class ReadListDao( filterOnLibraryIds: Collection?, restrictions: ContentRestrictions, ): ReadList? = - selectBase(restrictions.isRestricted) + dslRO + .selectBase(restrictions.isRestricted) .where(rl.ID.eq(readListId)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } - .fetchAndMap(filterOnLibraryIds, restrictions) + .fetchAndMap(dslRO, filterOnLibraryIds, restrictions) .firstOrNull() override fun findAll( @@ -79,7 +82,7 @@ class ReadListDao( if (belongsToLibraryIds == null && filterOnLibraryIds == null && !restrictions.isRestricted) null else - dsl + dslRO .selectDistinct(rl.ID) .from(rl) .leftJoin(rlb) @@ -91,9 +94,9 @@ class ReadListDao( val count = if (queryIds != null) - dsl.fetchCount(queryIds) + dslRO.fetchCount(queryIds) else - dsl.fetchCount(rl, searchCondition) + dslRO.fetchCount(rl, searchCondition) val orderBy = pageable.sort.mapNotNull { @@ -104,12 +107,13 @@ class ReadListDao( } val items = - selectBase(restrictions.isRestricted) + dslRO + .selectBase(restrictions.isRestricted) .where(conditions) .apply { if (queryIds != null) and(rl.ID.`in`(queryIds)) } .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } - .fetchAndMap(filterOnLibraryIds, restrictions) + .fetchAndMap(dslRO, filterOnLibraryIds, restrictions) val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted() return PageImpl( @@ -128,7 +132,7 @@ class ReadListDao( restrictions: ContentRestrictions, ): Collection { val queryIds = - dsl + dslRO .select(rl.ID) .from(rl) .leftJoin(rlb) @@ -137,19 +141,20 @@ class ReadListDao( .where(rlb.BOOK_ID.eq(containsBookId)) .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } - return selectBase(restrictions.isRestricted) + return dslRO + .selectBase(restrictions.isRestricted) .where(rl.ID.`in`(queryIds)) .apply { filterOnLibraryIds?.let { and(b.LIBRARY_ID.`in`(it)) } } .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } - .fetchAndMap(filterOnLibraryIds, restrictions) + .fetchAndMap(dslRO, filterOnLibraryIds, restrictions) } override fun findAllEmpty(): Collection = - dsl + dslRO .selectFrom(rl) .where( rl.ID.`in`( - dsl + dslRO .select(rl.ID) .from(rl) .leftJoin(rlb) @@ -160,13 +165,14 @@ class ReadListDao( .map { it.toDomain(sortedMapOf()) } override fun findByNameOrNull(name: String): ReadList? = - selectBase() + dslRO + .selectBase() .where(rl.NAME.equalIgnoreCase(name)) - .fetchAndMap(null) + .fetchAndMap(dslRO, null) .firstOrNull() - private fun selectBase(joinOnSeriesMetadata: Boolean = false) = - dsl + private fun DSLContext.selectBase(joinOnSeriesMetadata: Boolean = false) = + this .selectDistinct(*rl.fields()) .from(rl) .leftJoin(rlb) @@ -176,6 +182,7 @@ class ReadListDao( .apply { if (joinOnSeriesMetadata) leftJoin(sd).on(sd.SERIES_ID.eq(b.SERIES_ID)) } private fun ResultQuery.fetchAndMap( + dsl: DSLContext, filterOnLibraryIds: Collection?, restrictions: ContentRestrictions = ContentRestrictions(), ): List = @@ -201,7 +208,7 @@ class ReadListDao( @Transactional override fun insert(readList: ReadList) { - dsl + dslRW .insertInto(rl) .set(rl.ID, readList.id) .set(rl.NAME, readList.name) @@ -210,12 +217,12 @@ class ReadListDao( .set(rl.BOOK_COUNT, readList.bookIds.size) .execute() - insertBooks(readList) + dslRW.insertBooks(readList) } - private fun insertBooks(readList: ReadList) { + private fun DSLContext.insertBooks(readList: ReadList) { readList.bookIds.map { (index, id) -> - dsl + this .insertInto(rlb) .set(rlb.READLIST_ID, readList.id) .set(rlb.BOOK_ID, id) @@ -226,7 +233,7 @@ class ReadListDao( @Transactional override fun update(readList: ReadList) { - dsl + dslRW .update(rl) .set(rl.NAME, readList.name) .set(rl.SUMMARY, readList.summary) @@ -236,13 +243,13 @@ class ReadListDao( .where(rl.ID.eq(readList.id)) .execute() - dsl.deleteFrom(rlb).where(rlb.READLIST_ID.eq(readList.id)).execute() + dslRW.deleteFrom(rlb).where(rlb.READLIST_ID.eq(readList.id)).execute() - insertBooks(readList) + dslRW.insertBooks(readList) } override fun removeBookFromAll(bookId: String) { - dsl + dslRW .deleteFrom(rlb) .where(rlb.BOOK_ID.eq(bookId)) .execute() @@ -250,8 +257,8 @@ class ReadListDao( @Transactional override fun removeBooksFromAll(bookIds: Collection) { - dsl.withTempTable(batchSize, bookIds).use { - dsl + dslRW.withTempTable(batchSize, bookIds).use { + dslRW .deleteFrom(rlb) .where(rlb.BOOK_ID.`in`(it.selectTempStrings())) .execute() @@ -260,30 +267,30 @@ class ReadListDao( @Transactional override fun delete(readListId: String) { - dsl.deleteFrom(rlb).where(rlb.READLIST_ID.eq(readListId)).execute() - dsl.deleteFrom(rl).where(rl.ID.eq(readListId)).execute() + dslRW.deleteFrom(rlb).where(rlb.READLIST_ID.eq(readListId)).execute() + dslRW.deleteFrom(rl).where(rl.ID.eq(readListId)).execute() } @Transactional override fun delete(readListIds: Collection) { - dsl.deleteFrom(rlb).where(rlb.READLIST_ID.`in`(readListIds)).execute() - dsl.deleteFrom(rl).where(rl.ID.`in`(readListIds)).execute() + dslRW.deleteFrom(rlb).where(rlb.READLIST_ID.`in`(readListIds)).execute() + dslRW.deleteFrom(rl).where(rl.ID.`in`(readListIds)).execute() } @Transactional override fun deleteAll() { - dsl.deleteFrom(rlb).execute() - dsl.deleteFrom(rl).execute() + dslRW.deleteFrom(rlb).execute() + dslRW.deleteFrom(rl).execute() } override fun existsByName(name: String): Boolean = - dsl.fetchExists( - dsl + dslRO.fetchExists( + dslRO .selectFrom(rl) .where(rl.NAME.equalIgnoreCase(name)), ) - override fun count(): Long = dsl.fetchCount(rl).toLong() + override fun count(): Long = dslRO.fetchCount(rl).toLong() private fun ReadlistRecord.toDomain(bookIds: SortedMap) = ReadList( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt index 426ee3f90..f73eaf79c 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadListRequestDao.kt @@ -12,12 +12,13 @@ import org.jooq.impl.DSL.ltrim import org.jooq.impl.DSL.row import org.jooq.impl.DSL.value import org.jooq.impl.DSL.values +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import java.time.LocalDate @Component class ReadListRequestDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : ReadListRequestRepository { private val sd = Tables.SERIES_METADATA private val b = Tables.BOOK @@ -32,7 +33,7 @@ class ReadListRequestDao( val numberField = "number" val requestsTable = values(*requestsAsRows.toTypedArray()).`as`("request", indexField, seriesField, numberField) val matchedRequests = - dsl + dslRO .select( requestsTable.field(indexField, Int::class.java), sd.SERIES_ID, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt index fa99ab1ee..a5acc84af 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDao.kt @@ -15,6 +15,7 @@ import org.gotson.komga.language.toUTC import org.jooq.DSLContext import org.jooq.Query import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -23,7 +24,8 @@ import java.time.ZoneId @Component class ReadProgressDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, private val mapper: ObjectMapper, ) : ReadProgressRepository { @@ -32,7 +34,7 @@ class ReadProgressDao( private val b = Tables.BOOK override fun findAll(): Collection = - dsl + dslRO .selectFrom(r) .fetchInto(r) .map { it.toDomain() } @@ -41,21 +43,21 @@ class ReadProgressDao( bookId: String, userId: String, ): ReadProgress? = - dsl + dslRO .selectFrom(r) .where(r.BOOK_ID.eq(bookId).and(r.USER_ID.eq(userId))) .fetchOneInto(r) ?.toDomain() override fun findAllByUserId(userId: String): Collection = - dsl + dslRO .selectFrom(r) .where(r.USER_ID.eq(userId)) .fetchInto(r) .map { it.toDomain() } override fun findAllByBookId(bookId: String): Collection = - dsl + dslRO .selectFrom(r) .where(r.BOOK_ID.eq(bookId)) .fetchInto(r) @@ -65,7 +67,7 @@ class ReadProgressDao( bookIds: Collection, userId: String, ): Collection = - dsl + dslRO .selectFrom(r) .where(r.BOOK_ID.`in`(bookIds).and(r.USER_ID.eq(userId))) .fetchInto(r) @@ -73,25 +75,25 @@ class ReadProgressDao( @Transactional override fun save(readProgress: ReadProgress) { - readProgress.toQuery().execute() - aggregateSeriesProgress(listOf(readProgress.bookId), readProgress.userId) + readProgress.toQuery(dslRW).execute() + dslRW.aggregateSeriesProgress(listOf(readProgress.bookId), readProgress.userId) } @Transactional override fun save(readProgresses: Collection) { readProgresses - .map { it.toQuery() } + .map { it.toQuery(dslRW) } .chunked(batchSize) - .forEach { chunk -> dsl.batch(chunk).execute() } + .forEach { chunk -> dslRW.batch(chunk).execute() } readProgresses .groupBy { it.userId } .forEach { (userId, readProgresses) -> - aggregateSeriesProgress(readProgresses.map { it.bookId }, userId) + dslRW.aggregateSeriesProgress(readProgresses.map { it.bookId }, userId) } } - private fun ReadProgress.toQuery(): Query = + private fun ReadProgress.toQuery(dsl: DSLContext): Query = dsl .insertInto( r, @@ -126,34 +128,34 @@ class ReadProgressDao( bookId: String, userId: String, ) { - dsl.deleteFrom(r).where(r.BOOK_ID.eq(bookId).and(r.USER_ID.eq(userId))).execute() - aggregateSeriesProgress(listOf(bookId), userId) + dslRW.deleteFrom(r).where(r.BOOK_ID.eq(bookId).and(r.USER_ID.eq(userId))).execute() + dslRW.aggregateSeriesProgress(listOf(bookId), userId) } @Transactional override fun deleteByUserId(userId: String) { - dsl.deleteFrom(r).where(r.USER_ID.eq(userId)).execute() - dsl.deleteFrom(rs).where(rs.USER_ID.eq(userId)).execute() + dslRW.deleteFrom(r).where(r.USER_ID.eq(userId)).execute() + dslRW.deleteFrom(rs).where(rs.USER_ID.eq(userId)).execute() } @Transactional override fun deleteByBookId(bookId: String) { - dsl.deleteFrom(r).where(r.BOOK_ID.eq(bookId)).execute() - aggregateSeriesProgress(listOf(bookId)) + dslRW.deleteFrom(r).where(r.BOOK_ID.eq(bookId)).execute() + dslRW.aggregateSeriesProgress(listOf(bookId)) } @Transactional override fun deleteByBookIds(bookIds: Collection) { - dsl.withTempTable(batchSize, bookIds).use { tempTable -> - dsl.deleteFrom(r).where(r.BOOK_ID.`in`(tempTable.selectTempStrings())).execute() - aggregateSeriesProgress(tempTable) + dslRW.withTempTable(batchSize, bookIds).use { tempTable -> + dslRW.deleteFrom(r).where(r.BOOK_ID.`in`(tempTable.selectTempStrings())).execute() + dslRW.aggregateSeriesProgress(tempTable) } } @Transactional override fun deleteBySeriesIds(seriesIds: Collection) { - dsl.withTempTable(batchSize, seriesIds).use { - dsl.deleteFrom(rs).where(rs.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, seriesIds).use { + dslRW.deleteFrom(rs).where(rs.SERIES_ID.`in`(it.selectTempStrings())).execute() } } @@ -162,54 +164,54 @@ class ReadProgressDao( bookIds: Collection, userId: String, ) { - dsl.withTempTable(batchSize, bookIds).use { tempTable -> - dsl + dslRW.withTempTable(batchSize, bookIds).use { tempTable -> + dslRW .deleteFrom(r) .where(r.BOOK_ID.`in`(tempTable.selectTempStrings())) .and(r.USER_ID.eq(userId)) .execute() - aggregateSeriesProgress(tempTable, userId) + dslRW.aggregateSeriesProgress(tempTable, userId) } } @Transactional override fun deleteAll() { - dsl.deleteFrom(r).execute() - dsl.deleteFrom(rs).execute() + dslRW.deleteFrom(r).execute() + dslRW.deleteFrom(rs).execute() } - private fun aggregateSeriesProgress( + private fun DSLContext.aggregateSeriesProgress( bookIds: Collection, userId: String? = null, ) { - dsl.withTempTable(batchSize, bookIds).use { tempTable -> - aggregateSeriesProgress(tempTable, userId) + this.withTempTable(batchSize, bookIds).use { tempTable -> + this.aggregateSeriesProgress(tempTable, userId) } } /** * Get the book IDs from an existing TempTable to avoid recreating another temporary table if one already exists. */ - private fun aggregateSeriesProgress( + private fun DSLContext.aggregateSeriesProgress( bookIdsTempTable: TempTable, userId: String? = null, ) { val seriesIdsQuery = - dsl + this .select(b.SERIES_ID) .from(b) .where(b.ID.`in`(bookIdsTempTable.selectTempStrings())) - dsl + this .deleteFrom(rs) .where(rs.SERIES_ID.`in`(seriesIdsQuery)) .apply { userId?.let { and(rs.USER_ID.eq(it)) } } .execute() - dsl + this .insertInto(rs) .select( - dsl + this .select(b.SERIES_ID, r.USER_ID) .select(DSL.sum(DSL.`when`(r.COMPLETED.isTrue, 1).otherwise(0))) .select(DSL.sum(DSL.`when`(r.COMPLETED.isFalse, 1).otherwise(0))) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt index b0151bcb0..d595d9ae6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReadProgressDtoDao.kt @@ -10,12 +10,13 @@ import org.jooq.DSLContext import org.jooq.Record2 import org.jooq.impl.DSL import org.jooq.impl.DSL.rowNumber +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import java.math.BigDecimal @Component class ReadProgressDtoDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : ReadProgressDtoRepository { private val rlb = Tables.READLIST_BOOK private val b = Tables.BOOK @@ -31,7 +32,7 @@ class ReadProgressDtoDao( userId: String, ): TachiyomiReadProgressV2Dto { val numberSortReadProgress = - dsl + dslRO .select( d.NUMBER_SORT, r.COMPLETED, @@ -47,7 +48,7 @@ class ReadProgressDtoDao( .toList() val maxNumberSort = - dsl + dslRO .select(DSL.max(d.NUMBER_SORT)) .from(b) .leftJoin(d) @@ -63,7 +64,7 @@ class ReadProgressDtoDao( private fun getSeriesBooksCount( seriesId: String, userId: String, - ) = dsl + ) = dslRO .select(countUnread.`as`(BOOKS_UNREAD_COUNT)) .select(countRead.`as`(BOOKS_READ_COUNT)) .select(countInProgress.`as`(BOOKS_IN_PROGRESS_COUNT)) @@ -87,7 +88,7 @@ class ReadProgressDtoDao( userId: String, ): TachiyomiReadProgressDto { val indexedReadProgress = - dsl + dslRO .select( rowNumber().over().orderBy(rlb.NUMBER), r.COMPLETED, @@ -103,7 +104,7 @@ class ReadProgressDtoDao( .toList() val booksCountRecord = - dsl + dslRO .select(countUnread.`as`(BOOKS_UNREAD_COUNT)) .select(countRead.`as`(BOOKS_READ_COUNT)) .select(countInProgress.`as`(BOOKS_IN_PROGRESS_COUNT)) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt index 34593420a..c86d5f3a6 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ReferentialDao.kt @@ -11,6 +11,7 @@ import org.gotson.komga.language.stripAccents import org.jooq.DSLContext import org.jooq.impl.DSL.noCondition import org.jooq.impl.DSL.select +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest @@ -21,7 +22,7 @@ import java.time.LocalDate @Component class ReferentialDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : ReferentialRepository { private val a = Tables.BOOK_METADATA_AUTHOR private val sd = Tables.SERIES_METADATA @@ -41,7 +42,7 @@ class ReferentialDao( search: String, filterOnLibraryIds: Collection?, ): List = - dsl + dslRO .selectDistinct(a.NAME, a.ROLE) .from(a) .apply { filterOnLibraryIds?.let { leftJoin(b).on(a.BOOK_ID.eq(b.ID)) } } @@ -56,7 +57,7 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): List = - dsl + dslRO .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) .leftJoin(s) @@ -73,7 +74,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): List = - dsl + dslRO .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) .leftJoin(cs) @@ -91,7 +92,7 @@ class ReferentialDao( seriesId: String, filterOnLibraryIds: Collection?, ): List = - dsl + dslRO .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) .apply { filterOnLibraryIds?.let { leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID)) } } @@ -161,7 +162,7 @@ class ReferentialDao( filterBy: FilterBy?, ): Page { val query = - dsl + dslRO .selectDistinct(bmaa.NAME, bmaa.ROLE) .from(bmaa) .apply { if (filterOnLibraryIds != null || filterBy?.type == FilterByType.LIBRARY) leftJoin(s).on(bmaa.SERIES_ID.eq(s.ID)) } @@ -187,7 +188,7 @@ class ReferentialDao( } } - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) val sort = bmaa.NAME.collate(SqliteUdfDataSource.COLLATION_UNICODE_3) val items = @@ -212,7 +213,7 @@ class ReferentialDao( search: String, filterOnLibraryIds: Collection?, ): List = - dsl + dslRO .selectDistinct(a.NAME) .from(a) .apply { filterOnLibraryIds?.let { leftJoin(b).on(a.BOOK_ID.eq(b.ID)) } } @@ -222,7 +223,7 @@ class ReferentialDao( .fetch(a.NAME) override fun findAllAuthorsRoles(filterOnLibraryIds: Collection?): List = - dsl + dslRO .selectDistinct(a.ROLE) .from(a) .apply { @@ -235,7 +236,7 @@ class ReferentialDao( .fetch(a.ROLE) override fun findAllGenres(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .selectDistinct(g.GENRE) .from(g) .apply { @@ -251,7 +252,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(g.GENRE) .from(g) .leftJoin(s) @@ -265,7 +266,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(g.GENRE) .from(g) .leftJoin(cs) @@ -277,7 +278,7 @@ class ReferentialDao( .fetchSet(g.GENRE) override fun findAllSeriesAndBookTags(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .select(bt.TAG.`as`("tag")) .from(bt) .apply { filterOnLibraryIds?.let { leftJoin(b).on(bt.BOOK_ID.eq(b.ID)).where(b.LIBRARY_ID.`in`(it)) } } @@ -293,7 +294,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .select(bt.TAG.`as`("tag")) .from(bt) .leftJoin(b) @@ -315,7 +316,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .select(bmat.TAG.`as`("tag")) .from(bmat) .leftJoin(s) @@ -338,7 +339,7 @@ class ReferentialDao( .toSet() override fun findAllSeriesTags(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .select(st.TAG) .from(st) .apply { @@ -354,7 +355,7 @@ class ReferentialDao( libraryId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .select(st.TAG) .from(st) .leftJoin(s) @@ -368,7 +369,7 @@ class ReferentialDao( seriesId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .select(bt.TAG) .from(bt) .leftJoin(b) @@ -382,7 +383,7 @@ class ReferentialDao( readListId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .select(bt.TAG) .from(bt) .leftJoin(b) @@ -398,7 +399,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .select(st.TAG) .from(st) .leftJoin(cs) @@ -410,7 +411,7 @@ class ReferentialDao( .fetchSet(st.TAG) override fun findAllBookTags(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .select(bt.TAG) .from(bt) .apply { @@ -423,7 +424,7 @@ class ReferentialDao( .fetchSet(bt.TAG) override fun findAllLanguages(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .selectDistinct(sd.LANGUAGE) .from(sd) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } @@ -436,7 +437,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sd.LANGUAGE) .from(sd) .leftJoin(s) @@ -451,7 +452,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sd.LANGUAGE) .from(sd) .leftJoin(cs) @@ -464,7 +465,7 @@ class ReferentialDao( .fetchSet(sd.LANGUAGE) override fun findAllPublishers(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .selectDistinct(sd.PUBLISHER) .from(sd) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } @@ -478,14 +479,14 @@ class ReferentialDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .selectDistinct(sd.PUBLISHER) .from(sd) .apply { filterOnLibraryIds?.let { leftJoin(s).on(sd.SERIES_ID.eq(s.ID)) } } .where(sd.PUBLISHER.ne("")) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) val sort = sd.PUBLISHER.collate(SqliteUdfDataSource.COLLATION_UNICODE_3) val items = @@ -509,7 +510,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sd.PUBLISHER) .from(sd) .leftJoin(s) @@ -524,7 +525,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sd.PUBLISHER) .from(sd) .leftJoin(cs) @@ -537,7 +538,7 @@ class ReferentialDao( .fetchSet(sd.PUBLISHER) override fun findAllAgeRatings(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .selectDistinct(sd.AGE_RATING) .from(sd) .apply { @@ -553,7 +554,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sd.AGE_RATING) .from(sd) .leftJoin(s) @@ -567,7 +568,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sd.AGE_RATING) .from(sd) .leftJoin(cs) @@ -579,7 +580,7 @@ class ReferentialDao( .fetchSet(sd.AGE_RATING) override fun findAllSeriesReleaseDates(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .selectDistinct(bma.RELEASE_DATE) .from(bma) .apply { filterOnLibraryIds?.let { leftJoin(s).on(bma.SERIES_ID.eq(s.ID)) } } @@ -592,7 +593,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(bma.RELEASE_DATE) .from(bma) .leftJoin(s) @@ -607,7 +608,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(bma.RELEASE_DATE) .from(bma) .leftJoin(cs) @@ -620,7 +621,7 @@ class ReferentialDao( .fetchSet(bma.RELEASE_DATE) override fun findAllSharingLabels(filterOnLibraryIds: Collection?): Set = - dsl + dslRO .selectDistinct(sl.LABEL) .from(sl) .apply { @@ -636,7 +637,7 @@ class ReferentialDao( libraryIds: Set, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sl.LABEL) .from(sl) .leftJoin(s) @@ -650,7 +651,7 @@ class ReferentialDao( collectionId: String, filterOnLibraryIds: Collection?, ): Set = - dsl + dslRO .selectDistinct(sl.LABEL) .from(sl) .leftJoin(cs) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt index 9e50520ac..d38633ffd 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesCollectionDao.kt @@ -17,6 +17,7 @@ import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext import org.jooq.Record import org.jooq.ResultQuery +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl @@ -30,7 +31,8 @@ import java.time.ZoneId @Component class SeriesCollectionDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, private val luceneHelper: LuceneHelper, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : SeriesCollectionRepository { @@ -49,11 +51,12 @@ class SeriesCollectionDao( filterOnLibraryIds: Collection?, restrictions: ContentRestrictions, ): SeriesCollection? = - selectBase(restrictions.isRestricted) + dslRO + .selectBase(restrictions.isRestricted) .where(c.ID.eq(collectionId)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } - .fetchAndMap(filterOnLibraryIds, restrictions) + .fetchAndMap(dslRO, filterOnLibraryIds, restrictions) .firstOrNull() override fun findAll( @@ -76,7 +79,7 @@ class SeriesCollectionDao( if (belongsToLibraryIds == null && filterOnLibraryIds == null && !restrictions.isRestricted) null else - dsl + dslRO .selectDistinct(c.ID) .from(c) .leftJoin(cs) @@ -89,9 +92,9 @@ class SeriesCollectionDao( val count = if (queryIds != null) - dsl.fetchCount(queryIds) + dslRO.fetchCount(queryIds) else - dsl.fetchCount(c, searchCondition) + dslRO.fetchCount(c, searchCondition) val orderBy = pageable.sort.mapNotNull { @@ -102,12 +105,13 @@ class SeriesCollectionDao( } val items = - selectBase(restrictions.isRestricted) + dslRO + .selectBase(restrictions.isRestricted) .where(conditions) .apply { if (queryIds != null) and(c.ID.`in`(queryIds)) } .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } - .fetchAndMap(filterOnLibraryIds, restrictions) + .fetchAndMap(dslRO, filterOnLibraryIds, restrictions) val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted() return PageImpl( @@ -126,7 +130,7 @@ class SeriesCollectionDao( restrictions: ContentRestrictions, ): Collection { val queryIds = - dsl + dslRO .select(c.ID) .from(c) .leftJoin(cs) @@ -135,19 +139,20 @@ class SeriesCollectionDao( .where(cs.SERIES_ID.eq(containsSeriesId)) .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } - return selectBase(restrictions.isRestricted) + return dslRO + .selectBase(restrictions.isRestricted) .where(c.ID.`in`(queryIds)) .apply { filterOnLibraryIds?.let { and(s.LIBRARY_ID.`in`(it)) } } .apply { if (restrictions.isRestricted) and(restrictions.toCondition()) } - .fetchAndMap(filterOnLibraryIds, restrictions) + .fetchAndMap(dslRO, filterOnLibraryIds, restrictions) } override fun findAllEmpty(): Collection = - dsl + dslRO .selectFrom(c) .where( c.ID.`in`( - dsl + dslRO .select(c.ID) .from(c) .leftJoin(cs) @@ -158,13 +163,14 @@ class SeriesCollectionDao( .map { it.toDomain(emptyList()) } override fun findByNameOrNull(name: String): SeriesCollection? = - selectBase() + dslRO + .selectBase() .where(c.NAME.equalIgnoreCase(name)) - .fetchAndMap(null) + .fetchAndMap(dslRO, null) .firstOrNull() - private fun selectBase(joinOnSeriesMetadata: Boolean = false) = - dsl + private fun DSLContext.selectBase(joinOnSeriesMetadata: Boolean = false) = + this .selectDistinct(*c.fields()) .from(c) .leftJoin(cs) @@ -174,6 +180,7 @@ class SeriesCollectionDao( .apply { if (joinOnSeriesMetadata) leftJoin(sd).on(cs.SERIES_ID.eq(sd.SERIES_ID)) } private fun ResultQuery.fetchAndMap( + dsl: DSLContext, filterOnLibraryIds: Collection?, restrictions: ContentRestrictions = ContentRestrictions(), ): List = @@ -197,7 +204,7 @@ class SeriesCollectionDao( @Transactional override fun insert(collection: SeriesCollection) { - dsl + dslRW .insertInto(c) .set(c.ID, collection.id) .set(c.NAME, collection.name) @@ -205,12 +212,12 @@ class SeriesCollectionDao( .set(c.SERIES_COUNT, collection.seriesIds.size) .execute() - insertSeries(collection) + dslRW.insertSeries(collection) } - private fun insertSeries(collection: SeriesCollection) { + private fun DSLContext.insertSeries(collection: SeriesCollection) { collection.seriesIds.forEachIndexed { index, id -> - dsl + this .insertInto(cs) .set(cs.COLLECTION_ID, collection.id) .set(cs.SERIES_ID, id) @@ -221,7 +228,7 @@ class SeriesCollectionDao( @Transactional override fun update(collection: SeriesCollection) { - dsl + dslRW .update(c) .set(c.NAME, collection.name) .set(c.ORDERED, collection.ordered) @@ -230,14 +237,14 @@ class SeriesCollectionDao( .where(c.ID.eq(collection.id)) .execute() - dsl.deleteFrom(cs).where(cs.COLLECTION_ID.eq(collection.id)).execute() + dslRW.deleteFrom(cs).where(cs.COLLECTION_ID.eq(collection.id)).execute() - insertSeries(collection) + dslRW.insertSeries(collection) } @Transactional override fun removeSeriesFromAll(seriesId: String) { - dsl + dslRW .deleteFrom(cs) .where(cs.SERIES_ID.eq(seriesId)) .execute() @@ -245,8 +252,8 @@ class SeriesCollectionDao( @Transactional override fun removeSeriesFromAll(seriesIds: Collection) { - dsl.withTempTable(batchSize, seriesIds).use { - dsl + dslRW.withTempTable(batchSize, seriesIds).use { + dslRW .deleteFrom(cs) .where(cs.SERIES_ID.`in`(it.selectTempStrings())) .execute() @@ -255,30 +262,30 @@ class SeriesCollectionDao( @Transactional override fun delete(collectionId: String) { - dsl.deleteFrom(cs).where(cs.COLLECTION_ID.eq(collectionId)).execute() - dsl.deleteFrom(c).where(c.ID.eq(collectionId)).execute() + dslRW.deleteFrom(cs).where(cs.COLLECTION_ID.eq(collectionId)).execute() + dslRW.deleteFrom(c).where(c.ID.eq(collectionId)).execute() } @Transactional override fun delete(collectionIds: Collection) { - dsl.deleteFrom(cs).where(cs.COLLECTION_ID.`in`(collectionIds)).execute() - dsl.deleteFrom(c).where(c.ID.`in`(collectionIds)).execute() + dslRW.deleteFrom(cs).where(cs.COLLECTION_ID.`in`(collectionIds)).execute() + dslRW.deleteFrom(c).where(c.ID.`in`(collectionIds)).execute() } @Transactional override fun deleteAll() { - dsl.deleteFrom(cs).execute() - dsl.deleteFrom(c).execute() + dslRW.deleteFrom(cs).execute() + dslRW.deleteFrom(c).execute() } override fun existsByName(name: String): Boolean = - dsl.fetchExists( - dsl + dslRO.fetchExists( + dslRO .selectFrom(c) .where(c.NAME.equalIgnoreCase(name)), ) - override fun count(): Long = dsl.fetchCount(c).toLong() + override fun count(): Long = dslRO.fetchCount(c).toLong() private fun CollectionRecord.toDomain(seriesIds: List) = SeriesCollection( diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt index 9e8ef656a..f8e1c7b3e 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDao.kt @@ -11,15 +11,15 @@ import org.gotson.komga.infrastructure.jooq.csAlias import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.SeriesRecord import org.gotson.komga.language.toCurrentTimeZone -import org.jooq.Condition import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable -import org.springframework.data.domain.Sort +import org.springframework.data.domain.Sort.unsorted import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional import java.net.URL @@ -28,7 +28,8 @@ import java.time.ZoneId @Component class SeriesDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : SeriesRepository { private val s = Tables.SERIES @@ -37,20 +38,20 @@ class SeriesDao( private val bma = Tables.BOOK_METADATA_AGGREGATION override fun findAll(): Collection = - dsl + dslRO .selectFrom(s) .fetchInto(s) .map { it.toDomain() } override fun findByIdOrNull(seriesId: String): Series? = - dsl + dslRO .selectFrom(s) .where(s.ID.eq(seriesId)) .fetchOneInto(s) ?.toDomain() override fun findAllByLibraryId(libraryId: String): List = - dsl + dslRO .selectFrom(s) .where(s.LIBRARY_ID.eq(libraryId)) .fetchInto(s) @@ -61,8 +62,8 @@ class SeriesDao( libraryId: String, urls: Collection, ): List { - dsl.withTempTable(batchSize, urls.map { it.toString() }).use { tempTable -> - return dsl + dslRO.withTempTable(batchSize, urls.map { it.toString() }).use { tempTable -> + return dslRO .selectFrom(s) .where(s.LIBRARY_ID.eq(libraryId)) .and(s.DELETED_DATE.isNull) @@ -76,7 +77,7 @@ class SeriesDao( libraryId: String, url: URL, ): Series? = - dsl + dslRO .selectFrom(s) .where(s.LIBRARY_ID.eq(libraryId).and(s.URL.eq(url.toString()))) .and(s.DELETED_DATE.isNull) @@ -86,7 +87,7 @@ class SeriesDao( ?.toDomain() override fun findAllByTitleContaining(title: String): Collection = - dsl + dslRO .selectDistinct(*s.fields()) .from(s) .leftJoin(d) @@ -96,14 +97,14 @@ class SeriesDao( .map { it.toDomain() } override fun getLibraryId(seriesId: String): String? = - dsl + dslRO .select(s.LIBRARY_ID) .from(s) .where(s.ID.eq(seriesId)) .fetchOne(0, String::class.java) override fun findAllIdsByLibraryId(libraryId: String): Collection = - dsl + dslRO .select(s.ID) .from(s) .where(s.LIBRARY_ID.eq(libraryId)) @@ -115,16 +116,9 @@ class SeriesDao( pageable: Pageable, ): Page { val (conditions, joins) = SeriesSearchHelper(searchContext).toCondition(searchCondition) - return findAll(conditions, joins, pageable) - } - private fun findAll( - conditions: Condition, - joins: Set, - pageable: Pageable, - ): Page { val query = - dsl + dslRO .selectDistinct(*s.fields()) .from(s) .apply { @@ -145,7 +139,8 @@ class SeriesDao( } }.where(conditions) - val count = dsl.fetchCount(query) + val count = dslRO.fetchCount(query) + val items = query .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } @@ -155,15 +150,15 @@ class SeriesDao( return PageImpl( items, if (pageable.isPaged) - PageRequest.of(pageable.pageNumber, pageable.pageSize, Sort.unsorted()) + PageRequest.of(pageable.pageNumber, pageable.pageSize, unsorted()) else - PageRequest.of(0, maxOf(count, 20), Sort.unsorted()), + PageRequest.of(0, maxOf(count, 20), unsorted()), count.toLong(), ) } override fun insert(series: Series) { - dsl + dslRW .insertInto(s) .set(s.ID, series.id) .set(s.NAME, series.name) @@ -179,7 +174,7 @@ class SeriesDao( series: Series, updateModifiedTime: Boolean, ) { - dsl + dslRW .update(s) .set(s.NAME, series.name) .set(s.URL, series.url.toString()) @@ -194,24 +189,24 @@ class SeriesDao( } override fun delete(seriesId: String) { - dsl.deleteFrom(s).where(s.ID.eq(seriesId)).execute() + dslRW.deleteFrom(s).where(s.ID.eq(seriesId)).execute() } override fun deleteAll() { - dsl.deleteFrom(s).execute() + dslRW.deleteFrom(s).execute() } @Transactional override fun delete(seriesIds: Collection) { - dsl.withTempTable(batchSize, seriesIds).use { - dsl.deleteFrom(s).where(s.ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, seriesIds).use { + dslRW.deleteFrom(s).where(s.ID.`in`(it.selectTempStrings())).execute() } } - override fun count(): Long = dsl.fetchCount(s).toLong() + override fun count(): Long = dslRO.fetchCount(s).toLong() override fun countGroupedByLibraryId(): Map = - dsl + dslRO .select(s.LIBRARY_ID, DSL.count(s.ID)) .from(s) .groupBy(s.LIBRARY_ID) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt index e1d9d4ede..defe09935 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesDtoDao.kt @@ -36,6 +36,7 @@ import org.jooq.impl.DSL.count import org.jooq.impl.DSL.countDistinct import org.jooq.impl.DSL.lower import org.jooq.impl.DSL.substring +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl @@ -43,7 +44,6 @@ import org.springframework.data.domain.PageRequest import org.springframework.data.domain.Pageable import org.springframework.data.domain.Sort import org.springframework.stereotype.Component -import org.springframework.transaction.support.TransactionTemplate import java.net.URL const val BOOKS_UNREAD_COUNT = "booksUnreadCount" @@ -52,10 +52,9 @@ const val BOOKS_READ_COUNT = "booksReadCount" @Component class SeriesDtoDao( - private val dsl: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, private val luceneHelper: LuceneHelper, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, - private val transactionTemplate: TransactionTemplate, ) : SeriesDtoRepository { private val s = Tables.SERIES private val d = Tables.SERIES_METADATA @@ -139,7 +138,7 @@ class SeriesDtoDao( val searchCondition = s.ID.inOrNoCondition(seriesIds) val firstChar = lower(substring(d.TITLE_SORT, 1, 1)) - return dsl + return dslRO .select(firstChar, count()) .from(s) .leftJoin(d) @@ -178,18 +177,18 @@ class SeriesDtoDao( seriesId: String, userId: String, ): SeriesDto? = - selectBase(userId) + dslRO + .selectBase(userId) .where(s.ID.eq(seriesId)) .groupBy(*groupFields) - .fetchAndMap() + .fetchAndMap(dslRO) .firstOrNull() - private fun selectBase( + private fun DSLContext.selectBase( userId: String, joins: Set = emptySet(), - joinOnCollection: Boolean = false, ): SelectOnConditionStep = - dsl + this .select(*groupFields) .from(s) .leftJoin(d) @@ -229,7 +228,7 @@ class SeriesDtoDao( val searchCondition = s.ID.inOrNoCondition(seriesIds) val count = - dsl + dslRO .select(countDistinct(s.ID)) .from(s) .leftJoin(d) @@ -276,12 +275,13 @@ class SeriesDtoDao( } val dtos = - selectBase(userId, joins, pageable.sort.any { it.property == "collection.number" }) + dslRO + .selectBase(userId, joins) .where(conditions) .and(searchCondition) .orderBy(orderBy) .apply { if (pageable.isPaged) limit(pageable.pageSize).offset(pageable.offset) } - .fetchAndMap() + .fetchAndMap(dslRO) val pageSort = if (orderBy.isNotEmpty()) pageable.sort else Sort.unsorted() return PageImpl( @@ -296,7 +296,7 @@ class SeriesDtoDao( private fun readProgressConditionSeries(userId: String): Condition = rs.USER_ID.eq(userId).or(rs.USER_ID.isNull) - private fun ResultQuery.fetchAndMap(): MutableList { + private fun ResultQuery.fetchAndMap(dsl: DSLContext): MutableList { val records = fetch() val seriesIds = records.getValues(s.ID) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt index 2ca579278..9ba214eec 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SeriesMetadataDao.kt @@ -9,6 +9,7 @@ import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.SeriesMetadataRecord import org.gotson.komga.language.toCurrentTimeZone import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -18,7 +19,8 @@ import java.time.ZoneId @Component class SeriesMetadataDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : SeriesMetadataRepository { private val d = Tables.SERIES_METADATA @@ -28,47 +30,47 @@ class SeriesMetadataDao( private val slk = Tables.SERIES_METADATA_LINK private val sat = Tables.SERIES_METADATA_ALTERNATE_TITLE - override fun findById(seriesId: String): SeriesMetadata = findOne(seriesId)!!.toDomain(findGenres(seriesId), findTags(seriesId), findSharingLabels(seriesId), findLinks(seriesId), findAlternateTitles(seriesId)) + override fun findById(seriesId: String): SeriesMetadata = dslRO.findOne(seriesId)!!.toDomain(dslRO.findGenres(seriesId), dslRO.findTags(seriesId), dslRO.findSharingLabels(seriesId), dslRO.findLinks(seriesId), dslRO.findAlternateTitles(seriesId)) - override fun findByIdOrNull(seriesId: String): SeriesMetadata? = findOne(seriesId)?.toDomain(findGenres(seriesId), findTags(seriesId), findSharingLabels(seriesId), findLinks(seriesId), findAlternateTitles(seriesId)) + override fun findByIdOrNull(seriesId: String): SeriesMetadata? = dslRO.findOne(seriesId)?.toDomain(dslRO.findGenres(seriesId), dslRO.findTags(seriesId), dslRO.findSharingLabels(seriesId), dslRO.findLinks(seriesId), dslRO.findAlternateTitles(seriesId)) - private fun findOne(seriesId: String) = - dsl + private fun DSLContext.findOne(seriesId: String) = + this .selectFrom(d) .where(d.SERIES_ID.eq(seriesId)) .fetchOneInto(d) - private fun findGenres(seriesId: String) = - dsl + private fun DSLContext.findGenres(seriesId: String) = + this .select(g.GENRE) .from(g) .where(g.SERIES_ID.eq(seriesId)) .fetchSet(g.GENRE) - private fun findTags(seriesId: String) = - dsl + private fun DSLContext.findTags(seriesId: String) = + this .select(st.TAG) .from(st) .where(st.SERIES_ID.eq(seriesId)) .fetchSet(st.TAG) - private fun findSharingLabels(seriesId: String) = - dsl + private fun DSLContext.findSharingLabels(seriesId: String) = + this .select(sl.LABEL) .from(sl) .where(sl.SERIES_ID.eq(seriesId)) .fetchSet(sl.LABEL) - private fun findLinks(seriesId: String) = - dsl + private fun DSLContext.findLinks(seriesId: String) = + this .select(slk.LABEL, slk.URL) .from(slk) .where(slk.SERIES_ID.eq(seriesId)) .fetchInto(slk) .map { WebLink(it.label, URI(it.url)) } - private fun findAlternateTitles(seriesId: String) = - dsl + private fun DSLContext.findAlternateTitles(seriesId: String) = + this .select(sat.LABEL, sat.TITLE) .from(sat) .where(sat.SERIES_ID.eq(seriesId)) @@ -77,7 +79,7 @@ class SeriesMetadataDao( @Transactional override fun insert(metadata: SeriesMetadata) { - dsl + dslRW .insertInto(d) .set(d.SERIES_ID, metadata.seriesId) .set(d.STATUS, metadata.status.toString()) @@ -105,16 +107,16 @@ class SeriesMetadataDao( .set(d.ALTERNATE_TITLES_LOCK, metadata.alternateTitlesLock) .execute() - insertGenres(metadata) - insertTags(metadata) - insertSharingLabels(metadata) - insertLinks(metadata) - insertAlternateTitles(metadata) + dslRW.insertGenres(metadata) + dslRW.insertTags(metadata) + dslRW.insertSharingLabels(metadata) + dslRW.insertLinks(metadata) + dslRW.insertAlternateTitles(metadata) } @Transactional override fun update(metadata: SeriesMetadata) { - dsl + dslRW .update(d) .set(d.STATUS, metadata.status.toString()) .set(d.TITLE, metadata.title) @@ -143,44 +145,44 @@ class SeriesMetadataDao( .where(d.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(g) .where(g.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(st) .where(st.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(sl) .where(sl.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(slk) .where(slk.SERIES_ID.eq(metadata.seriesId)) .execute() - dsl + dslRW .deleteFrom(sat) .where(sat.SERIES_ID.eq(metadata.seriesId)) .execute() - insertGenres(metadata) - insertTags(metadata) - insertSharingLabels(metadata) - insertLinks(metadata) - insertAlternateTitles(metadata) + dslRW.insertGenres(metadata) + dslRW.insertTags(metadata) + dslRW.insertSharingLabels(metadata) + dslRW.insertLinks(metadata) + dslRW.insertAlternateTitles(metadata) } - private fun insertGenres(metadata: SeriesMetadata) { + private fun DSLContext.insertGenres(metadata: SeriesMetadata) { if (metadata.genres.isNotEmpty()) { metadata.genres.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(g, g.SERIES_ID, g.GENRE) .values(null as String?, null), ).also { step -> @@ -192,12 +194,12 @@ class SeriesMetadataDao( } } - private fun insertTags(metadata: SeriesMetadata) { + private fun DSLContext.insertTags(metadata: SeriesMetadata) { if (metadata.tags.isNotEmpty()) { metadata.tags.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(st, st.SERIES_ID, st.TAG) .values(null as String?, null), ).also { step -> @@ -209,12 +211,12 @@ class SeriesMetadataDao( } } - private fun insertSharingLabels(metadata: SeriesMetadata) { + private fun DSLContext.insertSharingLabels(metadata: SeriesMetadata) { if (metadata.sharingLabels.isNotEmpty()) { metadata.sharingLabels.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(sl, sl.SERIES_ID, sl.LABEL) .values(null as String?, null), ).also { step -> @@ -226,12 +228,12 @@ class SeriesMetadataDao( } } - private fun insertLinks(metadata: SeriesMetadata) { + private fun DSLContext.insertLinks(metadata: SeriesMetadata) { if (metadata.links.isNotEmpty()) { metadata.links.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(slk, slk.SERIES_ID, slk.LABEL, slk.URL) .values(null as String?, null, null), ).also { step -> @@ -243,12 +245,12 @@ class SeriesMetadataDao( } } - private fun insertAlternateTitles(metadata: SeriesMetadata) { + private fun DSLContext.insertAlternateTitles(metadata: SeriesMetadata) { if (metadata.alternateTitles.isNotEmpty()) { metadata.alternateTitles.chunked(batchSize).forEach { chunk -> - dsl + this .batch( - dsl + this .insertInto(sat, sat.SERIES_ID, sat.LABEL, sat.TITLE) .values(null as String?, null, null), ).also { step -> @@ -262,27 +264,27 @@ class SeriesMetadataDao( @Transactional override fun delete(seriesId: String) { - dsl.deleteFrom(g).where(g.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(st).where(st.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(sl).where(sl.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(slk).where(slk.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(sat).where(sat.SERIES_ID.eq(seriesId)).execute() - dsl.deleteFrom(d).where(d.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(g).where(g.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(st).where(st.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(sl).where(sl.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(slk).where(slk.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(sat).where(sat.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(d).where(d.SERIES_ID.eq(seriesId)).execute() } @Transactional override fun delete(seriesIds: Collection) { - dsl.withTempTable(batchSize, seriesIds).use { - dsl.deleteFrom(g).where(g.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(st).where(st.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(sl).where(sl.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(slk).where(slk.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(sat).where(sat.SERIES_ID.`in`(it.selectTempStrings())).execute() - dsl.deleteFrom(d).where(d.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, seriesIds).use { + dslRW.deleteFrom(g).where(g.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(st).where(st.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(sl).where(sl.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(slk).where(slk.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(sat).where(sat.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.deleteFrom(d).where(d.SERIES_ID.`in`(it.selectTempStrings())).execute() } } - override fun count(): Long = dsl.fetchCount(d).toLong() + override fun count(): Long = dslRO.fetchCount(d).toLong() private fun SeriesMetadataRecord.toDomain( genres: Set, diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt index 92dbf5e7e..a5fe965fd 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ServerSettingsDao.kt @@ -2,11 +2,13 @@ package org.gotson.komga.infrastructure.jooq.main import org.gotson.komga.jooq.main.Tables import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component @Component class ServerSettingsDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) { private val s = Tables.SERVER_SETTINGS @@ -14,7 +16,7 @@ class ServerSettingsDao( key: String, clazz: Class, ): T? = - dsl + dslRO .select(s.VALUE) .from(s) .where(s.KEY.eq(key)) @@ -24,7 +26,7 @@ class ServerSettingsDao( key: String, value: String, ) { - dsl + dslRW .insertInto(s) .values(key, value) .onDuplicateKeyUpdate() @@ -47,10 +49,10 @@ class ServerSettingsDao( } fun deleteSetting(key: String) { - dsl.deleteFrom(s).where(s.KEY.eq(key)).execute() + dslRW.deleteFrom(s).where(s.KEY.eq(key)).execute() } fun deleteAll() { - dsl.deleteFrom(s).execute() + dslRW.deleteFrom(s).execute() } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt index a44eb42ec..495c4e74b 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SidecarDao.kt @@ -8,6 +8,7 @@ import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.SidecarRecord import org.jooq.DSLContext import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -15,18 +16,19 @@ import java.net.URL @Component class SidecarDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : SidecarRepository { private val sc = Tables.SIDECAR - override fun findAll(): Collection = dsl.selectFrom(sc).fetch().map { it.toDomain() } + override fun findAll(): Collection = dslRO.selectFrom(sc).fetch().map { it.toDomain() } override fun save( libraryId: String, sidecar: Sidecar, ) { - dsl + dslRW .insertInto(sc) .values( sidecar.url.toString(), @@ -45,8 +47,8 @@ class SidecarDao( libraryId: String, urls: Collection, ) { - dsl.withTempTable(batchSize, urls.map { it.toString() }).use { - dsl + dslRW.withTempTable(batchSize, urls.map { it.toString() }).use { + dslRW .deleteFrom(sc) .where(sc.LIBRARY_ID.eq(libraryId)) .and(sc.URL.`in`(it.selectTempStrings())) @@ -55,14 +57,14 @@ class SidecarDao( } override fun deleteByLibraryId(libraryId: String) { - dsl + dslRW .deleteFrom(sc) .where(sc.LIBRARY_ID.eq(libraryId)) .execute() } override fun countGroupedByLibraryId(): Map = - dsl + dslRO .select(sc.LIBRARY_ID, DSL.count(sc.URL)) .from(sc) .groupBy(sc.LIBRARY_ID) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt index 26be6c85a..37942da7d 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/SyncPointDao.kt @@ -15,6 +15,7 @@ import org.jooq.Field import org.jooq.Record1 import org.jooq.SelectConditionStep import org.jooq.impl.DSL +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.data.domain.Page import org.springframework.data.domain.PageImpl import org.springframework.data.domain.PageRequest @@ -27,7 +28,8 @@ import java.time.ZoneId @Component class SyncPointDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, private val bookCommonDao: BookCommonDao, ) : SyncPointRepository { private val b = Tables.BOOK @@ -56,7 +58,7 @@ class SyncPointDao( val syncPointId = TsidCreator.getTsid256().toString() val createdAt = LocalDateTime.now(ZoneId.of("Z")) - dsl + dslRW .insertInto( sp, sp.ID, @@ -70,7 +72,7 @@ class SyncPointDao( createdAt, ).execute() - dsl + dslRW .insertInto( spb, spb.SYNC_POINT_ID, @@ -84,7 +86,7 @@ class SyncPointDao( spb.BOOK_READ_PROGRESS_LAST_MODIFIED_DATE, spb.BOOK_THUMBNAIL_ID, ).select( - dsl + dslRW .select( DSL.`val`(syncPointId), b.ID, @@ -143,16 +145,16 @@ class SyncPointDao( val (query, _, queryMostRecentDate) = bookCommonDao.getBooksOnDeckQuery(context.userId, context.restrictions, filterOnLibraryIds, onDeckFields) val count = - dsl + dslRW .insertInto(sprlb) .select(query) .execute() // only add the read list entry if some books were added if (count > 0) { - val mostRecentDate = dsl.fetch(queryMostRecentDate).into(LocalDateTime::class.java).firstOrNull() ?: createdAt + val mostRecentDate = dslRW.fetch(queryMostRecentDate).into(LocalDateTime::class.java).firstOrNull() ?: createdAt - dsl + dslRW .insertInto( sprl, sprl.SYNC_POINT_ID, @@ -171,7 +173,7 @@ class SyncPointDao( } override fun findByIdOrNull(syncPointId: String): SyncPoint? = - dsl + dslRO .selectFrom(sp) .where(sp.ID.eq(syncPointId)) .fetchInto(sp) @@ -190,7 +192,7 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .selectFrom(spb) .where(spb.SYNC_POINT_ID.eq(syncPointId)) .apply { @@ -199,7 +201,7 @@ class SyncPointDao( } } - return queryToPageBook(query, pageable) + return dslRO.queryToPageBook(query, pageable) } override fun findBooksAdded( @@ -209,7 +211,7 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .selectFrom(spb) .where(spb.SYNC_POINT_ID.eq(toSyncPointId)) .apply { @@ -218,11 +220,11 @@ class SyncPointDao( } }.and( spb.BOOK_ID.notIn( - dsl.select(spb.BOOK_ID).from(spb).where(spb.SYNC_POINT_ID.eq(fromSyncPointId)), + dslRO.select(spb.BOOK_ID).from(spb).where(spb.SYNC_POINT_ID.eq(fromSyncPointId)), ), ) - return queryToPageBook(query, pageable) + return dslRO.queryToPageBook(query, pageable) } override fun findBooksRemoved( @@ -232,23 +234,23 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .selectFrom(spb) .where(spb.SYNC_POINT_ID.eq(fromSyncPointId)) .and( spb.BOOK_ID.notIn( - dsl.select(spb.BOOK_ID).from(spb).where(spb.SYNC_POINT_ID.eq(toSyncPointId)), + dslRO.select(spb.BOOK_ID).from(spb).where(spb.SYNC_POINT_ID.eq(toSyncPointId)), ), ).apply { if (onlyNotSynced) and( spb.BOOK_ID.notIn( - dsl.select(spbs.BOOK_ID).from(spbs).where(spbs.SYNC_POINT_ID.eq(toSyncPointId)), + dslRO.select(spbs.BOOK_ID).from(spbs).where(spbs.SYNC_POINT_ID.eq(toSyncPointId)), ), ) } - return queryToPageBook(query, pageable) + return dslRO.queryToPageBook(query, pageable) } override fun findBooksChanged( @@ -259,7 +261,7 @@ class SyncPointDao( ): Page { val spbFrom = spb.`as`("spbFrom") val query = - dsl + dslRO .select(*spb.fields()) .from(spb) .join(spbFrom) @@ -279,7 +281,7 @@ class SyncPointDao( .or(spb.BOOK_THUMBNAIL_ID.ne(spbFrom.BOOK_THUMBNAIL_ID)), ) - return queryToPageBook(query, pageable) + return dslRO.queryToPageBook(query, pageable) } override fun findBooksReadProgressChanged( @@ -290,7 +292,7 @@ class SyncPointDao( ): Page { val spbFrom = spb.`as`("spbFrom") val query = - dsl + dslRO .select(*spb.fields()) .from(spb) .join(spbFrom) @@ -318,7 +320,7 @@ class SyncPointDao( ), ) - return queryToPageBook(query, pageable) + return dslRO.queryToPageBook(query, pageable) } override fun findReadListsById( @@ -327,7 +329,7 @@ class SyncPointDao( pageable: Pageable, ): Page { val query = - dsl + dslRO .selectFrom(sprl) .where(sprl.SYNC_POINT_ID.eq(syncPointId)) .apply { @@ -336,7 +338,7 @@ class SyncPointDao( } } - return queryToPageReadList(query, pageable) + return dslRO.queryToPageReadList(query, pageable) } override fun findReadListsAdded( @@ -348,7 +350,7 @@ class SyncPointDao( val to = sprl.`as`("to") val from = sprl.`as`("from") val query = - dsl + dslRO .select(*to.fields()) .from(to) .leftOuterJoin(from) @@ -357,7 +359,7 @@ class SyncPointDao( .apply { if (onlyNotSynced) and(to.SYNCED.isFalse) } .and(from.READLIST_ID.isNull) - return queryToPageReadList(query, pageable) + return dslRO.queryToPageReadList(query, pageable) } override fun findReadListsChanged( @@ -368,7 +370,7 @@ class SyncPointDao( ): Page { val from = sprl.`as`("from") val query = - dsl + dslRO .select(*sprl.fields()) .from(sprl) .join(from) @@ -382,7 +384,7 @@ class SyncPointDao( .or(sprl.READLIST_NAME.ne(from.READLIST_NAME)), ) - return queryToPageReadList(query, pageable) + return dslRO.queryToPageReadList(query, pageable) } override fun findReadListsRemoved( @@ -394,7 +396,7 @@ class SyncPointDao( val from = sprl.`as`("from") val to = sprl.`as`("to") val query = - dsl + dslRO .select(*from.fields()) .from(from) .leftOuterJoin(to) @@ -404,19 +406,19 @@ class SyncPointDao( if (onlyNotSynced) and( from.READLIST_ID.notIn( - dsl.select(sprls.READLIST_ID).from(sprls).where(sprls.SYNC_POINT_ID.eq(toSyncPointId)), + dslRO.select(sprls.READLIST_ID).from(sprls).where(sprls.SYNC_POINT_ID.eq(toSyncPointId)), ), ) }.and(to.READLIST_ID.isNull) - return queryToPageReadList(query, pageable) + return dslRO.queryToPageReadList(query, pageable) } override fun findBookIdsByReadListIds( syncPointId: String, readListIds: Collection, ): List = - dsl + dslRO .select(*sprlb.fields()) .from(sprlb) .where(sprlb.SYNC_POINT_ID.eq(syncPointId)) @@ -433,14 +435,14 @@ class SyncPointDao( // we store status in a separate table if (bookIds.isNotEmpty()) { if (forRemovedBooks) - dsl + dslRW .batch( - dsl.insertInto(spbs, spbs.SYNC_POINT_ID, spbs.BOOK_ID).values(null as String?, null).onDuplicateKeyIgnore(), + dslRW.insertInto(spbs, spbs.SYNC_POINT_ID, spbs.BOOK_ID).values(null as String?, null).onDuplicateKeyIgnore(), ).also { step -> bookIds.map { step.bind(syncPointId, it) } }.execute() else - dsl + dslRW .update(spb) .set(spb.SYNCED, true) .where(spb.SYNC_POINT_ID.eq(syncPointId)) @@ -458,14 +460,14 @@ class SyncPointDao( // we store status in a separate table if (readListIds.isNotEmpty()) { if (forRemovedReadLists) - dsl + dslRW .batch( - dsl.insertInto(sprls, sprls.SYNC_POINT_ID, sprls.READLIST_ID).values(null as String?, null).onDuplicateKeyIgnore(), + dslRW.insertInto(sprls, sprls.SYNC_POINT_ID, sprls.READLIST_ID).values(null as String?, null).onDuplicateKeyIgnore(), ).also { step -> readListIds.map { step.bind(syncPointId, it) } }.execute() else - dsl + dslRW .update(sprl) .set(sprl.SYNCED, true) .where(sprl.SYNC_POINT_ID.eq(syncPointId)) @@ -475,49 +477,49 @@ class SyncPointDao( } override fun deleteByUserId(userId: String) { - deleteSubEntities(dsl.select(sp.ID).from(sp).where(sp.USER_ID.eq(userId))) - dsl.deleteFrom(sp).where(sp.USER_ID.eq(userId)).execute() + dslRW.deleteSubEntities(dslRW.select(sp.ID).from(sp).where(sp.USER_ID.eq(userId))) + dslRW.deleteFrom(sp).where(sp.USER_ID.eq(userId)).execute() } override fun deleteByUserIdAndApiKeyIds( userId: String, apiKeyIds: Collection, ) { - deleteSubEntities(dsl.select(sp.ID).from(sp).where(sp.USER_ID.eq(userId).and(sp.API_KEY_ID.`in`(apiKeyIds)))) - dsl.deleteFrom(sp).where(sp.USER_ID.eq(userId).and(sp.API_KEY_ID.`in`(apiKeyIds))).execute() + dslRW.deleteSubEntities(dslRW.select(sp.ID).from(sp).where(sp.USER_ID.eq(userId).and(sp.API_KEY_ID.`in`(apiKeyIds)))) + dslRW.deleteFrom(sp).where(sp.USER_ID.eq(userId).and(sp.API_KEY_ID.`in`(apiKeyIds))).execute() } - private fun deleteSubEntities(condition: SelectConditionStep>) { - dsl.deleteFrom(sprls).where(sprls.SYNC_POINT_ID.`in`(condition)).execute() - dsl.deleteFrom(sprlb).where(sprlb.SYNC_POINT_ID.`in`(condition)).execute() - dsl.deleteFrom(sprl).where(sprl.SYNC_POINT_ID.`in`(condition)).execute() - dsl.deleteFrom(spbs).where(spbs.SYNC_POINT_ID.`in`(condition)).execute() - dsl.deleteFrom(spb).where(spb.SYNC_POINT_ID.`in`(condition)).execute() + private fun DSLContext.deleteSubEntities(condition: SelectConditionStep>) { + this.deleteFrom(sprls).where(sprls.SYNC_POINT_ID.`in`(condition)).execute() + this.deleteFrom(sprlb).where(sprlb.SYNC_POINT_ID.`in`(condition)).execute() + this.deleteFrom(sprl).where(sprl.SYNC_POINT_ID.`in`(condition)).execute() + this.deleteFrom(spbs).where(spbs.SYNC_POINT_ID.`in`(condition)).execute() + this.deleteFrom(spb).where(spb.SYNC_POINT_ID.`in`(condition)).execute() } override fun deleteOne(syncPointId: String) { - dsl.deleteFrom(sprls).where(sprls.SYNC_POINT_ID.eq(syncPointId)).execute() - dsl.deleteFrom(sprlb).where(sprlb.SYNC_POINT_ID.eq(syncPointId)).execute() - dsl.deleteFrom(sprl).where(sprl.SYNC_POINT_ID.eq(syncPointId)).execute() - dsl.deleteFrom(spbs).where(spbs.SYNC_POINT_ID.eq(syncPointId)).execute() - dsl.deleteFrom(spb).where(spb.SYNC_POINT_ID.eq(syncPointId)).execute() - dsl.deleteFrom(sp).where(sp.ID.eq(syncPointId)).execute() + dslRW.deleteFrom(sprls).where(sprls.SYNC_POINT_ID.eq(syncPointId)).execute() + dslRW.deleteFrom(sprlb).where(sprlb.SYNC_POINT_ID.eq(syncPointId)).execute() + dslRW.deleteFrom(sprl).where(sprl.SYNC_POINT_ID.eq(syncPointId)).execute() + dslRW.deleteFrom(spbs).where(spbs.SYNC_POINT_ID.eq(syncPointId)).execute() + dslRW.deleteFrom(spb).where(spb.SYNC_POINT_ID.eq(syncPointId)).execute() + dslRW.deleteFrom(sp).where(sp.ID.eq(syncPointId)).execute() } override fun deleteAll() { - dsl.deleteFrom(sprls).execute() - dsl.deleteFrom(sprlb).execute() - dsl.deleteFrom(sprl).execute() - dsl.deleteFrom(spbs).execute() - dsl.deleteFrom(spb).execute() - dsl.deleteFrom(sp).execute() + dslRW.deleteFrom(sprls).execute() + dslRW.deleteFrom(sprlb).execute() + dslRW.deleteFrom(sprl).execute() + dslRW.deleteFrom(spbs).execute() + dslRW.deleteFrom(spb).execute() + dslRW.deleteFrom(sp).execute() } - private fun queryToPageBook( + private fun DSLContext.queryToPageBook( query: SelectConditionStep<*>, pageable: Pageable, ): Page { - val count = dsl.fetchCount(query) + val count = this.fetchCount(query) val items = query @@ -548,11 +550,11 @@ class SyncPointDao( ) } - private fun queryToPageReadList( + private fun DSLContext.queryToPageReadList( query: SelectConditionStep<*>, pageable: Pageable, ): Page { - val count = dsl.fetchCount(query) + val count = this.fetchCount(query) val items = query diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt index 40952d31b..5be7ac358 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailBookDao.kt @@ -7,6 +7,7 @@ import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.ThumbnailBookRecord import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -14,13 +15,14 @@ import java.net.URL @Component class ThumbnailBookDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : ThumbnailBookRepository { private val tb = Tables.THUMBNAIL_BOOK override fun findAllByBookId(bookId: String): Collection = - dsl + dslRO .selectFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .fetchInto(tb) @@ -30,7 +32,7 @@ class ThumbnailBookDao( bookId: String, type: Set, ): Collection = - dsl + dslRO .selectFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .and(tb.TYPE.`in`(type.map { it.name })) @@ -38,14 +40,14 @@ class ThumbnailBookDao( .map { it.toDomain() } override fun findByIdOrNull(thumbnailId: String): ThumbnailBook? = - dsl + dslRO .selectFrom(tb) .where(tb.ID.eq(thumbnailId)) .fetchOneInto(tb) ?.toDomain() override fun findSelectedByBookIdOrNull(bookId: String): ThumbnailBook? = - dsl + dslRO .selectFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .and(tb.SELECTED.isTrue) @@ -58,7 +60,7 @@ class ThumbnailBookDao( type: ThumbnailBook.Type, size: Int, ): Collection = - dsl + dslRO .select(tb.BOOK_ID) .from(tb) .where(tb.TYPE.eq(type.toString())) @@ -66,10 +68,10 @@ class ThumbnailBookDao( .and(tb.HEIGHT.lt(size)) .fetch(tb.BOOK_ID) - override fun existsById(thumbnailId: String): Boolean = dsl.fetchExists(tb, tb.ID.eq(thumbnailId)) + override fun existsById(thumbnailId: String): Boolean = dslRO.fetchExists(tb, tb.ID.eq(thumbnailId)) override fun insert(thumbnail: ThumbnailBook) { - dsl + dslRW .insertInto(tb) .set(tb.ID, thumbnail.id) .set(tb.BOOK_ID, thumbnail.bookId) @@ -85,7 +87,7 @@ class ThumbnailBookDao( } override fun update(thumbnail: ThumbnailBook) { - dsl + dslRW .update(tb) .set(tb.BOOK_ID, thumbnail.bookId) .set(tb.THUMBNAIL, thumbnail.thumbnail) @@ -102,14 +104,14 @@ class ThumbnailBookDao( @Transactional override fun markSelected(thumbnail: ThumbnailBook) { - dsl + dslRW .update(tb) .set(tb.SELECTED, false) .where(tb.BOOK_ID.eq(thumbnail.bookId)) .and(tb.ID.ne(thumbnail.id)) .execute() - dsl + dslRW .update(tb) .set(tb.SELECTED, true) .where(tb.BOOK_ID.eq(thumbnail.bookId)) @@ -118,17 +120,17 @@ class ThumbnailBookDao( } override fun delete(thumbnailBookId: String) { - dsl.deleteFrom(tb).where(tb.ID.eq(thumbnailBookId)).execute() + dslRW.deleteFrom(tb).where(tb.ID.eq(thumbnailBookId)).execute() } override fun deleteByBookId(bookId: String) { - dsl.deleteFrom(tb).where(tb.BOOK_ID.eq(bookId)).execute() + dslRW.deleteFrom(tb).where(tb.BOOK_ID.eq(bookId)).execute() } @Transactional override fun deleteByBookIds(bookIds: Collection) { - dsl.withTempTable(batchSize, bookIds).use { - dsl.deleteFrom(tb).where(tb.BOOK_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, bookIds).use { + dslRW.deleteFrom(tb).where(tb.BOOK_ID.`in`(it.selectTempStrings())).execute() } } @@ -136,7 +138,7 @@ class ThumbnailBookDao( bookId: String, type: ThumbnailBook.Type, ) { - dsl + dslRW .deleteFrom(tb) .where(tb.BOOK_ID.eq(bookId)) .and(tb.TYPE.eq(type.toString())) diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt index a5e990b63..dfa6f63f0 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailReadListDao.kt @@ -6,31 +6,33 @@ import org.gotson.komga.domain.persistence.ThumbnailReadListRepository import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.ThumbnailReadlistRecord import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @Component class ThumbnailReadListDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : ThumbnailReadListRepository { private val tr = Tables.THUMBNAIL_READLIST override fun findAllByReadListId(readListId: String): Collection = - dsl + dslRO .selectFrom(tr) .where(tr.READLIST_ID.eq(readListId)) .fetchInto(tr) .map { it.toDomain() } override fun findByIdOrNull(thumbnailId: String): ThumbnailReadList? = - dsl + dslRO .selectFrom(tr) .where(tr.ID.eq(thumbnailId)) .fetchOneInto(tr) ?.toDomain() override fun findSelectedByReadListIdOrNull(readListId: String): ThumbnailReadList? = - dsl + dslRO .selectFrom(tr) .where(tr.READLIST_ID.eq(readListId)) .and(tr.SELECTED.isTrue) @@ -40,7 +42,7 @@ class ThumbnailReadListDao( .firstOrNull() override fun insert(thumbnail: ThumbnailReadList) { - dsl + dslRW .insertInto(tr) .set(tr.ID, thumbnail.id) .set(tr.READLIST_ID, thumbnail.readListId) @@ -55,7 +57,7 @@ class ThumbnailReadListDao( } override fun update(thumbnail: ThumbnailReadList) { - dsl + dslRW .update(tr) .set(tr.READLIST_ID, thumbnail.readListId) .set(tr.THUMBNAIL, thumbnail.thumbnail) @@ -71,14 +73,14 @@ class ThumbnailReadListDao( @Transactional override fun markSelected(thumbnail: ThumbnailReadList) { - dsl + dslRW .update(tr) .set(tr.SELECTED, false) .where(tr.READLIST_ID.eq(thumbnail.readListId)) .and(tr.ID.ne(thumbnail.id)) .execute() - dsl + dslRW .update(tr) .set(tr.SELECTED, true) .where(tr.READLIST_ID.eq(thumbnail.readListId)) @@ -87,15 +89,15 @@ class ThumbnailReadListDao( } override fun delete(thumbnailReadListId: String) { - dsl.deleteFrom(tr).where(tr.ID.eq(thumbnailReadListId)).execute() + dslRW.deleteFrom(tr).where(tr.ID.eq(thumbnailReadListId)).execute() } override fun deleteByReadListId(readListId: String) { - dsl.deleteFrom(tr).where(tr.READLIST_ID.eq(readListId)).execute() + dslRW.deleteFrom(tr).where(tr.READLIST_ID.eq(readListId)).execute() } override fun deleteByReadListIds(readListIds: Collection) { - dsl.deleteFrom(tr).where(tr.READLIST_ID.`in`(readListIds)).execute() + dslRW.deleteFrom(tr).where(tr.READLIST_ID.`in`(readListIds)).execute() } private fun ThumbnailReadlistRecord.toDomain() = diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt index b58a8023f..4218db5e0 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesCollectionDao.kt @@ -6,24 +6,26 @@ import org.gotson.komga.domain.persistence.ThumbnailSeriesCollectionRepository import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.ThumbnailCollectionRecord import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @Component class ThumbnailSeriesCollectionDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, ) : ThumbnailSeriesCollectionRepository { private val tc = Tables.THUMBNAIL_COLLECTION override fun findByIdOrNull(thumbnailId: String): ThumbnailSeriesCollection? = - dsl + dslRO .selectFrom(tc) .where(tc.ID.eq(thumbnailId)) .fetchOneInto(tc) ?.toDomain() override fun findSelectedByCollectionIdOrNull(collectionId: String): ThumbnailSeriesCollection? = - dsl + dslRO .selectFrom(tc) .where(tc.COLLECTION_ID.eq(collectionId)) .and(tc.SELECTED.isTrue) @@ -33,14 +35,14 @@ class ThumbnailSeriesCollectionDao( .firstOrNull() override fun findAllByCollectionId(collectionId: String): Collection = - dsl + dslRO .selectFrom(tc) .where(tc.COLLECTION_ID.eq(collectionId)) .fetchInto(tc) .map { it.toDomain() } override fun insert(thumbnail: ThumbnailSeriesCollection) { - dsl + dslRW .insertInto(tc) .set(tc.ID, thumbnail.id) .set(tc.COLLECTION_ID, thumbnail.collectionId) @@ -55,7 +57,7 @@ class ThumbnailSeriesCollectionDao( } override fun update(thumbnail: ThumbnailSeriesCollection) { - dsl + dslRW .update(tc) .set(tc.COLLECTION_ID, thumbnail.collectionId) .set(tc.THUMBNAIL, thumbnail.thumbnail) @@ -71,14 +73,14 @@ class ThumbnailSeriesCollectionDao( @Transactional override fun markSelected(thumbnail: ThumbnailSeriesCollection) { - dsl + dslRW .update(tc) .set(tc.SELECTED, false) .where(tc.COLLECTION_ID.eq(thumbnail.collectionId)) .and(tc.ID.ne(thumbnail.id)) .execute() - dsl + dslRW .update(tc) .set(tc.SELECTED, true) .where(tc.COLLECTION_ID.eq(thumbnail.collectionId)) @@ -87,15 +89,15 @@ class ThumbnailSeriesCollectionDao( } override fun delete(thumbnailCollectionId: String) { - dsl.deleteFrom(tc).where(tc.ID.eq(thumbnailCollectionId)).execute() + dslRW.deleteFrom(tc).where(tc.ID.eq(thumbnailCollectionId)).execute() } override fun deleteByCollectionId(collectionId: String) { - dsl.deleteFrom(tc).where(tc.COLLECTION_ID.eq(collectionId)).execute() + dslRW.deleteFrom(tc).where(tc.COLLECTION_ID.eq(collectionId)).execute() } override fun deleteByCollectionIds(collectionIds: Collection) { - dsl.deleteFrom(tc).where(tc.COLLECTION_ID.`in`(collectionIds)).execute() + dslRW.deleteFrom(tc).where(tc.COLLECTION_ID.`in`(collectionIds)).execute() } private fun ThumbnailCollectionRecord.toDomain() = diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt index f0698cb46..a125d8d1d 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/main/ThumbnailSeriesDao.kt @@ -7,6 +7,7 @@ import org.gotson.komga.infrastructure.jooq.TempTable.Companion.withTempTable import org.gotson.komga.jooq.main.Tables import org.gotson.komga.jooq.main.tables.records.ThumbnailSeriesRecord import org.jooq.DSLContext +import org.springframework.beans.factory.annotation.Qualifier import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Component import org.springframework.transaction.annotation.Transactional @@ -14,20 +15,21 @@ import java.net.URL @Component class ThumbnailSeriesDao( - private val dsl: DSLContext, + private val dslRW: DSLContext, + @Qualifier("dslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.database.batchChunkSize}") private val batchSize: Int, ) : ThumbnailSeriesRepository { private val ts = Tables.THUMBNAIL_SERIES override fun findByIdOrNull(thumbnailId: String): ThumbnailSeries? = - dsl + dslRO .selectFrom(ts) .where(ts.ID.eq(thumbnailId)) .fetchOneInto(ts) ?.toDomain() override fun findAllBySeriesId(seriesId: String): Collection = - dsl + dslRO .selectFrom(ts) .where(ts.SERIES_ID.eq(seriesId)) .fetchInto(ts) @@ -37,7 +39,7 @@ class ThumbnailSeriesDao( seriesId: String, type: ThumbnailSeries.Type, ): Collection = - dsl + dslRO .selectFrom(ts) .where(ts.SERIES_ID.eq(seriesId)) .and(ts.TYPE.eq(type.toString())) @@ -45,7 +47,7 @@ class ThumbnailSeriesDao( .map { it.toDomain() } override fun findSelectedBySeriesIdOrNull(seriesId: String): ThumbnailSeries? = - dsl + dslRO .selectFrom(ts) .where(ts.SERIES_ID.eq(seriesId)) .and(ts.SELECTED.isTrue) @@ -55,7 +57,7 @@ class ThumbnailSeriesDao( .firstOrNull() override fun insert(thumbnail: ThumbnailSeries) { - dsl + dslRW .insertInto(ts) .set(ts.ID, thumbnail.id) .set(ts.SERIES_ID, thumbnail.seriesId) @@ -71,7 +73,7 @@ class ThumbnailSeriesDao( } override fun update(thumbnail: ThumbnailSeries) { - dsl + dslRW .update(ts) .set(ts.SERIES_ID, thumbnail.seriesId) .set(ts.THUMBNAIL, thumbnail.thumbnail) @@ -88,14 +90,14 @@ class ThumbnailSeriesDao( @Transactional override fun markSelected(thumbnail: ThumbnailSeries) { - dsl + dslRW .update(ts) .set(ts.SELECTED, false) .where(ts.SERIES_ID.eq(thumbnail.seriesId)) .and(ts.ID.ne(thumbnail.id)) .execute() - dsl + dslRW .update(ts) .set(ts.SELECTED, true) .where(ts.SERIES_ID.eq(thumbnail.seriesId)) @@ -104,17 +106,17 @@ class ThumbnailSeriesDao( } override fun delete(thumbnailSeriesId: String) { - dsl.deleteFrom(ts).where(ts.ID.eq(thumbnailSeriesId)).execute() + dslRW.deleteFrom(ts).where(ts.ID.eq(thumbnailSeriesId)).execute() } override fun deleteBySeriesId(seriesId: String) { - dsl.deleteFrom(ts).where(ts.SERIES_ID.eq(seriesId)).execute() + dslRW.deleteFrom(ts).where(ts.SERIES_ID.eq(seriesId)).execute() } @Transactional override fun deleteBySeriesIds(seriesIds: Collection) { - dsl.withTempTable(batchSize, seriesIds).use { - dsl.deleteFrom(ts).where(ts.SERIES_ID.`in`(it.selectTempStrings())).execute() + dslRW.withTempTable(batchSize, seriesIds).use { + dslRW.deleteFrom(ts).where(ts.SERIES_ID.`in`(it.selectTempStrings())).execute() } } diff --git a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt index 3740db8fe..312034845 100644 --- a/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt +++ b/komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/tasks/TasksDao.kt @@ -22,8 +22,8 @@ private val logger = KotlinLogging.logger {} @Component @DependsOn("flywaySecondaryMigrationInitializer") class TasksDao( - @Qualifier("tasksDslContext") - private val dsl: DSLContext, + @Qualifier("tasksDslContextRW") private val dslRW: DSLContext, + @Qualifier("tasksDslContextRO") private val dslRO: DSLContext, @param:Value("#{@komgaProperties.tasksDb.batchChunkSize}") private val batchSize: Int, private val objectMapper: ObjectMapper, ) : TasksRepository { @@ -34,7 +34,7 @@ class TasksDao( .and( t.GROUP_ID .notIn( - dsl + DSL .select(t.GROUP_ID) .from(t) .where(t.OWNER.isNotNull) @@ -43,7 +43,7 @@ class TasksDao( ) override fun hasAvailable(): Boolean = - dsl.fetchExists( + dslRO.fetchExists( t, tasksAvailableCondition, ) @@ -51,7 +51,8 @@ class TasksDao( @Transactional override fun takeFirst(owner: String): Task? { val task = - selectBase() + dslRW + .selectBase() .where(tasksAvailableCondition) .orderBy(t.PRIORITY.desc(), t.LAST_MODIFIED_DATE) .limit(1) @@ -65,7 +66,7 @@ class TasksDao( } } ?: return null - dsl + dslRW .update(t) .set(t.OWNER, owner) .where(t.ID.eq(task.uniqueId)) @@ -75,12 +76,13 @@ class TasksDao( } override fun findAll(): List = - selectBase() + dslRO + .selectBase() .fetch() .mapNotNull { it.toDomain() } override fun findAllGroupedByOwner(): Map> = - dsl + dslRO .select(t.OWNER, t.CLASS, t.PAYLOAD) .from(t) .fetch() @@ -88,8 +90,8 @@ class TasksDao( it.into(t.CLASS, t.PAYLOAD).toDomain()?.let { task -> it.value1() to task } }.groupBy({ it.first }, { it.second }) - private fun selectBase() = - dsl + private fun DSLContext.selectBase() = + this .select(t.CLASS, t.PAYLOAD) .from(t) @@ -101,10 +103,10 @@ class TasksDao( null } - override fun count(): Int = dsl.fetchCount(t) + override fun count(): Int = dslRO.fetchCount(t) override fun countBySimpleType(): Map = - dsl + dslRO .select(t.SIMPLE_TYPE, DSL.count(t.SIMPLE_TYPE)) .from(t) .groupBy(t.SIMPLE_TYPE) @@ -112,34 +114,34 @@ class TasksDao( .associate { it.value1() to it.value2() } override fun save(task: Task) { - task.toQuery().execute() + task.toQuery(dslRW).execute() } override fun save(tasks: Collection) { tasks - .map { it.toQuery() } + .map { it.toQuery(dslRW) } .chunked(batchSize) - .forEach { chunk -> dsl.batch(chunk).execute() } + .forEach { chunk -> dslRW.batch(chunk).execute() } } override fun disown(): Int = - dsl + dslRW .update(t) .set(t.OWNER, null as String?) .where(t.OWNER.isNotNull) .execute() override fun delete(taskId: String) { - dsl.deleteFrom(t).where(t.ID.eq(taskId)).execute() + dslRW.deleteFrom(t).where(t.ID.eq(taskId)).execute() } override fun deleteAll() { - dsl.deleteFrom(t).execute() + dslRW.deleteFrom(t).execute() } - override fun deleteAllWithoutOwner(): Int = dsl.deleteFrom(t).where(t.OWNER.isNull).execute() + override fun deleteAllWithoutOwner(): Int = dslRW.deleteFrom(t).where(t.OWNER.isNull).execute() - private fun Task.toQuery(): Query = + private fun Task.toQuery(dsl: DSLContext): Query = dsl .insertInto( t, diff --git a/komga/src/test/kotlin/org/gotson/komga/AutowiringTest.kt b/komga/src/test/kotlin/org/gotson/komga/AutowiringTest.kt index a9483a94f..e888ec3d1 100644 --- a/komga/src/test/kotlin/org/gotson/komga/AutowiringTest.kt +++ b/komga/src/test/kotlin/org/gotson/komga/AutowiringTest.kt @@ -16,8 +16,8 @@ class AutowiringTest( fun `Application loads properly with test properties`() = Unit @Test - fun `Application has 2 dsl contexts`() { - assertThat(dataSources).hasSize(2) - assertThat(dslContexts).hasSize(2) + fun `Application has 4 dsl contexts`() { + assertThat(dataSources).hasSize(4) + assertThat(dslContexts).hasSize(4) } } diff --git a/komga/src/test/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfigurationTest.kt b/komga/src/test/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfigurationTest.kt new file mode 100644 index 000000000..c57ee044e --- /dev/null +++ b/komga/src/test/kotlin/org/gotson/komga/infrastructure/datasource/DataSourcesConfigurationTest.kt @@ -0,0 +1,43 @@ +package org.gotson.komga.infrastructure.datasource + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Nested +import org.junit.jupiter.api.Test +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Qualifier +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ActiveProfiles +import javax.sql.DataSource + +class DataSourcesConfigurationTest { + @SpringBootTest + @ActiveProfiles("test", "waltest") + @Nested + inner class WalMode( + @Autowired private val dataSourceRW: DataSource, + @Autowired @Qualifier("sqliteDataSourceRO") private val dataSourceRO: DataSource, + @Autowired @Qualifier("tasksDataSourceRW") private val tasksDataSourceRW: DataSource, + @Autowired @Qualifier("tasksDataSourceRO") private val tasksDataSourceRO: DataSource, + ) { + @Test + fun `given wal mode when autoriwiring beans then bean instances are different between RW and RO`() { + assertThat(dataSourceRW).isNotSameAs(dataSourceRO) + assertThat(tasksDataSourceRW).isNotSameAs(tasksDataSourceRO) + } + } + + @SpringBootTest + @Nested + inner class MemoryMode( + @Autowired private val dataSourceRW: DataSource, + @Autowired @Qualifier("sqliteDataSourceRO") private val dataSourceRO: DataSource, + @Autowired @Qualifier("tasksDataSourceRW") private val tasksDataSourceRW: DataSource, + @Autowired @Qualifier("tasksDataSourceRO") private val tasksDataSourceRO: DataSource, + ) { + @Test + fun `given wal mode when autoriwiring beans then bean instances are the same between RW and RO`() { + assertThat(dataSourceRW).isSameAs(dataSourceRO) + assertThat(tasksDataSourceRW).isSameAs(tasksDataSourceRO) + } + } +} diff --git a/komga/src/test/resources/application-waltest.yml b/komga/src/test/resources/application-waltest.yml new file mode 100644 index 000000000..f3e94e759 --- /dev/null +++ b/komga/src/test/resources/application-waltest.yml @@ -0,0 +1,7 @@ +komga: + database: + file: "\${java.io.tmpdir}/database.sqlite" + journal-mode: WAL + tasks-db: + file: "\${java.io.tmpdir}/tasks.sqlite" + journal-mode: WAL