Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: aggregate book information at series level
- Loading branch information
Showing
15 changed files
with
516 additions
and
5 deletions.
There are no files selected for viewing
20 changes: 20 additions & 0 deletions
20
...a/src/flyway/resources/db/migration/sqlite/V20210111113543__book_metadata_aggregation.sql
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
CREATE TABLE BOOK_METADATA_AGGREGATION | ||
( | ||
CREATED_DATE datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
LAST_MODIFIED_DATE datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
RELEASE_DATE date NULL, | ||
SUMMARY varchar NOT NULL DEFAULT '', | ||
SUMMARY_NUMBER varchar NOT NULL DEFAULT '', | ||
SERIES_ID varchar NOT NULL PRIMARY KEY, | ||
FOREIGN KEY (SERIES_ID) REFERENCES SERIES (ID) | ||
); | ||
CREATE TABLE BOOK_METADATA_AGGREGATION_AUTHOR | ||
( | ||
NAME varchar NOT NULL, | ||
ROLE varchar NOT NULL, | ||
SERIES_ID varchar NOT NULL, | ||
FOREIGN KEY (SERIES_ID) REFERENCES SERIES (ID) | ||
); | ||
INSERT INTO BOOK_METADATA_AGGREGATION(SERIES_ID) | ||
SELECT ID | ||
from SERIES; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
16 changes: 16 additions & 0 deletions
16
komga/src/main/kotlin/org/gotson/komga/domain/model/BookMetadataAggregation.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package org.gotson.komga.domain.model | ||
|
||
import java.time.LocalDate | ||
import java.time.LocalDateTime | ||
|
||
data class BookMetadataAggregation( | ||
val authors: List<Author> = emptyList(), | ||
val releaseDate: LocalDate? = null, | ||
val summary: String = "", | ||
val summaryNumber: String = "", | ||
|
||
val seriesId: String = "", | ||
|
||
override val createdDate: LocalDateTime = LocalDateTime.now(), | ||
override val lastModifiedDate: LocalDateTime = LocalDateTime.now() | ||
) : Auditable() |
16 changes: 16 additions & 0 deletions
16
.../src/main/kotlin/org/gotson/komga/domain/persistence/BookMetadataAggregationRepository.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package org.gotson.komga.domain.persistence | ||
|
||
import org.gotson.komga.domain.model.BookMetadataAggregation | ||
|
||
interface BookMetadataAggregationRepository { | ||
fun findById(seriesId: String): BookMetadataAggregation | ||
fun findByIdOrNull(seriesId: String): BookMetadataAggregation? | ||
|
||
fun insert(metadata: BookMetadataAggregation) | ||
fun update(metadata: BookMetadataAggregation) | ||
|
||
fun delete(seriesId: String) | ||
fun delete(seriesIds: Collection<String>) | ||
|
||
fun count(): Long | ||
} |
19 changes: 19 additions & 0 deletions
19
komga/src/main/kotlin/org/gotson/komga/domain/service/MetadataAggregator.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.gotson.komga.domain.service | ||
|
||
import org.gotson.komga.domain.model.BookMetadata | ||
import org.gotson.komga.domain.model.BookMetadataAggregation | ||
import org.springframework.stereotype.Service | ||
|
||
@Service | ||
class MetadataAggregator { | ||
|
||
fun aggregate(metadatas: Collection<BookMetadata>) : BookMetadataAggregation { | ||
val authors = metadatas.flatMap { it.authors }.distinctBy { "${it.role}__${it.name}" } | ||
val (summary, summaryNumber) = metadatas.sortedBy { it.numberSort }.find { it.summary.isNotBlank() }?.let { | ||
it.summary to it.number | ||
} ?: "" to "" | ||
val releaseDate = metadatas.mapNotNull { it.releaseDate }.minOrNull() | ||
|
||
return BookMetadataAggregation(authors = authors, releaseDate = releaseDate, summary = summary, summaryNumber = summaryNumber) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
124 changes: 124 additions & 0 deletions
124
komga/src/main/kotlin/org/gotson/komga/infrastructure/jooq/BookMetadataAggregationDao.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
package org.gotson.komga.infrastructure.jooq | ||
|
||
import org.gotson.komga.domain.model.Author | ||
import org.gotson.komga.domain.model.BookMetadataAggregation | ||
import org.gotson.komga.domain.persistence.BookMetadataAggregationRepository | ||
import org.gotson.komga.jooq.Tables | ||
import org.gotson.komga.jooq.tables.records.BookMetadataAggregationAuthorRecord | ||
import org.gotson.komga.jooq.tables.records.BookMetadataAggregationRecord | ||
import org.jooq.DSLContext | ||
import org.springframework.stereotype.Component | ||
import java.time.LocalDateTime | ||
import java.time.ZoneId | ||
|
||
@Component | ||
class BookMetadataAggregationDao( | ||
private val dsl: DSLContext | ||
) : BookMetadataAggregationRepository { | ||
|
||
private val d = Tables.BOOK_METADATA_AGGREGATION | ||
private val a = Tables.BOOK_METADATA_AGGREGATION_AUTHOR | ||
|
||
private val groupFields = arrayOf(*d.fields(), *a.fields()) | ||
|
||
override fun findById(seriesId: String): BookMetadataAggregation = | ||
findOne(listOf(seriesId)).first() | ||
|
||
override fun findByIdOrNull(seriesId: String): BookMetadataAggregation? = | ||
findOne(listOf(seriesId)).firstOrNull() | ||
|
||
private fun findOne(seriesIds: Collection<String>) = | ||
dsl.select(*groupFields) | ||
.from(d) | ||
.leftJoin(a).on(d.SERIES_ID.eq(a.SERIES_ID)) | ||
.where(d.SERIES_ID.`in`(seriesIds)) | ||
.groupBy(*groupFields) | ||
.fetchGroups( | ||
{ it.into(d) }, { it.into(a) } | ||
).map { (dr, ar) -> | ||
dr.toDomain(ar.filterNot { it.name == null }.map { it.toDomain() }) | ||
} | ||
|
||
override fun insert(metadata: BookMetadataAggregation) { | ||
dsl.transaction { config -> | ||
config.dsl().insertInto(d) | ||
.set(d.SERIES_ID, metadata.seriesId) | ||
.set(d.RELEASE_DATE, metadata.releaseDate) | ||
.set(d.SUMMARY, metadata.summary) | ||
.set(d.SUMMARY_NUMBER, metadata.summaryNumber) | ||
.execute() | ||
|
||
insertAuthors(config.dsl(), metadata) | ||
} | ||
} | ||
|
||
override fun update(metadata: BookMetadataAggregation) { | ||
dsl.transaction { config -> | ||
config.dsl().update(d) | ||
.set(d.SUMMARY, metadata.summary) | ||
.set(d.SUMMARY_NUMBER, metadata.summaryNumber) | ||
.set(d.RELEASE_DATE, metadata.releaseDate) | ||
.set(d.LAST_MODIFIED_DATE, LocalDateTime.now(ZoneId.of("Z"))) | ||
.where(d.SERIES_ID.eq(metadata.seriesId)) | ||
.execute() | ||
|
||
config.dsl().deleteFrom(a) | ||
.where(a.SERIES_ID.eq(metadata.seriesId)) | ||
.execute() | ||
|
||
insertAuthors(config.dsl(), metadata) | ||
} | ||
} | ||
|
||
private fun insertAuthors(dsl: DSLContext, metadata: BookMetadataAggregation) { | ||
if (metadata.authors.isNotEmpty()) { | ||
dsl.batch( | ||
dsl.insertInto(a, a.SERIES_ID, a.NAME, a.ROLE) | ||
.values(null as String?, null, null) | ||
).also { step -> | ||
metadata.authors.forEach { | ||
step.bind(metadata.seriesId, it.name, it.role) | ||
} | ||
}.execute() | ||
} | ||
} | ||
|
||
override fun delete(seriesId: String) { | ||
dsl.transaction { config -> | ||
with(config.dsl()) { | ||
deleteFrom(a).where(a.SERIES_ID.eq(seriesId)).execute() | ||
deleteFrom(d).where(d.SERIES_ID.eq(seriesId)).execute() | ||
} | ||
} | ||
} | ||
|
||
override fun delete(seriesIds: Collection<String>) { | ||
dsl.transaction { config -> | ||
with(config.dsl()) { | ||
deleteFrom(a).where(a.SERIES_ID.`in`(seriesIds)).execute() | ||
deleteFrom(d).where(d.SERIES_ID.`in`(seriesIds)).execute() | ||
} | ||
} | ||
} | ||
|
||
override fun count(): Long = dsl.fetchCount(d).toLong() | ||
|
||
private fun BookMetadataAggregationRecord.toDomain(authors: List<Author>) = | ||
BookMetadataAggregation( | ||
authors = authors, | ||
releaseDate = releaseDate, | ||
summary = summary, | ||
summaryNumber = summaryNumber, | ||
|
||
seriesId = seriesId, | ||
|
||
createdDate = createdDate.toCurrentTimeZone(), | ||
lastModifiedDate = lastModifiedDate.toCurrentTimeZone() | ||
) | ||
|
||
private fun BookMetadataAggregationAuthorRecord.toDomain() = | ||
Author( | ||
name = name, | ||
role = role | ||
) | ||
} |
Oops, something went wrong.