feat(api): add total book count field for series metadata

closes #298
This commit is contained in:
Gauthier Roebroeck 2021-07-30 10:41:52 +08:00
parent d096d7432b
commit 87c1432984
9 changed files with 84 additions and 34 deletions

View file

@ -0,0 +1,4 @@
alter table series_metadata
add column TOTAL_BOOK_COUNT int NULL;
alter table series_metadata
add column TOTAL_BOOK_COUNT_LOCK boolean NOT NULL DEFAULT 0;

View file

@ -13,6 +13,7 @@ class SeriesMetadata(
val language: String = "", val language: String = "",
genres: Set<String> = emptySet(), genres: Set<String> = emptySet(),
tags: Set<String> = emptySet(), tags: Set<String> = emptySet(),
val totalBookCount: Int? = null,
val statusLock: Boolean = false, val statusLock: Boolean = false,
val titleLock: Boolean = false, val titleLock: Boolean = false,
@ -24,6 +25,7 @@ class SeriesMetadata(
val languageLock: Boolean = false, val languageLock: Boolean = false,
val genresLock: Boolean = false, val genresLock: Boolean = false,
val tagsLock: Boolean = false, val tagsLock: Boolean = false,
val totalBookCountLock: Boolean = false,
val seriesId: String = "", val seriesId: String = "",
@ -48,6 +50,7 @@ class SeriesMetadata(
language: String = this.language, language: String = this.language,
genres: Set<String> = this.genres, genres: Set<String> = this.genres,
tags: Set<String> = this.tags, tags: Set<String> = this.tags,
totalBookCount: Int? = this.totalBookCount,
statusLock: Boolean = this.statusLock, statusLock: Boolean = this.statusLock,
titleLock: Boolean = this.titleLock, titleLock: Boolean = this.titleLock,
titleSortLock: Boolean = this.titleSortLock, titleSortLock: Boolean = this.titleSortLock,
@ -58,6 +61,7 @@ class SeriesMetadata(
languageLock: Boolean = this.languageLock, languageLock: Boolean = this.languageLock,
genresLock: Boolean = this.genresLock, genresLock: Boolean = this.genresLock,
tagsLock: Boolean = this.tagsLock, tagsLock: Boolean = this.tagsLock,
totalBookCountLock: Boolean = this.totalBookCountLock,
seriesId: String = this.seriesId, seriesId: String = this.seriesId,
createdDate: LocalDateTime = this.createdDate, createdDate: LocalDateTime = this.createdDate,
lastModifiedDate: LocalDateTime = this.lastModifiedDate lastModifiedDate: LocalDateTime = this.lastModifiedDate
@ -73,6 +77,7 @@ class SeriesMetadata(
language = language, language = language,
genres = genres, genres = genres,
tags = tags, tags = tags,
totalBookCount = totalBookCount,
statusLock = statusLock, statusLock = statusLock,
titleLock = titleLock, titleLock = titleLock,
titleSortLock = titleSortLock, titleSortLock = titleSortLock,
@ -83,6 +88,7 @@ class SeriesMetadata(
languageLock = languageLock, languageLock = languageLock,
genresLock = genresLock, genresLock = genresLock,
tagsLock = tagsLock, tagsLock = tagsLock,
totalBookCountLock = totalBookCountLock,
seriesId = seriesId, seriesId = seriesId,
createdDate = createdDate, createdDate = createdDate,
lastModifiedDate = lastModifiedDate lastModifiedDate = lastModifiedDate
@ -100,6 +106,6 @@ class SeriesMetadata(
} }
override fun toString(): String { override fun toString(): String {
return "SeriesMetadata(status=$status, readingDirection=$readingDirection, ageRating=$ageRating, language=$language, genres=$genres, statusLock=$statusLock, titleLock=$titleLock, titleSortLock=$titleSortLock, readingDirectionLock=$readingDirectionLock, publisherLock=$publisherLock, ageRatingLock=$ageRatingLock, languageLock=$languageLock, genresLock=$genresLock, seriesId='$seriesId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate, title='$title', titleSort='$titleSort', summary='$summary', publisher='$publisher')" return "SeriesMetadata(status=$status, readingDirection=$readingDirection, ageRating=$ageRating, language='$language', totalBookCount=$totalBookCount, statusLock=$statusLock, titleLock=$titleLock, titleSortLock=$titleSortLock, summaryLock=$summaryLock, readingDirectionLock=$readingDirectionLock, publisherLock=$publisherLock, ageRatingLock=$ageRatingLock, languageLock=$languageLock, genresLock=$genresLock, tagsLock=$tagsLock, totalBookCountLock=$totalBookCountLock, seriesId='$seriesId', createdDate=$createdDate, lastModifiedDate=$lastModifiedDate, title='$title', titleSort='$titleSort', summary='$summary', publisher='$publisher', tags=$tags, genres=$genres)"
} }
} }

View file

@ -365,7 +365,9 @@ class SeriesDtoDao(
genres = genres, genres = genres,
genresLock = genresLock, genresLock = genresLock,
tags = tags, tags = tags,
tagsLock = tagsLock tagsLock = tagsLock,
totalBookCount = totalBookCount,
totalBookCountLock = totalBookCountLock,
) )
private fun BookMetadataAggregationRecord.toDto(authors: List<AuthorDto>) = private fun BookMetadataAggregationRecord.toDto(authors: List<AuthorDto>) =

View file

@ -68,6 +68,8 @@ class SeriesMetadataDao(
.set(d.LANGUAGE_LOCK, metadata.languageLock) .set(d.LANGUAGE_LOCK, metadata.languageLock)
.set(d.GENRES_LOCK, metadata.genresLock) .set(d.GENRES_LOCK, metadata.genresLock)
.set(d.TAGS_LOCK, metadata.tagsLock) .set(d.TAGS_LOCK, metadata.tagsLock)
.set(d.TOTAL_BOOK_COUNT, metadata.totalBookCount)
.set(d.TOTAL_BOOK_COUNT_LOCK, metadata.totalBookCountLock)
.execute() .execute()
insertGenres(metadata) insertGenres(metadata)
@ -95,6 +97,8 @@ class SeriesMetadataDao(
.set(d.LANGUAGE_LOCK, metadata.languageLock) .set(d.LANGUAGE_LOCK, metadata.languageLock)
.set(d.GENRES_LOCK, metadata.genresLock) .set(d.GENRES_LOCK, metadata.genresLock)
.set(d.TAGS_LOCK, metadata.tagsLock) .set(d.TAGS_LOCK, metadata.tagsLock)
.set(d.TOTAL_BOOK_COUNT, metadata.totalBookCount)
.set(d.TOTAL_BOOK_COUNT_LOCK, metadata.totalBookCountLock)
.set(d.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) .set(d.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z")))
.where(d.SERIES_ID.eq(metadata.seriesId)) .where(d.SERIES_ID.eq(metadata.seriesId))
.execute() .execute()
@ -167,6 +171,7 @@ class SeriesMetadataDao(
language = language, language = language,
genres = genres, genres = genres,
tags = tags, tags = tags,
totalBookCount = totalBookCount,
statusLock = statusLock, statusLock = statusLock,
titleLock = titleLock, titleLock = titleLock,
@ -178,6 +183,7 @@ class SeriesMetadataDao(
languageLock = languageLock, languageLock = languageLock,
genresLock = genresLock, genresLock = genresLock,
tagsLock = tagsLock, tagsLock = tagsLock,
totalBookCountLock = totalBookCountLock,
seriesId = seriesId, seriesId = seriesId,

View file

@ -443,7 +443,9 @@ class SeriesController(
tags = if (isSet("tags")) { tags = if (isSet("tags")) {
if (tags != null) tags!! else emptySet() if (tags != null) tags!! else emptySet()
} else existing.tags, } else existing.tags,
tagsLock = tagsLock ?: existing.tagsLock tagsLock = tagsLock ?: existing.tagsLock,
totalBookCount = if (isSet("totalBookCount")) totalBookCount else existing.totalBookCount,
totalBookCountLock = totalBookCountLock ?: existing.totalBookCountLock,
) )
} }
seriesMetadataRepository.update(updated) seriesMetadataRepository.update(updated)

View file

@ -49,6 +49,8 @@ data class SeriesMetadataDto(
val genresLock: Boolean, val genresLock: Boolean,
val tags: Set<String>, val tags: Set<String>,
val tagsLock: Boolean, val tagsLock: Boolean,
val totalBookCount: Int?,
val totalBookCountLock: Boolean,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
val created: LocalDateTime, val created: LocalDateTime,

View file

@ -3,6 +3,7 @@ package org.gotson.komga.interfaces.rest.dto
import org.gotson.komga.domain.model.SeriesMetadata import org.gotson.komga.domain.model.SeriesMetadata
import org.gotson.komga.infrastructure.validation.NullOrBlankOrBCP47 import org.gotson.komga.infrastructure.validation.NullOrBlankOrBCP47
import org.gotson.komga.infrastructure.validation.NullOrNotBlank import org.gotson.komga.infrastructure.validation.NullOrNotBlank
import javax.validation.constraints.Positive
import javax.validation.constraints.PositiveOrZero import javax.validation.constraints.PositiveOrZero
import kotlin.properties.Delegates import kotlin.properties.Delegates
@ -33,7 +34,7 @@ class SeriesMetadataUpdateDto {
var publisherLock: Boolean? = null var publisherLock: Boolean? = null
var readingDirection: SeriesMetadata.ReadingDirection? var readingDirection: SeriesMetadata.ReadingDirection?
by Delegates.observable<SeriesMetadata.ReadingDirection?>(null) { prop, _, _ -> by Delegates.observable(null) { prop, _, _ ->
isSet[prop.name] = true isSet[prop.name] = true
} }
@ -41,7 +42,7 @@ class SeriesMetadataUpdateDto {
@get:PositiveOrZero @get:PositiveOrZero
var ageRating: Int? var ageRating: Int?
by Delegates.observable<Int?>(null) { prop, _, _ -> by Delegates.observable(null) { prop, _, _ ->
isSet[prop.name] = true isSet[prop.name] = true
} }
@ -53,16 +54,24 @@ class SeriesMetadataUpdateDto {
var languageLock: Boolean? = null var languageLock: Boolean? = null
var genres: Set<String>? var genres: Set<String>?
by Delegates.observable<Set<String>?>(null) { prop, _, _ -> by Delegates.observable(null) { prop, _, _ ->
isSet[prop.name] = true isSet[prop.name] = true
} }
var genresLock: Boolean? = null var genresLock: Boolean? = null
var tags: Set<String>? var tags: Set<String>?
by Delegates.observable<Set<String>?>(null) { prop, _, _ -> by Delegates.observable(null) { prop, _, _ ->
isSet[prop.name] = true isSet[prop.name] = true
} }
var tagsLock: Boolean? = null var tagsLock: Boolean? = null
@get:Positive
var totalBookCount: Int?
by Delegates.observable(null) { prop, _, _ ->
isSet[prop.name] = true
}
var totalBookCountLock: Boolean? = null
} }

View file

@ -61,6 +61,7 @@ class SeriesMetadataDaoTest(
genres = setOf("Action", "Adventure"), genres = setOf("Action", "Adventure"),
tags = setOf("tag", "another"), tags = setOf("tag", "another"),
language = "en", language = "en",
totalBookCount = 5,
titleLock = true, titleLock = true,
titleSortLock = true, titleSortLock = true,
summaryLock = true, summaryLock = true,
@ -70,6 +71,7 @@ class SeriesMetadataDaoTest(
genresLock = true, genresLock = true,
languageLock = true, languageLock = true,
tagsLock = true, tagsLock = true,
totalBookCountLock = true,
seriesId = series.id seriesId = series.id
) )
@ -90,6 +92,7 @@ class SeriesMetadataDaoTest(
assertThat(created.language).isEqualTo(metadata.language) assertThat(created.language).isEqualTo(metadata.language)
assertThat(created.genres).containsAll(metadata.genres) assertThat(created.genres).containsAll(metadata.genres)
assertThat(created.tags).containsAll(metadata.tags) assertThat(created.tags).containsAll(metadata.tags)
assertThat(created.totalBookCount).isEqualTo(metadata.totalBookCount)
assertThat(created.titleLock).isEqualTo(metadata.titleLock) assertThat(created.titleLock).isEqualTo(metadata.titleLock)
assertThat(created.titleSortLock).isEqualTo(metadata.titleSortLock) assertThat(created.titleSortLock).isEqualTo(metadata.titleSortLock)
@ -101,6 +104,7 @@ class SeriesMetadataDaoTest(
assertThat(created.genresLock).isEqualTo(metadata.genresLock) assertThat(created.genresLock).isEqualTo(metadata.genresLock)
assertThat(created.languageLock).isEqualTo(metadata.languageLock) assertThat(created.languageLock).isEqualTo(metadata.languageLock)
assertThat(created.tagsLock).isEqualTo(metadata.tagsLock) assertThat(created.tagsLock).isEqualTo(metadata.tagsLock)
assertThat(created.totalBookCountLock).isEqualTo(metadata.totalBookCountLock)
} }
@Test @Test
@ -122,25 +126,27 @@ class SeriesMetadataDaoTest(
assertThat(created.title).isEqualTo(metadata.title) assertThat(created.title).isEqualTo(metadata.title)
assertThat(created.titleSort).isEqualTo(metadata.title) assertThat(created.titleSort).isEqualTo(metadata.title)
assertThat(created.summary).isBlank() assertThat(created.summary).isBlank
assertThat(created.status).isEqualTo(SeriesMetadata.Status.ONGOING) assertThat(created.status).isEqualTo(SeriesMetadata.Status.ONGOING)
assertThat(created.readingDirection).isNull() assertThat(created.readingDirection).isNull()
assertThat(created.publisher).isBlank() assertThat(created.publisher).isBlank
assertThat(created.language).isBlank() assertThat(created.language).isBlank
assertThat(created.ageRating).isNull() assertThat(created.ageRating).isNull()
assertThat(created.genres).isEmpty() assertThat(created.genres).isEmpty()
assertThat(created.tags).isEmpty() assertThat(created.tags).isEmpty()
assertThat(created.totalBookCount).isNull()
assertThat(created.titleLock).isFalse() assertThat(created.titleLock).isFalse
assertThat(created.titleSortLock).isFalse() assertThat(created.titleSortLock).isFalse
assertThat(created.statusLock).isFalse() assertThat(created.statusLock).isFalse
assertThat(created.summaryLock).isFalse() assertThat(created.summaryLock).isFalse
assertThat(created.readingDirectionLock).isFalse() assertThat(created.readingDirectionLock).isFalse
assertThat(created.publisherLock).isFalse() assertThat(created.publisherLock).isFalse
assertThat(created.ageRatingLock).isFalse() assertThat(created.ageRatingLock).isFalse
assertThat(created.genresLock).isFalse() assertThat(created.genresLock).isFalse
assertThat(created.languageLock).isFalse() assertThat(created.languageLock).isFalse
assertThat(created.tagsLock).isFalse() assertThat(created.tagsLock).isFalse
assertThat(created.totalBookCountLock).isFalse
} }
@Test @Test
@ -191,6 +197,7 @@ class SeriesMetadataDaoTest(
language = "en", language = "en",
genres = setOf("Action"), genres = setOf("Action"),
tags = setOf("tag"), tags = setOf("tag"),
totalBookCount = 3,
seriesId = series.id seriesId = series.id
) )
seriesMetadataDao.insert(metadata) seriesMetadataDao.insert(metadata)
@ -210,6 +217,7 @@ class SeriesMetadataDaoTest(
language = "jp", language = "jp",
genres = setOf("Adventure"), genres = setOf("Adventure"),
tags = setOf("Another"), tags = setOf("Another"),
totalBookCount = 8,
statusLock = true, statusLock = true,
titleLock = true, titleLock = true,
titleSortLock = true, titleSortLock = true,
@ -219,7 +227,8 @@ class SeriesMetadataDaoTest(
ageRatingLock = true, ageRatingLock = true,
languageLock = true, languageLock = true,
genresLock = true, genresLock = true,
tagsLock = true tagsLock = true,
totalBookCountLock = true,
) )
} }
@ -241,16 +250,18 @@ class SeriesMetadataDaoTest(
assertThat(modified.language).isEqualTo(updated.language) assertThat(modified.language).isEqualTo(updated.language)
assertThat(modified.genres).containsAll(updated.genres) assertThat(modified.genres).containsAll(updated.genres)
assertThat(modified.tags).containsAll(updated.tags) assertThat(modified.tags).containsAll(updated.tags)
assertThat(modified.totalBookCount).isEqualTo(updated.totalBookCount)
assertThat(modified.titleLock).isTrue() assertThat(modified.titleLock).isTrue
assertThat(modified.titleSortLock).isTrue() assertThat(modified.titleSortLock).isTrue
assertThat(modified.statusLock).isTrue() assertThat(modified.statusLock).isTrue
assertThat(modified.summaryLock).isTrue() assertThat(modified.summaryLock).isTrue
assertThat(modified.readingDirectionLock).isTrue() assertThat(modified.readingDirectionLock).isTrue
assertThat(modified.ageRatingLock).isTrue() assertThat(modified.ageRatingLock).isTrue
assertThat(modified.languageLock).isTrue() assertThat(modified.languageLock).isTrue
assertThat(modified.genresLock).isTrue() assertThat(modified.genresLock).isTrue
assertThat(modified.publisherLock).isTrue() assertThat(modified.publisherLock).isTrue
assertThat(modified.tagsLock).isTrue() assertThat(modified.tagsLock).isTrue
assertThat(modified.totalBookCountLock).isTrue
} }
} }

