feature: get migrations from DB
This commit is contained in:
@@ -1,15 +1,16 @@
|
||||
package fr.postgresjson.migration
|
||||
|
||||
import fr.postgresjson.connexion.Connection
|
||||
import java.util.*
|
||||
import fr.postgresjson.definition.Function as DefinitionFunction
|
||||
|
||||
class Function(
|
||||
val up: DefinitionFunction,
|
||||
val down: DefinitionFunction,
|
||||
private val connection: Connection
|
||||
private val connection: Connection,
|
||||
override var executedAt: Date? = null
|
||||
): Migration {
|
||||
val name = up.name
|
||||
enum class Status(i: Int) { OK(2), UP_FAIL(0), DOWN_FAIL(1) }
|
||||
|
||||
init {
|
||||
if (up.name !== down.name) {
|
||||
@@ -17,32 +18,51 @@ class Function(
|
||||
}
|
||||
}
|
||||
|
||||
override fun up(): Int {
|
||||
constructor(
|
||||
up: String,
|
||||
down: String,
|
||||
connection: Connection,
|
||||
executedAt: Date? = null):
|
||||
this(
|
||||
DefinitionFunction(up),
|
||||
DefinitionFunction(down),
|
||||
connection,
|
||||
executedAt
|
||||
)
|
||||
|
||||
override fun up(): Migration.Status {
|
||||
connection.exec(up.script)
|
||||
return 1
|
||||
// TODO insert to migration Table
|
||||
return Migration.Status.OK
|
||||
}
|
||||
|
||||
override fun down(): Int {
|
||||
override fun down(): Migration.Status {
|
||||
connection.exec(down.script)
|
||||
return 1
|
||||
// TODO insert to migration Table
|
||||
return Migration.Status.OK
|
||||
}
|
||||
|
||||
override fun test(): Int {
|
||||
override fun test(): Migration.Status {
|
||||
connection.inTransaction {
|
||||
connection.exec(up.script)
|
||||
connection.exec(down.script)
|
||||
up()
|
||||
down()
|
||||
it.sendQuery("ROLLBACK");
|
||||
}
|
||||
return 1
|
||||
}.join()
|
||||
|
||||
return Migration.Status.OK // TODO
|
||||
}
|
||||
|
||||
override fun status(): Int {
|
||||
override fun status(): Migration.Status {
|
||||
val result = connection.inTransaction {
|
||||
connection.exec(up.script)
|
||||
connection.exec(down.script)
|
||||
up()
|
||||
down()
|
||||
it.sendQuery("ROLLBACK")
|
||||
}.join()
|
||||
|
||||
return result.rowsAffected.toInt()
|
||||
return Migration.Status.OK // TODO
|
||||
}
|
||||
|
||||
override fun doExecute(): Boolean {
|
||||
return executedAt === null
|
||||
}
|
||||
}
|
||||
@@ -2,24 +2,68 @@ package fr.postgresjson.migration
|
||||
|
||||
import com.github.jasync.sql.db.util.size
|
||||
import fr.postgresjson.connexion.Connection
|
||||
import fr.postgresjson.entity.Entity
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.util.*
|
||||
import fr.postgresjson.definition.Function as DefinitionFunction
|
||||
|
||||
class MigrationEntity(
|
||||
val filename: String,
|
||||
val definition: String,
|
||||
val executedAt: Date,
|
||||
val up: String,
|
||||
val down: String,
|
||||
val version: Int
|
||||
): Entity<String?>(filename) {
|
||||
|
||||
interface Migration {
|
||||
fun up(): Int
|
||||
fun down(): Int
|
||||
fun test(): Int
|
||||
fun status(): Int
|
||||
}
|
||||
|
||||
class Migrations(directory: File, private val connection: Connection): Migration {
|
||||
private val queries: MutableList<Query> = mutableListOf()
|
||||
interface Migration {
|
||||
var executedAt: Date?
|
||||
fun up(): Status
|
||||
fun down(): Status
|
||||
fun test(): Status
|
||||
fun status(): Status
|
||||
fun doExecute(): Boolean
|
||||
|
||||
enum class Status(i: Int) { OK(2), UP_FAIL(0), DOWN_FAIL(1) }
|
||||
}
|
||||
|
||||
class Migrations(directory: File, private val connection: Connection) {
|
||||
private val queries: MutableMap<String, Query> = mutableMapOf()
|
||||
private val functions: MutableMap<String, Function> = mutableMapOf()
|
||||
private var initialized = false
|
||||
|
||||
init {
|
||||
initDB()
|
||||
getMigrationFromDB()
|
||||
getMigrationFromDirectory(directory)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all migration from DB
|
||||
*/
|
||||
private fun getMigrationFromDB() {
|
||||
File(this::class.java.getResource("/sql/migration/findAllFunction.sql").toURI()).let {
|
||||
connection.select<String, List<MigrationEntity?>>(it.readText())
|
||||
.filterNotNull().map { function ->
|
||||
functions[function.filename] = Function(function.up, function.down, connection, function.executedAt)
|
||||
}
|
||||
}
|
||||
|
||||
File(this::class.java.getResource("/sql/migration/findAllHistory.sql").toURI()).let {
|
||||
connection.select<String, List<MigrationEntity?>>(it.readText())
|
||||
.filterNotNull().map { query ->
|
||||
queries[query.filename] = Query(query.filename, query.up, query.down, connection, query.executedAt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all migration from Directory
|
||||
*/
|
||||
private fun getMigrationFromDirectory(directory: File) {
|
||||
directory.walk().filter {
|
||||
it.isDirectory
|
||||
}.forEach { directory ->
|
||||
@@ -31,7 +75,8 @@ class Migrations(directory: File, private val connection: Connection): Migration
|
||||
try {
|
||||
val down = File("$it.down.sql").readText()
|
||||
val up = file.readText()
|
||||
addQuery(file.name, up, down)
|
||||
val name = file.name.substring(0, file.name.size - 7)
|
||||
addQuery(name, up, down)
|
||||
} catch (e: FileNotFoundException) {
|
||||
throw DownMigrationNotDefined("$it.down.sql", e)
|
||||
}
|
||||
@@ -46,22 +91,25 @@ class Migrations(directory: File, private val connection: Connection): Migration
|
||||
}
|
||||
}
|
||||
|
||||
enum class Direction { UP, DOWN }
|
||||
class DownMigrationNotDefined(path: String, cause: FileNotFoundException): Throwable("The file $path whas not found", cause)
|
||||
|
||||
fun addFunction(definition: DefinitionFunction): Migrations {
|
||||
functions[definition.name] = Function(definition, definition, connection)
|
||||
return this
|
||||
}
|
||||
|
||||
fun addFunction(sql: String): Migrations {
|
||||
DefinitionFunction(sql).let {
|
||||
functions[it.name] = Function(it, it, connection)
|
||||
if (functions[definition.name] === null) {
|
||||
functions[definition.name] = Function(definition, definition, connection)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
fun addFunction(sql: String): Migrations {
|
||||
addFunction(DefinitionFunction(sql))
|
||||
return this
|
||||
}
|
||||
|
||||
fun addQuery(name: String, up: String, down: String): Migrations {
|
||||
queries.add(Query(name, up, down, connection))
|
||||
if (queries[name] === null) {
|
||||
queries[name] = Query(name, up, down, connection)
|
||||
}
|
||||
return this
|
||||
}
|
||||
|
||||
@@ -77,42 +125,73 @@ class Migrations(directory: File, private val connection: Connection): Migration
|
||||
}
|
||||
}
|
||||
|
||||
override fun up(): Int {
|
||||
initDB()
|
||||
var count = 0
|
||||
fun up(): Map<String, Migration.Status> {
|
||||
val list: MutableMap<String, Migration.Status> = mutableMapOf()
|
||||
queries.forEach {
|
||||
it.up()
|
||||
++count
|
||||
it.value.let { query ->
|
||||
if (query.doExecute()) {
|
||||
query.up().let { status ->
|
||||
list[query.name] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
}
|
||||
|
||||
override fun down(): Int {
|
||||
initDB()
|
||||
var count = 0
|
||||
queries.forEach {
|
||||
it.down()
|
||||
++count
|
||||
functions.forEach {
|
||||
it.value.let { function ->
|
||||
if (function.doExecute()) {
|
||||
function.up().let { status ->
|
||||
list[function.name] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return count
|
||||
return list.toMap()
|
||||
}
|
||||
|
||||
override fun test(): Int {
|
||||
initDB()
|
||||
var count = 0
|
||||
fun down(): Map<String, Migration.Status> {
|
||||
val list: MutableMap<String, Migration.Status> = mutableMapOf()
|
||||
queries.forEach {
|
||||
it.value.let { query ->
|
||||
if (query.doExecute()) {
|
||||
query.down().let { status ->
|
||||
list[query.name] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
functions.forEach {
|
||||
it.value.let { function ->
|
||||
if (function.doExecute()) {
|
||||
function.down().let { status ->
|
||||
list[function.name] = status
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return list.toMap()
|
||||
}
|
||||
|
||||
fun test(): Map<Pair<String, Direction>, Migration.Status> {
|
||||
var list: MutableMap<Pair<String, Direction>, Migration.Status> = mutableMapOf()
|
||||
connection.inTransaction {
|
||||
count += up()
|
||||
count += down()
|
||||
up().map {
|
||||
list.set(Pair(it.key, Direction.UP), it.value)
|
||||
}
|
||||
down().map {
|
||||
list.set(Pair(it.key, Direction.DOWN), it.value)
|
||||
}
|
||||
|
||||
it.sendQuery("ROLLBACK");
|
||||
}.join()
|
||||
|
||||
return count
|
||||
return list.toMap()
|
||||
}
|
||||
|
||||
override fun status(): Int {
|
||||
initDB()
|
||||
fun status(): Map<String, Int> {
|
||||
TODO("not implemented")
|
||||
}
|
||||
}
|
||||
@@ -1,41 +1,51 @@
|
||||
package fr.postgresjson.migration
|
||||
|
||||
import fr.postgresjson.connexion.Connection
|
||||
import fr.postgresjson.entity.Entity
|
||||
import java.util.*
|
||||
|
||||
class Query(
|
||||
val name: String,
|
||||
val up: String,
|
||||
val down: String,
|
||||
private val connection: Connection
|
||||
): Migration {
|
||||
enum class Status(i: Int) { OK(2), UP_FAIL(0), DOWN_FAIL(1) }
|
||||
|
||||
override fun up(): Int {
|
||||
private val connection: Connection,
|
||||
override var executedAt: Date? = null
|
||||
): Migration, Entity<String?>(name) {
|
||||
override fun up(): Migration.Status {
|
||||
connection.exec(up)
|
||||
return 1
|
||||
// TODO insert to migration Table
|
||||
|
||||
return Migration.Status.OK
|
||||
}
|
||||
|
||||
override fun down(): Int {
|
||||
override fun down(): Migration.Status {
|
||||
connection.exec(down)
|
||||
return 1
|
||||
// TODO insert to migration Table
|
||||
|
||||
return Migration.Status.OK
|
||||
}
|
||||
|
||||
override fun test(): Int {
|
||||
override fun test(): Migration.Status {
|
||||
connection.inTransaction {
|
||||
connection.exec(up)
|
||||
connection.exec(down)
|
||||
up()
|
||||
down()
|
||||
it.sendQuery("ROLLBACK");
|
||||
}
|
||||
return 1
|
||||
}.join()
|
||||
|
||||
return Migration.Status.OK // TODO
|
||||
}
|
||||
|
||||
override fun status(): Int {
|
||||
override fun status(): Migration.Status {
|
||||
val result = connection.inTransaction {
|
||||
connection.exec(up)
|
||||
connection.exec(down)
|
||||
up()
|
||||
down()
|
||||
it.sendQuery("ROLLBACK")
|
||||
}.join()
|
||||
|
||||
return result.rowsAffected.toInt()
|
||||
return Migration.Status.OK // TODO
|
||||
}
|
||||
|
||||
override fun doExecute(): Boolean {
|
||||
return executedAt === null
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package fr.postgresjson
|
||||
|
||||
import fr.postgresjson.migration.Migration
|
||||
import fr.postgresjson.migration.Migrations
|
||||
import org.amshove.kluent.`should be equal to`
|
||||
import org.amshove.kluent.`should contain`
|
||||
import org.amshove.kluent.invoking
|
||||
import org.amshove.kluent.shouldThrow
|
||||
import org.junit.jupiter.api.Test
|
||||
@@ -14,7 +16,8 @@ class MigrationTest(): TestAbstract() {
|
||||
fun upQuery() {
|
||||
val resources = File(this::class.java.getResource("/sql/migrations").toURI())
|
||||
val m = Migrations(resources, getConnextion())
|
||||
m.up() `should be equal to` 1
|
||||
m.up() `should contain` Pair("1", Migration.Status.OK)
|
||||
m.up().size `should be equal to` 1
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -29,14 +32,15 @@ class MigrationTest(): TestAbstract() {
|
||||
fun downQuery() {
|
||||
val resources = File(this::class.java.getResource("/sql/migrations").toURI())
|
||||
val m = Migrations(resources, getConnextion())
|
||||
m.down() `should be equal to` 1
|
||||
m.down() `should contain` Pair("1", Migration.Status.OK)
|
||||
m.down().size `should be equal to` 1
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test up and down migrations`() {
|
||||
val resources = File(this::class.java.getResource("/sql/real_migrations").toURI())
|
||||
val m = Migrations(resources, getConnextion())
|
||||
m.test() `should be equal to` 2
|
||||
m.test() `should be equal to` 2
|
||||
m.test().size `should be equal to` 2
|
||||
m.test().size `should be equal to` 2
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
drop schema public cascade;
|
||||
create schema if not exists public;
|
||||
drop schema if exists public cascade;
|
||||
create schema if not exists public;
|
||||
drop schema if exists migration cascade;
|
||||
Reference in New Issue
Block a user