Skip to content

Commit

Permalink
refactor(backend): move PodcastRepository to non Reactive API
Browse files Browse the repository at this point in the history
Related to #231
  • Loading branch information
davinkevin committed Aug 3, 2024
1 parent c172f34 commit 3a95ca1
Show file tree
Hide file tree
Showing 8 changed files with 672 additions and 676 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ class ItemService(
val filename = Paths.get(filePart.filename().replace("[^a-zA-Z0-9.-]".toRegex(), "_"))

val path = file.cache(filePart, filename).block()!!
val podcast = podcastRepository.findById(podcastId).block()!!
val podcast = podcastRepository.findById(podcastId)!!

file.upload(podcast.title, path).block()
val metadata = file.metadata(podcast.title, path).block()!!
Expand Down Expand Up @@ -109,7 +109,7 @@ class ItemService(
)

val createdItem = repository.create(item)!!
podcastRepository.updateLastUpdate(podcastId).block()
podcastRepository.updateLastUpdate(podcastId)

return createdItem
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import org.jooq.Records.mapping
import org.jooq.TableField
import org.jooq.impl.DSL.*
import reactor.core.publisher.Flux
import reactor.core.publisher.Mono
import reactor.kotlin.core.publisher.toMono
import java.net.URI
import java.sql.Date
Expand All @@ -22,83 +21,94 @@ import java.util.*

class PodcastRepository(private val query: DSLContext) {

fun findById(id: UUID): Mono<Podcast> = query
.select(
PODCAST.ID, PODCAST.TITLE, PODCAST.DESCRIPTION, PODCAST.SIGNATURE, PODCAST.URL,
PODCAST.HAS_TO_BE_DELETED, PODCAST.LAST_UPDATE,
PODCAST.TYPE,
fun findById(id: UUID): Podcast? {
return query
.select(
PODCAST.ID, PODCAST.TITLE, PODCAST.DESCRIPTION, PODCAST.SIGNATURE, PODCAST.URL,
PODCAST.HAS_TO_BE_DELETED, PODCAST.LAST_UPDATE,
PODCAST.TYPE,

PODCAST.cover().ID, PODCAST.cover().URL, PODCAST.cover().HEIGHT, PODCAST.cover().WIDTH,
PODCAST.cover().ID, PODCAST.cover().URL, PODCAST.cover().HEIGHT, PODCAST.cover().WIDTH,

multiset(
select(PODCAST_TAGS.tag().ID, PODCAST_TAGS.tag().NAME)
.from(PODCAST_TAGS)
.where(PODCAST_TAGS.PODCASTS_ID.eq(PODCAST.ID))
multiset(
select(PODCAST_TAGS.tag().ID, PODCAST_TAGS.tag().NAME)
.from(PODCAST_TAGS)
.where(PODCAST_TAGS.PODCASTS_ID.eq(PODCAST.ID))
)
.convertFrom { r -> r.map(mapping(::Tag)) }
)
.convertFrom { r -> r.map(mapping(::Tag)) }
)
.from(PODCAST)
.where(PODCAST.ID.eq(id))
.toMono()
.map(::toPodcast)
.from(PODCAST)
.where(PODCAST.ID.eq(id))
.toMono()
.block()
?.let(::toPodcast)
}

fun findAll(): Flux<Podcast> = Flux.from(
query
.select(
PODCAST.ID, PODCAST.TITLE, PODCAST.DESCRIPTION, PODCAST.SIGNATURE, PODCAST.URL,
PODCAST.HAS_TO_BE_DELETED, PODCAST.LAST_UPDATE,
PODCAST.TYPE,

PODCAST.cover().ID, PODCAST.cover().URL, PODCAST.cover().HEIGHT, PODCAST.cover().WIDTH,

multiset(
select(PODCAST_TAGS.tag().ID, PODCAST_TAGS.tag().NAME)
.from(PODCAST_TAGS)
.where(PODCAST_TAGS.PODCASTS_ID.eq(PODCAST.ID))
.orderBy(PODCAST_TAGS.TAGS_ID)
)
.convertFrom { r -> r.map(mapping(::Tag)) },
fun findAll(): List<Podcast> {
val allPodcastQuery = Flux.from(query
.select(
PODCAST.ID, PODCAST.TITLE, PODCAST.DESCRIPTION, PODCAST.SIGNATURE, PODCAST.URL,
PODCAST.HAS_TO_BE_DELETED, PODCAST.LAST_UPDATE,
PODCAST.TYPE,

PODCAST.cover().ID, PODCAST.cover().URL, PODCAST.cover().HEIGHT, PODCAST.cover().WIDTH,

multiset(
select(PODCAST_TAGS.tag().ID, PODCAST_TAGS.tag().NAME)
.from(PODCAST_TAGS)
.where(PODCAST_TAGS.PODCASTS_ID.eq(PODCAST.ID))
.orderBy(PODCAST_TAGS.TAGS_ID)
)
.from(PODCAST)
.orderBy(PODCAST.ID)
)
.map(::toPodcast)
.convertFrom { r -> r.map(mapping(::Tag)) },
)
.from(PODCAST)
.orderBy(PODCAST.ID))
.collectList()
.block()!!

fun findStatByTypeAndCreationDate(numberOfMonth: Int) = findStatByTypeAndField(numberOfMonth, ITEM.CREATION_DATE)
fun findStatByTypeAndPubDate(numberOfMonth: Int) = findStatByTypeAndField(numberOfMonth, ITEM.PUB_DATE)
fun findStatByTypeAndDownloadDate(numberOfMonth: Int) = findStatByTypeAndField(numberOfMonth, ITEM.DOWNLOAD_DATE)
return allPodcastQuery.map(::toPodcast)
}

private fun findStatByTypeAndField(month: Int, field: TableField<ItemRecord, OffsetDateTime>): Flux<StatsPodcastType> = Flux.defer {
fun findStatByTypeAndCreationDate(numberOfMonth: Int): List<StatsPodcastType> = findStatByTypeAndField(numberOfMonth, ITEM.CREATION_DATE)
fun findStatByTypeAndPubDate(numberOfMonth: Int): List<StatsPodcastType> = findStatByTypeAndField(numberOfMonth, ITEM.PUB_DATE)
fun findStatByTypeAndDownloadDate(numberOfMonth: Int): List<StatsPodcastType> = findStatByTypeAndField(numberOfMonth, ITEM.DOWNLOAD_DATE)

private fun findStatByTypeAndField(month: Int, field: TableField<ItemRecord, OffsetDateTime>): List<StatsPodcastType> {
val date = trunc(field)
val startDate = ZonedDateTime.now().minusMonths(month.toLong())
val numberOfDays = Duration.between(startDate, ZonedDateTime.now()).toDays()

Flux.from(query
.select(PODCAST.TYPE, count(), date)
.from(ITEM.innerJoin(PODCAST).on(ITEM.PODCAST_ID.eq(PODCAST.ID)))
.where(field.isNotNull)
.and(dateDiff(currentDate(), field.cast(Date::class.java)).lessThan(numberOfDays.toInt()))
.groupBy(PODCAST.TYPE, date)
.orderBy(date.desc())
val stats = Flux.from(
query
.select(PODCAST.TYPE, count(), date)
.from(ITEM.innerJoin(PODCAST).on(ITEM.PODCAST_ID.eq(PODCAST.ID)))
.where(field.isNotNull)
.and(dateDiff(currentDate(), field.cast(Date::class.java)).lessThan(numberOfDays.toInt()))
.groupBy(PODCAST.TYPE, date)
.orderBy(date.desc())
)
.collectList()
.block()!!

return stats
.groupBy { it[PODCAST.TYPE] }
.flatMap { group -> group
.mapValues { (_, values) -> values
.map { (_, number, date) -> NumberOfItemByDateWrapper(date.toLocalDate(), number) }
.collectList()
.map { StatsPodcastType(group.key(), it.toSet()) }
.toSet()
}
.map { StatsPodcastType(it.key, it.value) }
}

fun findStatByPodcastIdAndPubDate(pid: UUID, month: Int) = findStatOfOnField(pid, month, ITEM.PUB_DATE)
fun findStatByPodcastIdAndCreationDate(pid: UUID, month: Int) = findStatOfOnField(pid, month, ITEM.CREATION_DATE)
fun findStatByPodcastIdAndDownloadDate(pid: UUID, month: Int) = findStatOfOnField(pid, month, ITEM.DOWNLOAD_DATE)

private fun findStatOfOnField(pid: UUID, month: Int, field: TableField<ItemRecord, OffsetDateTime>): Flux<NumberOfItemByDateWrapper> = Flux.defer {
private fun findStatOfOnField(pid: UUID, month: Int, field: TableField<ItemRecord, OffsetDateTime>): List<NumberOfItemByDateWrapper> {
val date = trunc(field)
val startDate = ZonedDateTime.now().minusMonths(month.toLong())
val numberOfDays = Duration.between(startDate, ZonedDateTime.now()).toDays()

Flux.from(
val results = Flux.from(
query
.select(count(), date)
.from(ITEM)
Expand All @@ -108,112 +118,124 @@ class PodcastRepository(private val query: DSLContext) {
.groupBy(date)
.orderBy(date.desc())
)
.collectList()
.block()!!

return results
.map { (count, date) -> NumberOfItemByDateWrapper(date.toLocalDate(), count) }
}

fun save(title: String, url: String?, hasToBeDeleted: Boolean, type: String, tags: Collection<Tag>, cover: Cover) = Mono.defer {
fun save(title: String, url: String?, hasToBeDeleted: Boolean, type: String, tags: Collection<Tag>, cover: Cover): Podcast {
val id = UUID.randomUUID()

val insertPodcast = query
query
.insertInto(PODCAST, PODCAST.ID, PODCAST.TITLE, PODCAST.URL, PODCAST.HAS_TO_BE_DELETED, PODCAST.TYPE, PODCAST.COVER_ID)
.values(id, title, url, hasToBeDeleted, type, cover.id)
.toMono()
.block()!!

val linkToTags = if (tags.isEmpty()) Mono.empty() else {
if (!tags.isEmpty()) {
query.insertInto(PODCAST_TAGS, PODCAST_TAGS.PODCASTS_ID, PODCAST_TAGS.TAGS_ID )
.apply { tags.forEach { values(id, it.id) } }
.toMono()
.block()!!
}

insertPodcast
.then(linkToTags)
.then(findById(id))
return findById(id)!!
}

fun update(id: UUID, title: String, url: String?, hasToBeDeleted: Boolean, tags: Collection<Tag>, cover: Cover): Mono<Podcast> = Mono.defer {

val update = query
fun update(id: UUID, title: String, url: String?, hasToBeDeleted: Boolean, tags: Collection<Tag>, cover: Cover): Podcast {
query
.update(PODCAST)
.set(PODCAST.TITLE, title)
.set(PODCAST.URL, url)
.set(PODCAST.HAS_TO_BE_DELETED, hasToBeDeleted)
.set(PODCAST.COVER_ID, cover.id)
.where(PODCAST.ID.eq(id))
.toMono()
.block()

val deleteAllTags = query
query
.delete(PODCAST_TAGS)
.where(PODCAST_TAGS.PODCASTS_ID.eq(id))
.toMono()
.block()

val insertNewTags = if (tags.isEmpty()) Mono.empty()
else query
.insertInto(PODCAST_TAGS, PODCAST_TAGS.PODCASTS_ID, PODCAST_TAGS.TAGS_ID)
.apply { tags.forEach { values(id, it.id) } }
.toMono()
if (tags.isNotEmpty()) {
query
.insertInto(PODCAST_TAGS, PODCAST_TAGS.PODCASTS_ID, PODCAST_TAGS.TAGS_ID)
.apply { tags.forEach { values(id, it.id) } }
.toMono()
.block()
}

update
.then(deleteAllTags)
.then(insertNewTags)
.then(findById(id))
return findById(id)!!
}

fun updateSignature(podcastId: UUID, newSignature: String): Mono<Void> = Mono.defer {
fun updateSignature(podcastId: UUID, newSignature: String) {
query
.update(PODCAST)
.set(PODCAST.SIGNATURE, newSignature)
.where(PODCAST.ID.eq(podcastId))
.toMono()
.block()
}
.then()


fun updateLastUpdate(podcastId: UUID): Mono<Void> = Mono.defer {
fun updateLastUpdate(podcastId: UUID) {
query
.update(PODCAST)
.set(PODCAST.LAST_UPDATE, now())
.where(PODCAST.ID.eq(podcastId))
.toMono()
.block()
}
.then()

fun deleteById(id: UUID): Mono<DeletePodcastRequest> = Mono.defer {
val removeItemFromPlaylist = query
fun deleteById(id: UUID): DeletePodcastRequest? {
query
.delete(WATCH_LIST_ITEMS)
.where(WATCH_LIST_ITEMS.ITEMS_ID.`in`(query
.select(ITEM.ID)
.from(ITEM)
.where(ITEM.PODCAST_ID.eq(id)))
.where(
WATCH_LIST_ITEMS.ITEMS_ID.`in`(
query
.select(ITEM.ID)
.from(ITEM)
.where(ITEM.PODCAST_ID.eq(id))
)
)
.toMono()
.block()

val removePodcastTags = query
query
.delete(PODCAST_TAGS)
.where(PODCAST_TAGS.PODCASTS_ID.eq(id))
.toMono()
.block()

val removeItems = query
query
.delete(ITEM)
.where(ITEM.PODCAST_ID.eq(id))
.toMono()
.block()

val deletePodcast = query
val podcast = query
.select(PODCAST.ID, PODCAST.TITLE, PODCAST.HAS_TO_BE_DELETED, PODCAST.COVER_ID)
.from(PODCAST)
.where(PODCAST.ID.eq(id))
.toMono()
.delayUntil {
val deletePodcast = query.delete(PODCAST).where(PODCAST.ID.eq(id)).toMono()
val deleteCover = query.delete(COVER).where(COVER.ID.eq(it[PODCAST.COVER_ID])).toMono()
.block()!!

deletePodcast.then(deleteCover)
}
.filter { it[PODCAST.HAS_TO_BE_DELETED] }
.map { DeletePodcastRequest(it[PODCAST.ID], it[PODCAST.TITLE]) }
query.delete(PODCAST).where(PODCAST.ID.eq(id))
.toMono()
.block()

query.delete(COVER).where(COVER.ID.eq(podcast[PODCAST.COVER_ID]))
.toMono()
.block()

if (!podcast[PODCAST.HAS_TO_BE_DELETED]) {
return null
}

removeItemFromPlaylist
.then(Mono.zip(removePodcastTags, removeItems))
.then(deletePodcast)
return DeletePodcastRequest(podcast[PODCAST.ID], podcast[PODCAST.TITLE])
}
}

Expand Down
Loading

0 comments on commit 3a95ca1

Please sign in to comment.