View file

@ -419,6 +419,7 @@ class SeriesControllerTest(
"""{"title":""}""", """{"title":""}""",
"""{"titleSort":""}""", """{"titleSort":""}""",
"""{"ageRating":-1}""", """{"ageRating":-1}""",
"""{"totalBookCount":0}""",
"""{"language":"japanese"}""" """{"language":"japanese"}"""
] ]
) )
@ -463,7 +464,9 @@ class SeriesControllerTest(
"genres":["Action"], "genres":["Action"],
"genresLock":true, "genresLock":true,
"tags":["tag"], "tags":["tag"],
"tagsLock":true "tagsLock":true,
"totalBookCount":5,
"totalBookCountLock":true
} }
""".trimIndent() """.trimIndent()
@ -486,6 +489,7 @@ class SeriesControllerTest(
assertThat(ageRating).isEqualTo(12) assertThat(ageRating).isEqualTo(12)
assertThat(genres).containsExactly("action") assertThat(genres).containsExactly("action")
assertThat(tags).containsExactly("tag") assertThat(tags).containsExactly("tag")
assertThat(totalBookCount).isEqualTo(5)
assertThat(titleLock).isEqualTo(true) assertThat(titleLock).isEqualTo(true)
assertThat(titleSortLock).isEqualTo(true) assertThat(titleSortLock).isEqualTo(true)
@ -497,6 +501,7 @@ class SeriesControllerTest(
assertThat(summaryLock).isEqualTo(true) assertThat(summaryLock).isEqualTo(true)
assertThat(genresLock).isEqualTo(true) assertThat(genresLock).isEqualTo(true)
assertThat(tagsLock).isEqualTo(true) assertThat(tagsLock).isEqualTo(true)
assertThat(totalBookCountLock).isEqualTo(true)
} }
} }
@ -515,7 +520,8 @@ class SeriesControllerTest(
ageRating = 12, ageRating = 12,
readingDirection = SeriesMetadata.ReadingDirection.LEFT_TO_RIGHT, readingDirection = SeriesMetadata.ReadingDirection.LEFT_TO_RIGHT,
genres = setOf("Action"), genres = setOf("Action"),
tags = setOf("tag") tags = setOf("tag"),
totalBookCount = 5,
) )
seriesMetadataRepository.update(updated) seriesMetadataRepository.update(updated)
@ -533,7 +539,8 @@ class SeriesControllerTest(
"readingDirection":null, "readingDirection":null,
"ageRating":null, "ageRating":null,
"genres":null, "genres":null,
"tags":null "tags":null,
"totalBookCount":null
} }
""".trimIndent() """.trimIndent()
@ -550,6 +557,7 @@ class SeriesControllerTest(
assertThat(ageRating).isNull() assertThat(ageRating).isNull()
assertThat(genres).isEmpty() assertThat(genres).isEmpty()
assertThat(tags).isEmpty() assertThat(tags).isEmpty()
assertThat(totalBookCount).isNull()
} }
} }
} }