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