mirror of
https://github.com/gotson/komga.git
synced 2025-12-15 21:12:27 +01:00
perf: separate database reads from writes
this is only used when the database is in WAL mode
This commit is contained in:
parent
7464e64687
commit
f9d9139bb2
37 changed files with 875 additions and 735 deletions
|
|
@ -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<out SQLiteDataSource>,
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<TransactionProvider?>,
|
||||
executeListenerProviders: ObjectProvider<ExecuteListenerProvider?>,
|
||||
): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders)
|
||||
|
||||
@Bean("tasksDslContext")
|
||||
fun tasksDslContext(
|
||||
@Qualifier("tasksDataSource") dataSource: DataSource,
|
||||
@Bean("dslContextRO")
|
||||
fun mainDslContextRO(
|
||||
@Qualifier("sqliteDataSourceRO") dataSource: DataSource,
|
||||
transactionProvider: ObjectProvider<TransactionProvider?>,
|
||||
executeListenerProviders: ObjectProvider<ExecuteListenerProvider?>,
|
||||
): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders)
|
||||
|
||||
@Bean("tasksDslContextRW")
|
||||
fun tasksDslContextRW(
|
||||
@Qualifier("tasksDataSourceRW") dataSource: DataSource,
|
||||
transactionProvider: ObjectProvider<TransactionProvider?>,
|
||||
executeListenerProviders: ObjectProvider<ExecuteListenerProvider?>,
|
||||
): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders)
|
||||
|
||||
@Bean("tasksDslContextRO")
|
||||
fun tasksDslContextRO(
|
||||
@Qualifier("tasksDataSourceRO") dataSource: DataSource,
|
||||
transactionProvider: ObjectProvider<TransactionProvider?>,
|
||||
executeListenerProviders: ObjectProvider<ExecuteListenerProvider?>,
|
||||
): DSLContext = createDslContext(dataSource, transactionProvider, executeListenerProviders)
|
||||
|
|
|
|||
|
|
@ -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<AuthenticationActivity> {
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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<Book> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(b)
|
||||
.where(b.SERIES_ID.eq(seriesId))
|
||||
.fetchInto(b)
|
||||
|
|
@ -80,8 +76,8 @@ class BookDao(
|
|||
|
||||
@Transactional
|
||||
override fun findAllBySeriesIds(seriesIds: Collection<String>): Collection<Book> {
|
||||
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<URL>,
|
||||
): Collection<Book> {
|
||||
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<Book> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(b)
|
||||
.where(b.DELETED_DATE.isNotNull.and(b.FILE_SIZE.eq(fileSize)))
|
||||
.fetchInto(b)
|
||||
.map { it.toDomain() }
|
||||
|
||||
override fun findAll(): Collection<Book> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(b)
|
||||
.fetchInto(b)
|
||||
.map { it.toDomain() }
|
||||
|
|
@ -125,20 +121,13 @@ class BookDao(
|
|||
pageable: Pageable,
|
||||
): Page<Book> {
|
||||
val bookCondition = BookSearchHelper(searchContext).toCondition(searchCondition)
|
||||
return findAll(bookCondition.first, bookCondition.second, pageable)
|
||||
}
|
||||
|
||||
private fun findAll(
|
||||
conditions: Condition,
|
||||
joins: Set<RequiredJoin>,
|
||||
pageable: Pageable,
|
||||
): PageImpl<Book> {
|
||||
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<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(b.ID)
|
||||
.from(b)
|
||||
.where(b.SERIES_ID.eq(seriesId))
|
||||
.fetch(b.ID)
|
||||
|
||||
override fun findAllIdsByLibraryId(libraryId: String): Collection<String> =
|
||||
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<String>,
|
||||
): Collection<Book> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(*b.fields())
|
||||
.from(b)
|
||||
.leftJoin(m)
|
||||
|
|
@ -284,7 +273,7 @@ class BookDao(
|
|||
mediaType: String,
|
||||
extension: String,
|
||||
): Collection<Book> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(*b.fields())
|
||||
.from(b)
|
||||
.leftJoin(m)
|
||||
|
|
@ -296,7 +285,7 @@ class BookDao(
|
|||
.map { it.toDomain() }
|
||||
|
||||
override fun findAllByLibraryIdAndWithEmptyHash(libraryId: String): Collection<Book> =
|
||||
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<Book> =
|
||||
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<Book> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(b)
|
||||
.where(b.FILE_HASH_KOREADER.eq(hashKoreader))
|
||||
.fetchInto(b)
|
||||
|
|
@ -327,9 +316,9 @@ class BookDao(
|
|||
override fun insert(books: Collection<Book>) {
|
||||
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<String>) {
|
||||
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<String, Int> =
|
||||
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<String, BigDecimal> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(b.LIBRARY_ID, DSL.sum(b.FILE_SIZE))
|
||||
.from(b)
|
||||
.groupBy(b.LIBRARY_ID)
|
||||
|
|
|
|||
|
|
@ -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<BookDto> {
|
||||
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<BookDto> {
|
||||
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<RequiredJoin> = emptySet(),
|
||||
): SelectOnConditionStep<Record> {
|
||||
|
|
@ -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<Record>.fetchAndMap(): MutableList<BookDto> {
|
||||
private fun ResultQuery<Record>.fetchAndMap(dsl: DSLContext): MutableList<BookDto> {
|
||||
val records = fetch()
|
||||
val bookIds = records.getValues(b.ID)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String>) =
|
||||
dsl
|
||||
private fun DSLContext.findOne(seriesIds: Collection<String>) =
|
||||
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<String>) {
|
||||
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<Author>,
|
||||
|
|
|
|||
|
|
@ -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<String>): Collection<BookMetadata> = find(dsl, bookIds)
|
||||
override fun findAllByIds(bookIds: Collection<String>): Collection<BookMetadata> = dslRO.find(bookIds)
|
||||
|
||||
private fun find(
|
||||
dsl: DSLContext,
|
||||
private fun DSLContext.find(
|
||||
bookIds: Collection<String>,
|
||||
) = 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<BookMetadata>) {
|
||||
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<BookMetadata>) {
|
||||
private fun DSLContext.insertAuthors(metadatas: Collection<BookMetadata>) {
|
||||
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<BookMetadata>) {
|
||||
private fun DSLContext.insertTags(metadatas: Collection<BookMetadata>) {
|
||||
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<BookMetadata>) {
|
||||
private fun DSLContext.insertLinks(metadatas: Collection<BookMetadata>) {
|
||||
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<String>) {
|
||||
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<Author>,
|
||||
|
|
|
|||
|
|
@ -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<String, ClientSettingDto> =
|
||||
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<String, ClientSettingDto> =
|
||||
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<String>) {
|
||||
dsl
|
||||
dslRW
|
||||
.deleteFrom(g)
|
||||
.where(g.KEY.`in`(keys))
|
||||
.execute()
|
||||
|
|
@ -68,7 +70,7 @@ class ClientSettingsDtoDao(
|
|||
userId: String,
|
||||
keys: Collection<String>,
|
||||
) {
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -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 ->
|
||||
|
|
|
|||
|
|
@ -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<HistoricalEventDto> {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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<String>,
|
||||
): Collection<KoboBookMetadataDto> {
|
||||
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 }
|
||||
|
|
|
|||
|
|
@ -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<KomgaUser> =
|
||||
selectBase()
|
||||
.fetchAndMap()
|
||||
dslRO
|
||||
.selectBase()
|
||||
.fetchAndMap(dslRO)
|
||||
|
||||
override fun findApiKeyByUserId(userId: String): Collection<ApiKey> =
|
||||
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<Record>.fetchAndMap() =
|
||||
private fun ResultQuery<Record>.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<String>,
|
||||
) {
|
||||
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<String> =
|
||||
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<KomgaUser, ApiKey>? {
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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<Library> =
|
||||
selectBase()
|
||||
dslRO
|
||||
.selectBase()
|
||||
.fetchAndMap()
|
||||
|
||||
override fun findAllByIds(libraryIds: Collection<String>): Collection<Library> =
|
||||
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 ->
|
||||
|
|
|
|||
|
|
@ -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<String>): Collection<Pair<String, Int>> =
|
||||
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<Media>) {
|
||||
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<Media>) {
|
||||
private fun DSLContext.insertPages(medias: Collection<Media>) {
|
||||
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<Media>) {
|
||||
private fun DSLContext.insertFiles(medias: Collection<Media>) {
|
||||
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<String>) {
|
||||
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<BookPage>,
|
||||
|
|
|
|||
|
|
@ -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<PageHashKnown> {
|
||||
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<PageHashUnknown> {
|
||||
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<PageHashMatch> {
|
||||
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<PageHashKnown.Action>?,
|
||||
libraryId: String?,
|
||||
): Map<String, Collection<BookPageNumbered>> =
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -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<String>?,
|
||||
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<ReadList> {
|
||||
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<ReadList> =
|
||||
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<Record>.fetchAndMap(
|
||||
dsl: DSLContext,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
restrictions: ContentRestrictions = ContentRestrictions(),
|
||||
): List<ReadList> =
|
||||
|
|
@ -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<String>) {
|
||||
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<String>) {
|
||||
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<Int, String>) =
|
||||
ReadList(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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<ReadProgress> =
|
||||
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<ReadProgress> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(r)
|
||||
.where(r.USER_ID.eq(userId))
|
||||
.fetchInto(r)
|
||||
.map { it.toDomain() }
|
||||
|
||||
override fun findAllByBookId(bookId: String): Collection<ReadProgress> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(r)
|
||||
.where(r.BOOK_ID.eq(bookId))
|
||||
.fetchInto(r)
|
||||
|
|
@ -65,7 +67,7 @@ class ReadProgressDao(
|
|||
bookIds: Collection<String>,
|
||||
userId: String,
|
||||
): Collection<ReadProgress> =
|
||||
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<ReadProgress>) {
|
||||
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<String>) {
|
||||
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<String>) {
|
||||
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<String>,
|
||||
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<String>,
|
||||
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)))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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<String>?,
|
||||
): List<Author> =
|
||||
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<String>?,
|
||||
): List<Author> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(bmaa.NAME, bmaa.ROLE)
|
||||
.from(bmaa)
|
||||
.leftJoin(s)
|
||||
|
|
@ -73,7 +74,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): List<Author> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(bmaa.NAME, bmaa.ROLE)
|
||||
.from(bmaa)
|
||||
.leftJoin(cs)
|
||||
|
|
@ -91,7 +92,7 @@ class ReferentialDao(
|
|||
seriesId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): List<Author> =
|
||||
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<Author> {
|
||||
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<String>?,
|
||||
): List<String> =
|
||||
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<String>?): List<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(a.ROLE)
|
||||
.from(a)
|
||||
.apply {
|
||||
|
|
@ -235,7 +236,7 @@ class ReferentialDao(
|
|||
.fetch(a.ROLE)
|
||||
|
||||
override fun findAllGenres(filterOnLibraryIds: Collection<String>?): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(g.GENRE)
|
||||
.from(g)
|
||||
.apply {
|
||||
|
|
@ -251,7 +252,7 @@ class ReferentialDao(
|
|||
libraryIds: Set<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(g.GENRE)
|
||||
.from(g)
|
||||
.leftJoin(s)
|
||||
|
|
@ -265,7 +266,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(g.GENRE)
|
||||
.from(g)
|
||||
.leftJoin(cs)
|
||||
|
|
@ -277,7 +278,7 @@ class ReferentialDao(
|
|||
.fetchSet(g.GENRE)
|
||||
|
||||
override fun findAllSeriesAndBookTags(filterOnLibraryIds: Collection<String>?): Set<String> =
|
||||
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<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(bt.TAG.`as`("tag"))
|
||||
.from(bt)
|
||||
.leftJoin(b)
|
||||
|
|
@ -315,7 +316,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(bmat.TAG.`as`("tag"))
|
||||
.from(bmat)
|
||||
.leftJoin(s)
|
||||
|
|
@ -338,7 +339,7 @@ class ReferentialDao(
|
|||
.toSet()
|
||||
|
||||
override fun findAllSeriesTags(filterOnLibraryIds: Collection<String>?): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(st.TAG)
|
||||
.from(st)
|
||||
.apply {
|
||||
|
|
@ -354,7 +355,7 @@ class ReferentialDao(
|
|||
libraryId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(st.TAG)
|
||||
.from(st)
|
||||
.leftJoin(s)
|
||||
|
|
@ -368,7 +369,7 @@ class ReferentialDao(
|
|||
seriesId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(bt.TAG)
|
||||
.from(bt)
|
||||
.leftJoin(b)
|
||||
|
|
@ -382,7 +383,7 @@ class ReferentialDao(
|
|||
readListId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(bt.TAG)
|
||||
.from(bt)
|
||||
.leftJoin(b)
|
||||
|
|
@ -398,7 +399,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(st.TAG)
|
||||
.from(st)
|
||||
.leftJoin(cs)
|
||||
|
|
@ -410,7 +411,7 @@ class ReferentialDao(
|
|||
.fetchSet(st.TAG)
|
||||
|
||||
override fun findAllBookTags(filterOnLibraryIds: Collection<String>?): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(bt.TAG)
|
||||
.from(bt)
|
||||
.apply {
|
||||
|
|
@ -423,7 +424,7 @@ class ReferentialDao(
|
|||
.fetchSet(bt.TAG)
|
||||
|
||||
override fun findAllLanguages(filterOnLibraryIds: Collection<String>?): Set<String> =
|
||||
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<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sd.LANGUAGE)
|
||||
.from(sd)
|
||||
.leftJoin(s)
|
||||
|
|
@ -451,7 +452,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sd.LANGUAGE)
|
||||
.from(sd)
|
||||
.leftJoin(cs)
|
||||
|
|
@ -464,7 +465,7 @@ class ReferentialDao(
|
|||
.fetchSet(sd.LANGUAGE)
|
||||
|
||||
override fun findAllPublishers(filterOnLibraryIds: Collection<String>?): Set<String> =
|
||||
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<String> {
|
||||
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<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sd.PUBLISHER)
|
||||
.from(sd)
|
||||
.leftJoin(s)
|
||||
|
|
@ -524,7 +525,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sd.PUBLISHER)
|
||||
.from(sd)
|
||||
.leftJoin(cs)
|
||||
|
|
@ -537,7 +538,7 @@ class ReferentialDao(
|
|||
.fetchSet(sd.PUBLISHER)
|
||||
|
||||
override fun findAllAgeRatings(filterOnLibraryIds: Collection<String>?): Set<Int?> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sd.AGE_RATING)
|
||||
.from(sd)
|
||||
.apply {
|
||||
|
|
@ -553,7 +554,7 @@ class ReferentialDao(
|
|||
libraryIds: Set<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<Int?> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sd.AGE_RATING)
|
||||
.from(sd)
|
||||
.leftJoin(s)
|
||||
|
|
@ -567,7 +568,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<Int?> =
|
||||
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<String>?): Set<LocalDate> =
|
||||
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<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<LocalDate> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(bma.RELEASE_DATE)
|
||||
.from(bma)
|
||||
.leftJoin(s)
|
||||
|
|
@ -607,7 +608,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<LocalDate> =
|
||||
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<String>?): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sl.LABEL)
|
||||
.from(sl)
|
||||
.apply {
|
||||
|
|
@ -636,7 +637,7 @@ class ReferentialDao(
|
|||
libraryIds: Set<String>,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sl.LABEL)
|
||||
.from(sl)
|
||||
.leftJoin(s)
|
||||
|
|
@ -650,7 +651,7 @@ class ReferentialDao(
|
|||
collectionId: String,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
): Set<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectDistinct(sl.LABEL)
|
||||
.from(sl)
|
||||
.leftJoin(cs)
|
||||
|
|
|
|||
|
|
@ -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<String>?,
|
||||
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<SeriesCollection> {
|
||||
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<SeriesCollection> =
|
||||
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<Record>.fetchAndMap(
|
||||
dsl: DSLContext,
|
||||
filterOnLibraryIds: Collection<String>?,
|
||||
restrictions: ContentRestrictions = ContentRestrictions(),
|
||||
): List<SeriesCollection> =
|
||||
|
|
@ -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<String>) {
|
||||
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<String>) {
|
||||
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<String>) =
|
||||
SeriesCollection(
|
||||
|
|
|
|||
|
|
@ -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<Series> =
|
||||
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<Series> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(s)
|
||||
.where(s.LIBRARY_ID.eq(libraryId))
|
||||
.fetchInto(s)
|
||||
|
|
@ -61,8 +62,8 @@ class SeriesDao(
|
|||
libraryId: String,
|
||||
urls: Collection<URL>,
|
||||
): List<Series> {
|
||||
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<Series> =
|
||||
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<String> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(s.ID)
|
||||
.from(s)
|
||||
.where(s.LIBRARY_ID.eq(libraryId))
|
||||
|
|
@ -115,16 +116,9 @@ class SeriesDao(
|
|||
pageable: Pageable,
|
||||
): Page<Series> {
|
||||
val (conditions, joins) = SeriesSearchHelper(searchContext).toCondition(searchCondition)
|
||||
return findAll(conditions, joins, pageable)
|
||||
}
|
||||
|
||||
private fun findAll(
|
||||
conditions: Condition,
|
||||
joins: Set<RequiredJoin>,
|
||||
pageable: Pageable,
|
||||
): Page<Series> {
|
||||
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<String>) {
|
||||
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<String, Int> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(s.LIBRARY_ID, DSL.count(s.ID))
|
||||
.from(s)
|
||||
.groupBy(s.LIBRARY_ID)
|
||||
|
|
|
|||
|
|
@ -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<RequiredJoin> = emptySet(),
|
||||
joinOnCollection: Boolean = false,
|
||||
): SelectOnConditionStep<Record> =
|
||||
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<Record>.fetchAndMap(): MutableList<SeriesDto> {
|
||||
private fun ResultQuery<Record>.fetchAndMap(dsl: DSLContext): MutableList<SeriesDto> {
|
||||
val records = fetch()
|
||||
val seriesIds = records.getValues(s.ID)
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String>) {
|
||||
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<String>,
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
): 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()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<SidecarStored> = dsl.selectFrom(sc).fetch().map { it.toDomain() }
|
||||
override fun findAll(): Collection<SidecarStored> = 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<URL>,
|
||||
) {
|
||||
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<String, Int> =
|
||||
dsl
|
||||
dslRO
|
||||
.select(sc.LIBRARY_ID, DSL.count(sc.URL))
|
||||
.from(sc)
|
||||
.groupBy(sc.LIBRARY_ID)
|
||||
|
|
|
|||
|
|
@ -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<SyncPoint.Book> {
|
||||
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<SyncPoint.Book> {
|
||||
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<SyncPoint.Book> {
|
||||
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<SyncPoint.Book> {
|
||||
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<SyncPoint.Book> {
|
||||
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<SyncPoint.ReadList> {
|
||||
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<SyncPoint.ReadList> {
|
||||
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<String>,
|
||||
): List<SyncPoint.ReadList.Book> =
|
||||
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<String>,
|
||||
) {
|
||||
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<Record1<String>>) {
|
||||
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<Record1<String>>) {
|
||||
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<SyncPoint.Book> {
|
||||
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<SyncPoint.ReadList> {
|
||||
val count = dsl.fetchCount(query)
|
||||
val count = this.fetchCount(query)
|
||||
|
||||
val items =
|
||||
query
|
||||
|
|
|
|||
|
|
@ -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<ThumbnailBook> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(tb)
|
||||
.where(tb.BOOK_ID.eq(bookId))
|
||||
.fetchInto(tb)
|
||||
|
|
@ -30,7 +32,7 @@ class ThumbnailBookDao(
|
|||
bookId: String,
|
||||
type: Set<ThumbnailBook.Type>,
|
||||
): Collection<ThumbnailBook> =
|
||||
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<String> =
|
||||
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<String>) {
|
||||
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()))
|
||||
|
|
|
|||
|
|
@ -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<ThumbnailReadList> =
|
||||
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<String>) {
|
||||
dsl.deleteFrom(tr).where(tr.READLIST_ID.`in`(readListIds)).execute()
|
||||
dslRW.deleteFrom(tr).where(tr.READLIST_ID.`in`(readListIds)).execute()
|
||||
}
|
||||
|
||||
private fun ThumbnailReadlistRecord.toDomain() =
|
||||
|
|
|
|||
|
|
@ -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<ThumbnailSeriesCollection> =
|
||||
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<String>) {
|
||||
dsl.deleteFrom(tc).where(tc.COLLECTION_ID.`in`(collectionIds)).execute()
|
||||
dslRW.deleteFrom(tc).where(tc.COLLECTION_ID.`in`(collectionIds)).execute()
|
||||
}
|
||||
|
||||
private fun ThumbnailCollectionRecord.toDomain() =
|
||||
|
|
|
|||
|
|
@ -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<ThumbnailSeries> =
|
||||
dsl
|
||||
dslRO
|
||||
.selectFrom(ts)
|
||||
.where(ts.SERIES_ID.eq(seriesId))
|
||||
.fetchInto(ts)
|
||||
|
|
@ -37,7 +39,7 @@ class ThumbnailSeriesDao(
|
|||
seriesId: String,
|
||||
type: ThumbnailSeries.Type,
|
||||
): Collection<ThumbnailSeries> =
|
||||
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<String>) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<Task> =
|
||||
selectBase()
|
||||
dslRO
|
||||
.selectBase()
|
||||
.fetch()
|
||||
.mapNotNull { it.toDomain() }
|
||||
|
||||
override fun findAllGroupedByOwner(): Map<String?, List<Task>> =
|
||||
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<String, Int> =
|
||||
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<Task>) {
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
7
komga/src/test/resources/application-waltest.yml
Normal file
7
komga/src/test/resources/application-waltest.yml
Normal file
|
|
@ -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
|
||||
Loading…
Reference in a new issue