238 lines
7.6 KiB
Kotlin
238 lines
7.6 KiB
Kotlin
package be.simplenotes.persistance.notes
|
|
|
|
import be.simplenotes.domain.model.*
|
|
import be.simplenotes.domain.usecases.repositories.NoteRepository
|
|
import me.liuwj.ktorm.database.Database
|
|
import me.liuwj.ktorm.dsl.*
|
|
import me.liuwj.ktorm.entity.*
|
|
import java.time.LocalDateTime
|
|
import java.util.*
|
|
import kotlin.collections.HashMap
|
|
|
|
internal class NoteRepositoryImpl(private val db: Database) : NoteRepository {
|
|
|
|
@Throws(IllegalArgumentException::class)
|
|
override fun findAll(
|
|
userId: Int,
|
|
limit: Int,
|
|
offset: Int,
|
|
tag: String?,
|
|
deleted: Boolean
|
|
): List<PersistedNoteMetadata> {
|
|
require(limit > 0) { "limit should be positive" }
|
|
require(offset >= 0) { "offset should not be negative" }
|
|
|
|
val uuids1: List<UUID>? = if (tag != null) {
|
|
db.from(Tags)
|
|
.leftJoin(Notes, on = Notes.uuid eq Tags.noteUuid)
|
|
.select(Notes.uuid)
|
|
.where { (Notes.userId eq userId) and (Tags.name eq tag) and (Notes.deleted eq deleted) }
|
|
.map { it[Notes.uuid]!! }
|
|
} else null
|
|
|
|
var query = db.notes
|
|
.filterColumns { listOf(it.uuid, it.title, it.updatedAt) }
|
|
.filter { (it.userId eq userId) and (it.deleted eq deleted) }
|
|
|
|
if (uuids1 != null) query = query.filter { it.uuid inList uuids1 }
|
|
|
|
val notes = query
|
|
.sortedByDescending { it.updatedAt }
|
|
.take(limit)
|
|
.drop(offset)
|
|
.toList()
|
|
|
|
val tagsByUuid = notes.tagsByUuid()
|
|
|
|
return notes.map { note ->
|
|
val tags = tagsByUuid[note.uuid] ?: emptyList()
|
|
note.toPersistedMetadata(tags)
|
|
}
|
|
}
|
|
|
|
override fun exists(userId: Int, uuid: UUID): Boolean {
|
|
return db.notes.any { (it.userId eq userId) and (it.uuid eq uuid) and (it.deleted eq false) }
|
|
}
|
|
|
|
override fun create(userId: Int, note: Note): PersistedNote {
|
|
val uuid = UUID.randomUUID()
|
|
val entity = note.toEntity(uuid, userId).apply {
|
|
this.updatedAt = LocalDateTime.now()
|
|
}
|
|
db.useTransaction {
|
|
db.notes.add(entity)
|
|
db.batchInsert(Tags) {
|
|
note.meta.tags.forEach { tagName ->
|
|
item {
|
|
it.noteUuid to uuid
|
|
it.name to tagName
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return entity.toPersistedNote(note.meta.tags)
|
|
}
|
|
|
|
override fun find(userId: Int, uuid: UUID): PersistedNote? {
|
|
val note = db.notes
|
|
.filterColumns { it.columns - it.userId }
|
|
.filter { it.uuid eq uuid }
|
|
.find { (it.userId eq userId) and (it.deleted eq false) }
|
|
?: return null
|
|
|
|
val tags = db.from(Tags)
|
|
.select(Tags.name)
|
|
.where { Tags.noteUuid eq uuid }
|
|
.map { it[Tags.name]!! }
|
|
|
|
return note.toPersistedNote(tags)
|
|
}
|
|
|
|
override fun update(userId: Int, uuid: UUID, note: Note): PersistedNote? {
|
|
db.useTransaction {
|
|
|
|
val now = LocalDateTime.now()
|
|
val count = db.update(Notes) {
|
|
it.title to note.meta.title
|
|
it.markdown to note.markdown
|
|
it.html to note.html
|
|
it.updatedAt to now
|
|
where { (it.uuid eq uuid) and (it.userId eq userId) and (it.deleted eq false) }
|
|
}
|
|
|
|
if (count == 0) return null
|
|
|
|
// delete all tags
|
|
db.delete(Tags) {
|
|
it.noteUuid eq uuid
|
|
}
|
|
|
|
// put new ones
|
|
note.meta.tags.forEach { tagName ->
|
|
db.insert(Tags) {
|
|
it.name to tagName
|
|
it.noteUuid to uuid
|
|
}
|
|
}
|
|
|
|
return PersistedNote(
|
|
meta = note.meta,
|
|
markdown = note.markdown,
|
|
html = note.html,
|
|
updatedAt = now,
|
|
uuid = uuid,
|
|
public = false, // TODO
|
|
)
|
|
}
|
|
}
|
|
|
|
override fun delete(userId: Int, uuid: UUID, permanent: Boolean): Boolean {
|
|
return if (!permanent) {
|
|
db.useTransaction {
|
|
db.update(Notes) {
|
|
it.deleted to true
|
|
it.updatedAt to LocalDateTime.now()
|
|
where { it.userId eq userId and (it.uuid eq uuid) }
|
|
}
|
|
} == 1
|
|
} else db.useTransaction {
|
|
db.delete(Notes) { it.uuid eq uuid and (it.userId eq userId) } == 1
|
|
}
|
|
}
|
|
|
|
override fun restore(userId: Int, uuid: UUID): Boolean {
|
|
return db.useTransaction {
|
|
db.update(Notes) {
|
|
it.deleted to false
|
|
where { (it.userId eq userId) and (it.uuid eq uuid) }
|
|
} == 1
|
|
}
|
|
}
|
|
|
|
override fun getTags(userId: Int): List<String> =
|
|
db.from(Tags)
|
|
.leftJoin(Notes, on = Notes.uuid eq Tags.noteUuid)
|
|
.selectDistinct(Tags.name)
|
|
.where { (Notes.userId eq userId) and (Notes.deleted eq false) }
|
|
.map { it[Tags.name]!! }
|
|
|
|
override fun count(userId: Int, tag: String?, deleted: Boolean): Int {
|
|
return if (tag == null) db.notes.count { (it.userId eq userId) and (Notes.deleted eq deleted) }
|
|
else db.sequenceOf(Tags).count {
|
|
(it.name eq tag) and (it.note.userId eq userId) and (it.note.deleted eq deleted)
|
|
}
|
|
}
|
|
|
|
override fun export(userId: Int): List<ExportedNote> {
|
|
|
|
val notes = db.notes
|
|
.filterColumns { it.columns - it.userId }
|
|
.filter { it.userId eq userId }
|
|
.sortedByDescending { it.updatedAt }
|
|
.toList()
|
|
|
|
val tagsByUuid = notes.tagsByUuid()
|
|
|
|
return notes.map { note ->
|
|
ExportedNote(
|
|
title = note.title,
|
|
tags = tagsByUuid[note.uuid] ?: emptyList(),
|
|
markdown = note.markdown,
|
|
html = note.html,
|
|
updatedAt = note.updatedAt,
|
|
trash = note.deleted,
|
|
)
|
|
}
|
|
}
|
|
|
|
override fun findAllDetails(userId: Int): List<PersistedNote> {
|
|
val notes = db.notes
|
|
.filterColumns { it.columns - it.deleted }
|
|
.filter { (it.userId eq userId) and (it.deleted eq false) }
|
|
.toList()
|
|
|
|
val tagsByUuid = notes.tagsByUuid()
|
|
|
|
return notes.map { note ->
|
|
val tags = tagsByUuid[note.uuid] ?: emptyList()
|
|
note.toPersistedNote(tags)
|
|
}
|
|
}
|
|
|
|
override fun makePublic(userId: Int, uuid: UUID) = db.update(Notes) {
|
|
it.public to true
|
|
where { Notes.userId eq userId and (Notes.uuid eq uuid) and (it.deleted eq false) }
|
|
} == 1
|
|
|
|
override fun makePrivate(userId: Int, uuid: UUID) = db.update(Notes) {
|
|
it.public to false
|
|
where { Notes.userId eq userId and (Notes.uuid eq uuid) and (it.deleted eq false) }
|
|
} == 1
|
|
|
|
override fun findPublic(uuid: UUID): PersistedNote? {
|
|
val note = db.notes
|
|
.filterColumns { it.columns - it.userId }
|
|
.filter { it.uuid eq uuid }
|
|
.filter { it.public eq true }
|
|
.find { it.deleted eq false }
|
|
?: return null
|
|
|
|
val tags = db.from(Tags)
|
|
.select(Tags.name)
|
|
.where { Tags.noteUuid eq uuid }
|
|
.map { it[Tags.name]!! }
|
|
|
|
return note.toPersistedNote(tags)
|
|
}
|
|
|
|
private fun List<NoteEntity>.tagsByUuid(): Map<UUID, List<String>> {
|
|
return if (isEmpty()) emptyMap()
|
|
else db.tags
|
|
.filterColumns { listOf(it.noteUuid, it.name) }
|
|
.filter { it.noteUuid inList map { note -> note.uuid } }
|
|
.groupByTo(HashMap(), { it.note.uuid }, { it.name })
|
|
}
|
|
|
|
}
|