194 lines
5.5 KiB
Kotlin
194 lines
5.5 KiB
Kotlin
package be.vandewalleh.services
|
|
|
|
import be.vandewalleh.tables.Chapters
|
|
import be.vandewalleh.tables.Notes
|
|
import be.vandewalleh.tables.Tags
|
|
import me.liuwj.ktorm.database.*
|
|
import me.liuwj.ktorm.dsl.*
|
|
import me.liuwj.ktorm.entity.*
|
|
import org.kodein.di.Kodein
|
|
import org.kodein.di.KodeinAware
|
|
import org.kodein.di.generic.instance
|
|
import java.time.LocalDateTime
|
|
import java.time.format.DateTimeFormatter
|
|
import java.util.*
|
|
|
|
/**
|
|
* service to handle database queries at the Notes level.
|
|
*/
|
|
class NotesService(override val kodein: Kodein) : KodeinAware {
|
|
private val db by instance<Database>()
|
|
|
|
/**
|
|
* returns a list of [BasicNoteDTO] associated with the userId
|
|
*/
|
|
fun getNotes(userId: Int): List<BasicNoteDTO> {
|
|
val notes = db.sequenceOf(Notes)
|
|
.filterColumns { listOf(it.uuid, it.title, it.updatedAt) }
|
|
.filter { it.userId eq userId }
|
|
.sortedByDescending { it.updatedAt }
|
|
.toList()
|
|
|
|
if (notes.isEmpty()) return emptyList()
|
|
|
|
val tags = db.sequenceOf(Tags)
|
|
.filterColumns { listOf(it.noteUuid, it.name) }
|
|
.filter { it.noteUuid inList notes.map { it.uuid } }
|
|
.toList()
|
|
|
|
return notes.map { note ->
|
|
val noteTags = tags.asSequence()
|
|
.filter { it.note.uuid == note.uuid }
|
|
.map { it.name }
|
|
.toList()
|
|
|
|
BasicNoteDTO(note.uuid, note.title, noteTags, DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(note.updatedAt))
|
|
}
|
|
}
|
|
|
|
fun noteExists(userId: Int, uuid: UUID): Boolean {
|
|
return db.from(Notes)
|
|
.select(Notes.uuid)
|
|
.where { Notes.userId eq userId }
|
|
.where { Notes.uuid eq uuid }
|
|
.limit(0, 1)
|
|
.toList().size == 1
|
|
}
|
|
|
|
fun createNote(userId: Int, note: FullNoteCreateDTO): UUID {
|
|
val uuid = UUID.randomUUID()
|
|
db.useTransaction {
|
|
db.insert(Notes) {
|
|
it.uuid to uuid
|
|
it.title to note.title
|
|
it.userId to userId
|
|
it.updatedAt to LocalDateTime.now()
|
|
}
|
|
|
|
db.batchInsert(Tags) {
|
|
note.tags.forEach { tagName ->
|
|
item {
|
|
it.noteUuid to uuid
|
|
it.name to tagName
|
|
}
|
|
}
|
|
}
|
|
|
|
db.batchInsert(Chapters) {
|
|
note.chapters.forEachIndexed { index, chapter ->
|
|
item {
|
|
it.noteUuid to uuid
|
|
it.title to chapter.title
|
|
it.number to index
|
|
it.content to chapter.content
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return uuid
|
|
}
|
|
|
|
fun getNote(noteUuid: UUID): FullNoteDTO {
|
|
val note = db.sequenceOf(Notes)
|
|
.filterColumns { listOf(it.title, it.updatedAt) }
|
|
.find { it.uuid eq noteUuid } ?: error("Note not found")
|
|
|
|
val tags = db.from(Tags)
|
|
.select(Tags.name)
|
|
.where { Tags.noteUuid eq noteUuid }
|
|
.map { it[Tags.name]!! }
|
|
.toList()
|
|
|
|
val chapters = db.from(Chapters)
|
|
.select(Chapters.title, Chapters.content)
|
|
.where { Chapters.noteUuid eq noteUuid }
|
|
.orderBy(Chapters.number.asc())
|
|
.map { ChapterDTO(it[Chapters.title]!!, it[Chapters.content]!!) }
|
|
.toList()
|
|
|
|
val updatedAtFormatted = DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(note.updatedAt)
|
|
return FullNoteDTO(
|
|
uuid = noteUuid,
|
|
title = note.title,
|
|
updatedAt = updatedAtFormatted,
|
|
tags = tags,
|
|
chapters = chapters
|
|
)
|
|
}
|
|
|
|
fun updateNote(patch: FullNotePatchDTO) {
|
|
if (patch.uuid == null) return
|
|
db.useTransaction {
|
|
if (patch.title != null) {
|
|
db.update(Notes) {
|
|
it.title to patch.title
|
|
it.updatedAt to LocalDateTime.now()
|
|
where { it.uuid eq patch.uuid }
|
|
}
|
|
}
|
|
|
|
if (patch.tags != null) {
|
|
// delete all tags
|
|
db.delete(Tags) {
|
|
it.noteUuid eq patch.uuid
|
|
}
|
|
|
|
// put new ones
|
|
patch.tags.forEach { tagName ->
|
|
db.insert(Tags) {
|
|
it.name to tagName
|
|
it.noteUuid to patch.uuid
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TODO("get chapters")
|
|
}
|
|
|
|
fun deleteNote(noteUuid: UUID): Unit =
|
|
db.useTransaction {
|
|
db.delete(Notes) { it.uuid eq noteUuid }
|
|
}
|
|
|
|
fun getTags(userId: Int): List<String> = db.from(Tags)
|
|
.leftJoin(Notes, on = Tags.noteUuid eq Notes.uuid)
|
|
.select(Tags.name)
|
|
.where { Notes.userId eq userId }
|
|
.map { it[Tags.name]!! }
|
|
}
|
|
|
|
data class ChapterDTO(
|
|
val title: String,
|
|
val content: String
|
|
)
|
|
|
|
data class FullNoteDTO(
|
|
val uuid: UUID,
|
|
val title: String,
|
|
val updatedAt: String,
|
|
val tags: List<String>,
|
|
val chapters: List<ChapterDTO>
|
|
)
|
|
|
|
data class FullNoteCreateDTO(
|
|
val title: String,
|
|
val tags: List<String>,
|
|
val chapters: List<ChapterDTO>
|
|
)
|
|
|
|
data class FullNotePatchDTO(
|
|
val uuid: UUID? = null,
|
|
val title: String? = null,
|
|
val updatedAt: String? = null,
|
|
val tags: List<String>? = null,
|
|
val chapters: List<ChapterDTO>? = null
|
|
)
|
|
|
|
data class BasicNoteDTO(
|
|
val uuid: UUID,
|
|
val title: String,
|
|
val tags: List<String>,
|
|
val updatedAt: String
|
|
) |