SimpleNotes/api/src/services/NotesService.kt

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
)