From 3dc988573d607a36ed793747ebb32c20346040de Mon Sep 17 00:00:00 2001 From: aminecmi Date: Fri, 12 Aug 2022 21:38:15 +0200 Subject: [PATCH] Migrations. Fixing the ordering. --- src/main/kotlin/MigrationsController.kt | 72 +++++++++++++++++++++++++ src/main/kotlin/dao/DB.kt | 35 +++++------- src/main/kotlin/dao/Items.kt | 2 +- src/main/kotlin/dao/Migrations.kt | 24 +++++++++ src/main/kotlin/server.kt | 8 +-- 5 files changed, 114 insertions(+), 27 deletions(-) create mode 100644 src/main/kotlin/MigrationsController.kt create mode 100644 src/main/kotlin/dao/Migrations.kt diff --git a/src/main/kotlin/MigrationsController.kt b/src/main/kotlin/MigrationsController.kt new file mode 100644 index 0000000..a3407eb --- /dev/null +++ b/src/main/kotlin/MigrationsController.kt @@ -0,0 +1,72 @@ +import dao.* +import org.jetbrains.exposed.sql.and +import org.jetbrains.exposed.sql.selectAll +import org.jetbrains.exposed.sql.transactions.transaction +import org.jetbrains.exposed.sql.update + +class MigrationsController { + private val migrations: Map Boolean> = mapOf( + "update-checked-null-position" to {updateNullPositionForChecked()}, + "update-unchecked-position" to {updatePositionForUnchecked()} + ) + + fun checkMigrationsToDo() { + this.migrations.forEach { + transaction { + val migrationWithName = Migration.find { Migrations.identifier eq it.key }.firstOrNull() + if (migrationWithName == null) { + Migration.new { + identifier = it.key + } + println("Migration ${it.key} will start now.") + it.value() + Migrations.update({Migrations.identifier eq it.key}) { + it[done] = true + } + println("Migration ${it.key} done.") + } else if (!migrationWithName.done) { + println("Migration ${it.key} not done yet. Redoing.") + it.value() + Migrations.update({Migrations.identifier eq it.key}) { + it[done] = true + } + println("Migration ${it.key} done.") + } else { + println("Migration ${it.key} done.") + } + } + } + } + + private fun updateNullPositionForChecked() : Boolean { + try { + transaction { + Items.update({ Items.checked eq true }) { + it[position] = null + } + } + } catch (e: Exception) { + return false + } + return true + } + + private fun updatePositionForUnchecked() : Boolean { + try { + transaction { + Lists.selectAll().forEach { + var i = 0 + Item.find { Items.list eq it[Lists.id].value and (Items.checked eq false) } + .sortedBy { it.position } + .forEach { + it.position = i + i++ + } + } + } + } catch (e: Exception) { + return false + } + return true + } +} \ No newline at end of file diff --git a/src/main/kotlin/dao/DB.kt b/src/main/kotlin/dao/DB.kt index 50f57eb..8a279c2 100644 --- a/src/main/kotlin/dao/DB.kt +++ b/src/main/kotlin/dao/DB.kt @@ -81,17 +81,15 @@ class DB { fun createItem(listId: Int, c: ItemView, ctx: Context) { transaction { - val allITems = Item.find { Items.list eq listId }.sortedBy { it.position } - val firstChecked = allITems.firstOrNull { it.checked } - val p = firstChecked?.position ?: ((allITems.lastOrNull()?.position ?: - 1) + 1) val listOpt = List.findById(listId) if (listOpt != null) { - reorderElements(listId, p) + val count = Item.find { Items.list eq listId and (Items.checked eq false) }.count() + val p = (count + 1) var i = Item.new { list = listId content = c.content - position = p + position = p.toInt() checked = false } @@ -106,7 +104,7 @@ class DB { private fun reorderElements(listId: Int, position: Int, itemId: Int? = null) { transaction { var i = 0 - Item.find { Items.list eq listId and (Items.id neq itemId) } + Item.find { Items.list eq listId and (Items.id neq itemId and (Items.checked eq false)) } .sortedBy { it.position } .forEach { if (i == position) { @@ -147,25 +145,18 @@ class DB { if (listOpt != null) { val item = Item.find { Items.list eq listId and (Items.id eq itemId) }.limit(1).firstOrNull() if (item != null) { - var p = body.position + if (body.position != null) { + reorderElements(listId, body.position, itemId) + item.position = body.position + } if (body.checked != null) { - val allITems = Item.find { Items.list eq listId }.sortedBy { it.position } - val firstChecked = allITems.firstOrNull { it.checked } - p = if (body.checked) { - if (firstChecked != null) { - firstChecked.position - 1 - } else { - allITems.lastOrNull()?.position - } + var p: Int? = if (body.checked) { + (Item.find { Items.list eq listId and (Items.checked eq false) }.count() + 1).toInt() } else { - firstChecked?.position ?: allITems.lastOrNull()?.position - } - - item.checked = body.checked - } - if (p != null) { - reorderElements(listId, p, itemId) + null + } item.position = p + item.checked = body.checked } if (body.content != null) { item.content = body.content diff --git a/src/main/kotlin/dao/Items.kt b/src/main/kotlin/dao/Items.kt index d9b8aef..991217a 100644 --- a/src/main/kotlin/dao/Items.kt +++ b/src/main/kotlin/dao/Items.kt @@ -8,7 +8,7 @@ import org.jetbrains.exposed.dao.id.IntIdTable object Items : IntIdTable() { val list = integer("list") val content = varchar("content", 256) - val position = integer("position") + val position = integer("position").nullable() val checked = bool("checked").default(false) } diff --git a/src/main/kotlin/dao/Migrations.kt b/src/main/kotlin/dao/Migrations.kt new file mode 100644 index 0000000..cf83eb3 --- /dev/null +++ b/src/main/kotlin/dao/Migrations.kt @@ -0,0 +1,24 @@ +package dao + +import org.jetbrains.exposed.dao.IntEntity +import org.jetbrains.exposed.dao.IntEntityClass +import org.jetbrains.exposed.dao.id.EntityID +import org.jetbrains.exposed.dao.id.IntIdTable + +object Migrations : IntIdTable() { + val identifier = varchar("identifier", 256) + val done = bool("done").default(false) +} + +class Migration(id: EntityID) : IntEntity(id) { + companion object : IntEntityClass(Migrations) + + var identifier by Migrations.identifier + var done by Migrations.done +} + +fun Migration.toView(): MigrationView { + return MigrationView(this.id.value, this.identifier, this.done) +} + +data class MigrationView(val id: Int, val identifier: String, val done: Boolean = false) \ No newline at end of file diff --git a/src/main/kotlin/server.kt b/src/main/kotlin/server.kt index 4002370..4faefb3 100644 --- a/src/main/kotlin/server.kt +++ b/src/main/kotlin/server.kt @@ -1,7 +1,4 @@ -import dao.Items -import dao.Key -import dao.Keys -import dao.Lists +import dao.* import io.javalin.Javalin import io.javalin.apibuilder.ApiBuilder.* import io.javalin.core.security.Role @@ -15,6 +12,7 @@ import org.jetbrains.exposed.sql.transactions.transaction enum class ApiRole : Role { PUBLIC, BASIC_AUTHED, API_AUTHED } fun main() { + var migrationsController = MigrationsController() val app = Javalin.create { it.accessManager { handler, ctx, permittedRoles -> transaction { @@ -36,6 +34,8 @@ fun main() { Database.connect("jdbc:sqlite:data.db", "org.sqlite.JDBC") transaction { addLogger(StdOutSqlLogger) + SchemaUtils.create (Migrations) + migrationsController.checkMigrationsToDo() SchemaUtils.create (Lists) SchemaUtils.create (Items) SchemaUtils.create (Keys)