fix: scan could fail with latest sqlite library

statement would be too long to execute

closes #644
This commit is contained in:
Gauthier Roebroeck 2021-08-31 11:56:56 +08:00
parent 4e23d1a6bb
commit f8cd7dfcf7
7 changed files with 49 additions and 12 deletions

View file

@ -0,0 +1,4 @@
CREATE TABLE TEMP_URL_LIST
(
URL varchar NOT NULL
);

View file

@ -14,7 +14,7 @@ interface BookRepository {
fun findAll(): Collection<Book>
fun findAllBySeriesId(seriesId: String): Collection<Book>
fun findAllBySeriesIds(seriesIds: Collection<String>): Collection<Book>
fun findAllByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): Collection<Book>
fun findAllNotDeletedByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): Collection<Book>
fun findAll(bookSearch: BookSearch): Collection<Book>
fun findAll(bookSearch: BookSearch, pageable: Pageable): Page<Book>
fun findAllDeletedByFileSize(fileSize: Long): Collection<Book>

View file

@ -10,7 +10,7 @@ interface SeriesRepository {
fun findAll(): Collection<Series>
fun findAllByLibraryId(libraryId: String): Collection<Series>
fun findAllByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): Collection<Series>
fun findAllNotDeletedByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): Collection<Series>
fun findAllByTitle(title: String): Collection<Series>
fun findAll(search: SeriesSearch): Collection<Series>

View file

@ -96,7 +96,7 @@ class LibraryContentLifecycle(
seriesLifecycle.softDeleteMany(series)
} else {
scannedSeries.keys.map { it.url }.let { urls ->
val series = seriesRepository.findAllByLibraryIdAndUrlNotIn(library.id, urls).filterNot { it.deletedDate != null }
val series = seriesRepository.findAllNotDeletedByLibraryIdAndUrlNotIn(library.id, urls)
if (series.isNotEmpty()) {
logger.info { "Soft deleting series not on disk anymore: $series" }
seriesLifecycle.softDeleteMany(series)
@ -106,7 +106,7 @@ class LibraryContentLifecycle(
// delete books that don't exist anymore. We need to do this now, so trash bin can work
val seriesToSortAndRefresh = scannedSeries.values.flatten().map { it.url }.let { urls ->
val books = bookRepository.findAllByLibraryIdAndUrlNotIn(library.id, urls).filterNot { it.deletedDate != null }
val books = bookRepository.findAllNotDeletedByLibraryIdAndUrlNotIn(library.id, urls)
if (books.isNotEmpty()) {
logger.info { "Soft deleting books not on disk anymore: $books" }
bookLifecycle.softDeleteMany(books)

View file

@ -28,6 +28,7 @@ class BookDao(
private val m = Tables.MEDIA
private val d = Tables.BOOK_METADATA
private val r = Tables.READ_PROGRESS
private val u = Tables.TEMP_URL_LIST
private val sorts = mapOf(
"createdDate" to b.CREATED_DATE,
@ -62,11 +63,26 @@ class BookDao(
.fetchInto(b)
.map { it.toDomain() }
override fun findAllByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): Collection<Book> =
dsl.selectFrom(b)
.where(b.LIBRARY_ID.eq(libraryId).and(b.URL.notIn(urls.map { it.toString() })))
@Transactional
override fun findAllNotDeletedByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): Collection<Book> {
// insert urls in a temporary table, else the select size can exceed the statement limit
dsl.deleteFrom(u).execute()
dsl.batch(
dsl.insertInto(u, u.URL).values(null as String?)
).also { step ->
urls.forEach {
step.bind(it.toString())
}
}.execute()
return dsl.selectFrom(b)
.where(b.LIBRARY_ID.eq(libraryId))
.and(b.DELETED_DATE.isNull)
.and(b.URL.notIn(dsl.selectFrom(u)))
.fetchInto(b)
.map { it.toDomain() }
}
override fun findAllDeletedByFileSize(fileSize: Long): Collection<Book> =
dsl.selectFrom(b)

View file

@ -9,6 +9,7 @@ import org.jooq.Condition
import org.jooq.DSLContext
import org.jooq.impl.DSL
import org.springframework.stereotype.Component
import org.springframework.transaction.annotation.Transactional
import java.net.URL
import java.time.LocalDateTime
import java.time.ZoneId
@ -21,6 +22,7 @@ class SeriesDao(
private val s = Tables.SERIES
private val d = Tables.SERIES_METADATA
private val cs = Tables.COLLECTION_SERIES
private val u = Tables.TEMP_URL_LIST
override fun findAll(): Collection<Series> =
dsl.selectFrom(s)
@ -39,11 +41,26 @@ class SeriesDao(
.fetchInto(s)
.map { it.toDomain() }
override fun findAllByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): List<Series> =
dsl.selectFrom(s)
.where(s.LIBRARY_ID.eq(libraryId).and(s.URL.notIn(urls.map { it.toString() })))
@Transactional
override fun findAllNotDeletedByLibraryIdAndUrlNotIn(libraryId: String, urls: Collection<URL>): List<Series> {
// insert urls in a temporary table, else the select size can exceed the statement limit
dsl.deleteFrom(u).execute()
dsl.batch(
dsl.insertInto(u, u.URL).values(null as String?)
).also { step ->
urls.forEach {
step.bind(it.toString())
}
}.execute()
return dsl.selectFrom(s)
.where(s.LIBRARY_ID.eq(libraryId))
.and(s.DELETED_DATE.isNull)
.and(s.URL.notIn(dsl.selectFrom(u)))
.fetchInto(s)
.map { it.toDomain() }
}
override fun findByLibraryIdAndUrlOrNull(libraryId: String, url: URL): Series? =
dsl.selectFrom(s)

View file

@ -269,8 +269,8 @@ class SeriesDaoTest(
)
seriesDao.insert(series)
val found = seriesDao.findAllByLibraryIdAndUrlNotIn(library.id, listOf(URL("file://series2")))
val notFound = seriesDao.findAllByLibraryIdAndUrlNotIn(library.id, listOf(URL("file://series")))
val found = seriesDao.findAllNotDeletedByLibraryIdAndUrlNotIn(library.id, listOf(URL("file://series2")))
val notFound = seriesDao.findAllNotDeletedByLibraryIdAndUrlNotIn(library.id, listOf(URL("file://series")))
assertThat(found).hasSize(1)
assertThat(found.first().name).isEqualTo("Series")