diff --git a/dbmigration-test/resources/dbmigration/myapp/migration-current.xml b/dbmigration-test/resources/dbmigration/myapp/migration-current.xml
new file mode 100644
index 000000000..bda435bc4
--- /dev/null
+++ b/dbmigration-test/resources/dbmigration/myapp/migration-current.xml
@@ -0,0 +1,1311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ms-migration.xml b/ms-migration.xml
new file mode 100644
index 000000000..339a4c535
--- /dev/null
+++ b/ms-migration.xml
@@ -0,0 +1,1311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/mysql-migration.xml b/mysql-migration.xml
new file mode 100644
index 000000000..a676629fb
--- /dev/null
+++ b/mysql-migration.xml
@@ -0,0 +1,1311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ora-migration.xml b/ora-migration.xml
new file mode 100644
index 000000000..f2df70ed6
--- /dev/null
+++ b/ora-migration.xml
@@ -0,0 +1,1311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/avaje/ebean/config/DbMigrationConfig.java b/src/main/java/com/avaje/ebean/config/DbMigrationConfig.java
new file mode 100644
index 000000000..030b026f6
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/config/DbMigrationConfig.java
@@ -0,0 +1,42 @@
+package com.avaje.ebean.config;
+
+/**
+ * Configuration for the DB migration processing.
+ */
+public class DbMigrationConfig {
+
+ /**
+ * The application name which is used as the unique code when applying migrations.
+ */
+ private String appName;
+
+ /**
+ * Path where migration
+ */
+ private String resourcePath;
+
+ public String getAppName() {
+ return appName;
+ }
+
+ public void setAppName(String appName) {
+ this.appName = appName;
+ }
+
+ public String getResourcePath() {
+ return resourcePath;
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ /**
+ * Load the settings from the PropertiesWrapper.
+ */
+ public void loadSettings(PropertiesWrapper properties) {
+
+ appName = properties.get("migration.appName", appName);
+ resourcePath = properties.get("migration.resourcePath", resourcePath);
+ }
+}
diff --git a/src/main/java/com/avaje/ebean/config/ServerConfig.java b/src/main/java/com/avaje/ebean/config/ServerConfig.java
index 47a86d573..29f9affe4 100644
--- a/src/main/java/com/avaje/ebean/config/ServerConfig.java
+++ b/src/main/java/com/avaje/ebean/config/ServerConfig.java
@@ -207,6 +207,11 @@ public class ServerConfig {
*/
private DataSourceConfig dataSourceConfig = new DataSourceConfig();
+ /**
+ * The db migration config (migration resource path etc).
+ */
+ private DbMigrationConfig migrationConfig = new DbMigrationConfig();
+
/**
* Set to true if the DataSource uses autoCommit.
*
@@ -502,7 +507,7 @@ public class ServerConfig {
/**
* Return the JDBC batch mode to use per save(), delete(), insert() or update() request.
*
- * This makes sense when a save() or delete() etc cascades and executes multiple child statements. The best caase
+ * This makes sense when a save() or delete() cascades and executes multiple child statements. The best case
* for this is when saving a master/parent bean this cascade inserts many detail/child beans.
*
*
@@ -620,6 +625,20 @@ public class ServerConfig {
this.databaseSequenceBatchSize = databaseSequenceBatchSize;
}
+ /**
+ * Return the DB migration configuration.
+ */
+ public DbMigrationConfig getMigrationConfig() {
+ return migrationConfig;
+ }
+
+ /**
+ * Set the DB migration configuration.
+ */
+ public void setMigrationConfig(DbMigrationConfig migrationConfig) {
+ this.migrationConfig = migrationConfig;
+ }
+
/**
* Return the suffix appended to the base table to derive the view that contains the union
* of the base table and the history table in order to support asOf queries.
@@ -1856,6 +1875,8 @@ public class ServerConfig {
*/
protected void loadSettings(PropertiesWrapper p) {
+ migrationConfig.loadSettings(p);
+
namingConvention = createNamingConvention(p, namingConvention);
if (namingConvention != null) {
namingConvention.loadFromProperties(p);
diff --git a/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java
new file mode 100644
index 000000000..6163ec561
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/dbmigration/DbMigration.java
@@ -0,0 +1,56 @@
+package com.avaje.ebean.dbmigration;
+
+import com.avaje.ebean.Ebean;
+import com.avaje.ebean.EbeanServer;
+import com.avaje.ebean.config.DbMigrationConfig;
+import com.avaje.ebean.dbmigration.model.CurrentModel;
+import com.avaje.ebeaninternal.api.SpiEbeanServer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+
+/**
+ *
+ */
+public class DbMigration {
+
+ private static final Logger logger = LoggerFactory.getLogger(DbMigration.class);
+
+ private final SpiEbeanServer server;
+
+ private final DbMigrationConfig migrationConfig;
+
+ public DbMigration() {
+ this(Ebean.getDefaultServer());
+ }
+
+ public DbMigration(EbeanServer ebeanServer) {
+ this.server = (SpiEbeanServer) ebeanServer;
+ this.migrationConfig = server.getServerConfig().getMigrationConfig();
+ }
+
+
+
+ public void writeCurrent() {
+
+ CurrentModel currentModel = new CurrentModel(server);
+
+ File writeTo = getWritePath();
+ logger.info("... write to {}", writeTo.getAbsolutePath());
+ currentModel.writeMigration(writeTo);
+ }
+
+ public File getWritePath() {
+ File resourceRootDir = new File("./dbmigration-test/resources");
+
+ // expect to be a relative path
+ String resourcePath = migrationConfig.getResourcePath();
+
+ File path = new File(resourceRootDir, resourcePath);
+ if (!path.exists()) {
+ path.mkdirs();
+ }
+ return new File(path, "migration-current.xml");
+ }
+}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java b/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java
new file mode 100644
index 000000000..b65fa303d
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/dbmigration/DbOffline.java
@@ -0,0 +1,37 @@
+package com.avaje.ebean.dbmigration;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ */
+public class DbOffline {
+
+ private static final Logger logger = LoggerFactory.getLogger(DbOffline.class);
+
+ private static final String KEY = "ebean.dboffline";
+
+ public static final String H2 = "H2";
+
+ public static void setPlatform(String platformName) {
+ System.setProperty(KEY, platformName);
+ }
+
+ public static String getPlatform() {
+ return System.getProperty(KEY);
+ }
+
+ public static void asH2() {
+ setPlatform(H2);
+ }
+
+ public static boolean isSet() {
+ return getPlatform() != null;
+ }
+
+ public static void reset() {
+ System.clearProperty(KEY);
+ logger.info("reset");
+ }
+}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java
index d627c5458..edf2cb695 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/BaseDdlHandler.java
@@ -5,6 +5,7 @@ import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseTableDdl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DdlNamingConvention;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import com.avaje.ebean.dbmigration.migration.AddColumn;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
@@ -23,7 +24,7 @@ public class BaseDdlHandler implements DdlHandler {
public BaseDdlHandler(DdlNamingConvention namingConvention, PlatformDdl platformDdl) {
this.tableDdl = new BaseTableDdl(namingConvention, platformDdl);
- this.columnDdl = new BaseColumnDdl();
+ this.columnDdl = new BaseColumnDdl(platformDdl);
}
@Override
@@ -37,6 +38,8 @@ public class BaseDdlHandler implements DdlHandler {
generate(writer, (AddColumn) change);
} else if (change instanceof DropColumn) {
generate(writer, (DropColumn) change);
+ } else if (change instanceof AlterColumn) {
+ generate(writer, (AlterColumn) change);
}
}
}
@@ -56,4 +59,8 @@ public class BaseDdlHandler implements DdlHandler {
columnDdl.generate(writer, dropColumn);
}
+ @Override
+ public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
+ columnDdl.generate(writer, alterColumn);
+ }
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/ColumnDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/ColumnDdl.java
index 00192f92a..ade0ee159 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/ColumnDdl.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/ColumnDdl.java
@@ -1,23 +1,28 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.io.IOException;
/**
- * Write AddColumn or DropColumn.
+ * Write DDL for AddColumn , DropColumn or AlterColumn.
*/
public interface ColumnDdl {
/**
- * Write a AddColumn change.
+ * Write the add column change.
*/
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
/**
- * Write a DropColumn change.
+ * Write the drop column change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
+ /**
+ * Write the alter column changes.
+ */
+ void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/DdlHandler.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/DdlHandler.java
index 715657724..fa5f7b043 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/DdlHandler.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/DdlHandler.java
@@ -1,6 +1,7 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
@@ -18,4 +19,7 @@ public interface DdlHandler {
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
-}
+
+ void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java
index e92f2593c..f7416ff48 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseColumnDdl.java
@@ -4,6 +4,7 @@ import com.avaje.ebean.dbmigration.ddlgeneration.ColumnDdl;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.AddColumn;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.Column;
import com.avaje.ebean.dbmigration.migration.DropColumn;
@@ -14,6 +15,11 @@ import java.util.List;
*/
public class BaseColumnDdl implements ColumnDdl {
+ protected final PlatformDdl platformDdl;
+
+ public BaseColumnDdl(PlatformDdl platformDdl) {
+ this.platformDdl = platformDdl;
+ }
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
@@ -40,6 +46,89 @@ public class BaseColumnDdl implements ColumnDdl {
// are put into a separate changeSet that is run last
}
+ @Override
+ public void generate(DdlWrite writer, AlterColumn alterColumn) throws IOException {
+
+ if (isTrue(alterColumn.isHistoryExclude())) {
+ historyExcludeColumn(writer, alterColumn);
+ } else if (isFalse(alterColumn.isHistoryExclude())) {
+ historyIncludeColumn(writer, alterColumn);
+ }
+
+ if (hasValue(alterColumn.getOldReferences())) {
+ dropForeignKey(writer, alterColumn);
+ }
+ if (hasValue(alterColumn.getNewReferences())) {
+ addForeignKey(writer, alterColumn);
+ }
+
+ if (isTrue(alterColumn.isUnique())) {
+ addUniqueConstraint(writer, alterColumn);
+ } else if (isFalse(alterColumn.isUnique())) {
+ dropUniqueConstraint(writer, alterColumn);
+ }
+
+ if (isTrue(alterColumn.isUniqueOneToOne())) {
+ addUniqueOneToOneConstraint(writer, alterColumn);
+ } else if (isFalse(alterColumn.isUniqueOneToOne())) {
+ dropUniqueOneToOneConstraint(writer, alterColumn);
+ }
+
+ }
+
+
+
+ protected void addForeignKey(DdlWrite writer, AlterColumn alterColumn) {
+
+ }
+
+ protected void dropForeignKey(DdlWrite writer, AlterColumn alterColumn) {
+
+ }
+
+ protected void dropUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alterColumn) {
+
+ }
+
+ protected void addUniqueOneToOneConstraint(DdlWrite writer, AlterColumn alterColumn) {
+
+ }
+
+ protected void dropUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
+
+ String tableName = alter.getTableName();
+ String columnName = alter.getColumnName();
+ String uqName = platformDdl.namingConvention.uniqueConstraintName(tableName, columnName, 50);
+
+ writer.apply()
+ .append(platformDdl.dropIndex(uqName, tableName))
+ .endOfStatement();
+ }
+
+ protected void addUniqueConstraint(DdlWrite writer, AlterColumn alter) throws IOException {
+
+ String tableName = alter.getTableName();
+ String columnName = alter.getColumnName();
+ String uqName = platformDdl.namingConvention.uniqueConstraintName(tableName, columnName, 50);
+
+ String[] cols = {columnName};
+ writer.apply()
+ .append(platformDdl.createExternalUniqueForOneToOne(uqName, tableName, cols))
+ .endOfStatement();
+
+ writer.rollbackForeignKeys()
+ .append(platformDdl.dropIndex(uqName, tableName))
+ .endOfStatement();
+ }
+
+ protected void historyIncludeColumn(DdlWrite writer, AlterColumn alterColumn) {
+ platformDdl.historyIncludeColumn(writer, alterColumn);
+ }
+
+ protected void historyExcludeColumn(DdlWrite writer, AlterColumn alterColumn) {
+ platformDdl.historyExcludeColumn(writer, alterColumn);
+ }
+
protected void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("alter table ").append(tableName)
@@ -63,6 +152,14 @@ public class BaseColumnDdl implements ColumnDdl {
}
+ protected boolean isFalse(Boolean value) {
+ return value != null && !value;
+ }
+
+ protected boolean isTrue(Boolean value) {
+ return value != null && value;
+ }
+
protected boolean hasValue(String value) {
return value != null && !value.trim().isEmpty();
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java
index 3877de935..9d740c606 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/BaseTableDdl.java
@@ -356,20 +356,6 @@ public class BaseTableDdl implements TableDdl {
appendColumns(pkColumns, buffer);
}
- /**
- * Write alter table add primary key statement.
- */
- public void alterTableAddPrimaryKey(DdlBuffer buffer, String tableName, List pk) throws IOException {
-
- String[] pkColumns = toColumnNames(pk);
- String pkName = determinePrimaryKeyName(tableName);
-
- buffer.append("alter table ").append(tableName);
- buffer.append(" add primary key ").append(pkName);
- appendColumns(pkColumns, buffer);
- buffer.append(")").endOfStatement();
- }
-
/**
* Return as an array of string column names.
*/
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java
index 8204eb8df..15636f65e 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/MsSqlServerDdl.java
@@ -13,6 +13,7 @@ public class MsSqlServerDdl extends PlatformDdl {
this.identitySuffix = " identity(1,1)";
this.foreignKeyRestrict = "";
this.inlineUniqueOneToOne = false;
+ this.namingConvention.maxConstraintNameLength = 62; //Actually 128
}
@Override
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java
index 422d383c7..eadee2052 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PlatformDdl.java
@@ -7,6 +7,7 @@ import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.util.PlatformTypeConverter;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.IdentityType;
import com.avaje.ebean.dbmigration.model.MTable;
@@ -176,4 +177,12 @@ public class PlatformDdl {
// does nothing by default, really this is a MsSqlServer specific requirement
return "";
}
+
+ public void historyExcludeColumn(DdlWrite writer, AlterColumn alterColumn) {
+
+ }
+
+ public void historyIncludeColumn(DdlWrite writer, AlterColumn alterColumn) {
+
+ }
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java
index 8db849012..30dd1e10e 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/ddlgeneration/platform/PostgresDdl.java
@@ -12,6 +12,7 @@ public class PostgresDdl extends PlatformDdl {
super(platformTypes, dbIdentity);
this.historyDdl = new PostgresHistoryDdl(this.namingConvention.normalise);
this.dropTableCascade = " cascade";
+ this.namingConvention.maxConstraintNameLength = 62;
}
/**
diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java b/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java
new file mode 100644
index 000000000..55a05a233
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/dbmigration/migration/AlterColumn.java
@@ -0,0 +1,384 @@
+
+package com.avaje.ebean.dbmigration.migration;
+
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlAttribute;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * Java class for anonymous complex type.
+ *
+ *
The following schema fragment specifies the expected content contained within this class.
+ *
+ *
+ * <complexType>
+ * <complexContent>
+ * <restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ * <attribute name="columnName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="type" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="notnull" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="historyExclude" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="uniqueOneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
+ * <attribute name="oldDefaultValue" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="newDefaultValue" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="oldCheckConstraint" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="newCheckConstraint" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="oldReferences" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="newReferences" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * </restriction>
+ * </complexContent>
+ * </complexType>
+ *
+ *
+ *
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "")
+@XmlRootElement(name = "alterColumn")
+public class AlterColumn {
+
+ @XmlAttribute(name = "columnName", required = true)
+ protected String columnName;
+ @XmlAttribute(name = "tableName", required = true)
+ protected String tableName;
+ @XmlAttribute(name = "type")
+ protected String type;
+ @XmlAttribute(name = "notnull")
+ protected Boolean notnull;
+ @XmlAttribute(name = "historyExclude")
+ protected Boolean historyExclude;
+ @XmlAttribute(name = "unique")
+ protected Boolean unique;
+ @XmlAttribute(name = "uniqueOneToOne")
+ protected Boolean uniqueOneToOne;
+ @XmlAttribute(name = "oldDefaultValue")
+ protected String oldDefaultValue;
+ @XmlAttribute(name = "newDefaultValue")
+ protected String newDefaultValue;
+ @XmlAttribute(name = "oldCheckConstraint")
+ protected String oldCheckConstraint;
+ @XmlAttribute(name = "newCheckConstraint")
+ protected String newCheckConstraint;
+ @XmlAttribute(name = "oldReferences")
+ protected String oldReferences;
+ @XmlAttribute(name = "newReferences")
+ protected String newReferences;
+
+ /**
+ * Gets the value of the columnName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getColumnName() {
+ return columnName;
+ }
+
+ /**
+ * Sets the value of the columnName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setColumnName(String value) {
+ this.columnName = value;
+ }
+
+ /**
+ * Gets the value of the tableName property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getTableName() {
+ return tableName;
+ }
+
+ /**
+ * Sets the value of the tableName property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setTableName(String value) {
+ this.tableName = value;
+ }
+
+ /**
+ * Gets the value of the type property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getType() {
+ return type;
+ }
+
+ /**
+ * Sets the value of the type property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setType(String value) {
+ this.type = value;
+ }
+
+ /**
+ * Gets the value of the notnull property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isNotnull() {
+ return notnull;
+ }
+
+ /**
+ * Sets the value of the notnull property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setNotnull(Boolean value) {
+ this.notnull = value;
+ }
+
+ /**
+ * Gets the value of the historyExclude property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isHistoryExclude() {
+ return historyExclude;
+ }
+
+ /**
+ * Sets the value of the historyExclude property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setHistoryExclude(Boolean value) {
+ this.historyExclude = value;
+ }
+
+ /**
+ * Gets the value of the unique property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isUnique() {
+ return unique;
+ }
+
+ /**
+ * Sets the value of the unique property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setUnique(Boolean value) {
+ this.unique = value;
+ }
+
+ /**
+ * Gets the value of the uniqueOneToOne property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isUniqueOneToOne() {
+ return uniqueOneToOne;
+ }
+
+ /**
+ * Sets the value of the uniqueOneToOne property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setUniqueOneToOne(Boolean value) {
+ this.uniqueOneToOne = value;
+ }
+
+ /**
+ * Gets the value of the oldDefaultValue property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getOldDefaultValue() {
+ return oldDefaultValue;
+ }
+
+ /**
+ * Sets the value of the oldDefaultValue property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setOldDefaultValue(String value) {
+ this.oldDefaultValue = value;
+ }
+
+ /**
+ * Gets the value of the newDefaultValue property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNewDefaultValue() {
+ return newDefaultValue;
+ }
+
+ /**
+ * Sets the value of the newDefaultValue property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setNewDefaultValue(String value) {
+ this.newDefaultValue = value;
+ }
+
+ /**
+ * Gets the value of the oldCheckConstraint property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getOldCheckConstraint() {
+ return oldCheckConstraint;
+ }
+
+ /**
+ * Sets the value of the oldCheckConstraint property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setOldCheckConstraint(String value) {
+ this.oldCheckConstraint = value;
+ }
+
+ /**
+ * Gets the value of the newCheckConstraint property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNewCheckConstraint() {
+ return newCheckConstraint;
+ }
+
+ /**
+ * Sets the value of the newCheckConstraint property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setNewCheckConstraint(String value) {
+ this.newCheckConstraint = value;
+ }
+
+ /**
+ * Gets the value of the oldReferences property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getOldReferences() {
+ return oldReferences;
+ }
+
+ /**
+ * Sets the value of the oldReferences property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setOldReferences(String value) {
+ this.oldReferences = value;
+ }
+
+ /**
+ * Gets the value of the newReferences property.
+ *
+ * @return
+ * possible object is
+ * {@link String }
+ *
+ */
+ public String getNewReferences() {
+ return newReferences;
+ }
+
+ /**
+ * Sets the value of the newReferences property.
+ *
+ * @param value
+ * allowed object is
+ * {@link String }
+ *
+ */
+ public void setNewReferences(String value) {
+ this.newReferences = value;
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java b/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java
index 4024e6f50..16fd6b4aa 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/migration/ChangeSet.java
@@ -51,14 +51,10 @@ public class ChangeSet {
@XmlElement(name = "dropTable", type = DropTable.class),
@XmlElement(name = "renameTable", type = RenameTable.class),
@XmlElement(name = "createHistoryTable", type = CreateHistoryTable.class),
- @XmlElement(name = "createView", type = CreateView.class),
- @XmlElement(name = "dropView", type = DropView.class),
- @XmlElement(name = "renameView", type = RenameView.class),
@XmlElement(name = "addColumn", type = AddColumn.class),
@XmlElement(name = "dropColumn", type = DropColumn.class),
- @XmlElement(name = "renameColumn", type = RenameColumn.class),
- @XmlElement(name = "addForeignKey", type = AddForeignKey.class),
- @XmlElement(name = "dropForeignKey", type = DropForeignKey.class)
+ @XmlElement(name = "alterColumn", type = AlterColumn.class),
+ @XmlElement(name = "renameColumn", type = RenameColumn.class)
})
protected List changeSetChildren;
@XmlAttribute(name = "type", required = true)
@@ -94,14 +90,10 @@ public class ChangeSet {
* {@link DropTable }
* {@link RenameTable }
* {@link CreateHistoryTable }
- * {@link CreateView }
- * {@link DropView }
- * {@link RenameView }
* {@link AddColumn }
* {@link DropColumn }
+ * {@link AlterColumn }
* {@link RenameColumn }
- * {@link AddForeignKey }
- * {@link DropForeignKey }
*
*
*/
diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java b/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java
index 0825264e3..69e84822c 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/migration/Column.java
@@ -23,6 +23,7 @@ import javax.xml.bind.annotation.XmlValue;
* <attribute name="defaultValue" type="{http://www.w3.org/2001/XMLSchema}string" />
* <attribute name="notnull" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* <attribute name="checkConstraint" type="{http://www.w3.org/2001/XMLSchema}string" />
+ * <attribute name="historyExclude" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* <attribute name="unique" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* <attribute name="uniqueOneToOne" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* <attribute name="primaryKey" type="{http://www.w3.org/2001/XMLSchema}boolean" />
@@ -55,6 +56,8 @@ public class Column {
protected Boolean notnull;
@XmlAttribute(name = "checkConstraint")
protected String checkConstraint;
+ @XmlAttribute(name = "historyExclude")
+ protected Boolean historyExclude;
@XmlAttribute(name = "unique")
protected Boolean unique;
@XmlAttribute(name = "uniqueOneToOne")
@@ -212,6 +215,30 @@ public class Column {
this.checkConstraint = value;
}
+ /**
+ * Gets the value of the historyExclude property.
+ *
+ * @return
+ * possible object is
+ * {@link Boolean }
+ *
+ */
+ public Boolean isHistoryExclude() {
+ return historyExclude;
+ }
+
+ /**
+ * Sets the value of the historyExclude property.
+ *
+ * @param value
+ * allowed object is
+ * {@link Boolean }
+ *
+ */
+ public void setHistoryExclude(Boolean value) {
+ this.historyExclude = value;
+ }
+
/**
* Gets the value of the unique property.
*
diff --git a/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java b/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java
index 1b9610b16..83a1ae9ef 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/migration/ObjectFactory.java
@@ -30,11 +30,19 @@ public class ObjectFactory {
}
/**
- * Create an instance of {@link CreateTable }
+ * Create an instance of {@link Rollback }
*
*/
- public CreateTable createCreateTable() {
- return new CreateTable();
+ public Rollback createRollback() {
+ return new Rollback();
+ }
+
+ /**
+ * Create an instance of {@link AddColumn }
+ *
+ */
+ public AddColumn createAddColumn() {
+ return new AddColumn();
}
/**
@@ -45,6 +53,14 @@ public class ObjectFactory {
return new Column();
}
+ /**
+ * Create an instance of {@link CreateTable }
+ *
+ */
+ public CreateTable createCreateTable() {
+ return new CreateTable();
+ }
+
/**
* Create an instance of {@link UniqueConstraint }
*
@@ -62,11 +78,11 @@ public class ObjectFactory {
}
/**
- * Create an instance of {@link DropForeignKey }
+ * Create an instance of {@link Apply }
*
*/
- public DropForeignKey createDropForeignKey() {
- return new DropForeignKey();
+ public Apply createApply() {
+ return new Apply();
}
/**
@@ -101,6 +117,14 @@ public class ObjectFactory {
return new DropHistoryTable();
}
+ /**
+ * Create an instance of {@link AlterColumn }
+ *
+ */
+ public AlterColumn createAlterColumn() {
+ return new AlterColumn();
+ }
+
/**
* Create an instance of {@link DropColumn }
*
@@ -110,11 +134,11 @@ public class ObjectFactory {
}
/**
- * Create an instance of {@link DropView }
+ * Create an instance of {@link ChangeSet }
*
*/
- public DropView createDropView() {
- return new DropView();
+ public ChangeSet createChangeSet() {
+ return new ChangeSet();
}
/**
@@ -126,19 +150,11 @@ public class ObjectFactory {
}
/**
- * Create an instance of {@link Apply }
+ * Create an instance of {@link DropTable }
*
*/
- public Apply createApply() {
- return new Apply();
- }
-
- /**
- * Create an instance of {@link Rollback }
- *
- */
- public Rollback createRollback() {
- return new Rollback();
+ public DropTable createDropTable() {
+ return new DropTable();
}
/**
@@ -157,62 +173,6 @@ public class ObjectFactory {
return new RenameColumn();
}
- /**
- * Create an instance of {@link CreateView }
- *
- */
- public CreateView createCreateView() {
- return new CreateView();
- }
-
- /**
- * Create an instance of {@link DropTable }
- *
- */
- public DropTable createDropTable() {
- return new DropTable();
- }
-
- /**
- * Create an instance of {@link AddColumn }
- *
- */
- public AddColumn createAddColumn() {
- return new AddColumn();
- }
-
- /**
- * Create an instance of {@link RenameView }
- *
- */
- public RenameView createRenameView() {
- return new RenameView();
- }
-
- /**
- * Create an instance of {@link AddForeignKey }
- *
- */
- public AddForeignKey createAddForeignKey() {
- return new AddForeignKey();
- }
-
- /**
- * Create an instance of {@link ChangeSet }
- *
- */
- public ChangeSet createChangeSet() {
- return new ChangeSet();
- }
-
- /**
- * Create an instance of {@link Application }
- *
- */
- public Application createApplication() {
- return new Application();
- }
-
/**
* Create an instance of {@link Migration }
*
@@ -221,12 +181,4 @@ public class ObjectFactory {
return new Migration();
}
- /**
- * Create an instance of {@link Applications }
- *
- */
- public Applications createApplications() {
- return new Applications();
- }
-
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlReader.java b/src/main/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlReader.java
index 5e3eb421b..95d4df445 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlReader.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlReader.java
@@ -15,6 +15,19 @@ public class MigrationXmlReader {
private static final MigrationXmlReader INSTANCE = new MigrationXmlReader();
+ /**
+ * Read and return a Migration from an xml document at the given resource path.
+ */
+ public static Migration readMaybe(String resourcePath) {
+
+ InputStream is = MigrationXmlReader.class.getResourceAsStream(resourcePath);
+ if (is == null) {
+ return null;
+ }
+
+ return INSTANCE.read(is);
+ }
+
/**
* Read and return a Migration from an xml document at the given resource path.
*/
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java b/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java
index 45f653898..fdcfd4732 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/CurrentModel.java
@@ -2,7 +2,6 @@ package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
-import com.avaje.ebean.dbmigration.ddlgeneration.platform.DdlNamingConvention;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
@@ -22,17 +21,22 @@ public class CurrentModel {
private final SpiEbeanServer server;
- private DdlNamingConvention namingConvention;
-
private ModelContainer model;
+
private ChangeSet changeSet;
+
private DdlWrite write;
+ /**
+ * Construct with a given EbeanServer instance.
+ */
public CurrentModel(SpiEbeanServer server) {
this.server = server;
- this.namingConvention = new DdlNamingConvention();
}
+ /**
+ * Return the current model by reading all the bean descriptors and properties.
+ */
public ModelContainer read() {
if (model == null) {
model = new ModelContainer();
@@ -48,6 +52,9 @@ public class CurrentModel {
this.changeSet = changeSet;
}
+ /**
+ * Return as a ChangeSet.
+ */
public ChangeSet getChangeSet() {
read();
if (changeSet == null) {
@@ -56,6 +63,9 @@ public class CurrentModel {
return changeSet;
}
+ /**
+ * Write as migration xml to the given file.
+ */
public void writeMigration(File file) {
ChangeSet changeSet = getChangeSet();
@@ -66,6 +76,9 @@ public class CurrentModel {
writer.write(migration, file);
}
+ /**
+ * Return the 'Create' DDL.
+ */
public String getCreateDdl() throws IOException {
createDdl();
@@ -78,6 +91,9 @@ public class CurrentModel {
return ddl.toString();
}
+ /**
+ * Return the 'Drop' DDL.
+ */
public String getDropDdl() throws IOException {
createDdl();
@@ -89,16 +105,9 @@ public class CurrentModel {
return ddl.toString();
}
- public DdlWrite generateDdl(ChangeSet changeSet) throws IOException {
-
- DdlWrite write = new DdlWrite();
-
- DdlHandler handler = handler();
- handler.generate(write, changeSet);
-
- return write;
- }
-
+ /**
+ * Create all the DDL based on the changeSet.
+ */
private void createDdl() throws IOException {
if (write == null) {
@@ -111,8 +120,10 @@ public class CurrentModel {
}
}
+ /**
+ * Return the platform specific DdlHandler (to generate DDL).
+ */
private DdlHandler handler() {
-
return server.getDatabasePlatform().createDdlHandler();
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java b/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java
index 1be7074ae..7855d9920 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/MColumn.java
@@ -1,5 +1,6 @@
package com.avaje.ebean.dbmigration.model;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.Column;
/**
@@ -12,6 +13,7 @@ public class MColumn {
private String checkConstraint;
private String defaultValue;
private String references;
+ private boolean historyExclude;
private boolean notnull;
private boolean primaryKey;
private boolean identity;
@@ -34,6 +36,7 @@ public class MColumn {
this.primaryKey = Boolean.TRUE.equals(column.isPrimaryKey());
this.identity = Boolean.TRUE.equals(column.isIdentity());
this.unique = Boolean.TRUE.equals(column.isUnique());
+ this.historyExclude = Boolean.TRUE.equals(column.isHistoryExclude());
}
public MColumn(String name, String type) {
@@ -103,6 +106,14 @@ public class MColumn {
this.notnull = notnull;
}
+ public boolean isHistoryExclude() {
+ return historyExclude;
+ }
+
+ public void setHistoryExclude(boolean historyExclude) {
+ this.historyExclude = historyExclude;
+ }
+
public void setUnique(boolean unique) {
this.unique = unique;
}
@@ -136,6 +147,7 @@ public class MColumn {
if (uniqueOneToOne) c.setUniqueOneToOne(true);
if (primaryKey) c.setPrimaryKey(true);
if (identity) c.setIdentity(true);
+ if (historyExclude) c.setHistoryExclude(true);
c.setCheckConstraint(checkConstraint);
c.setReferences(references);
@@ -143,4 +155,64 @@ public class MColumn {
return c;
}
+
+ private boolean different(String val1, String val2) {
+ return (val1 == null) ? val2 != null : !val1.equals(val2);
+ }
+
+ AlterColumn alterColumn;
+
+ private AlterColumn getAlterColumn(String tableName) {
+ if (alterColumn == null) {
+ alterColumn = new AlterColumn();
+ alterColumn.setColumnName(name);
+ alterColumn.setTableName(tableName);
+ }
+ return alterColumn;
+ }
+
+ public void compare(ModelDiff modelDiff, MTable table, MColumn newColumn) {
+
+ String tableName = table.getName();
+
+ this.alterColumn = null;
+
+ if (different(type, newColumn.type)) {
+ getAlterColumn(tableName).setType(newColumn.type);
+ }
+ if (historyExclude != newColumn.historyExclude) {
+ getAlterColumn(tableName).setHistoryExclude(newColumn.historyExclude);
+ }
+ if (notnull != newColumn.notnull) {
+ getAlterColumn(tableName).setNotnull(newColumn.notnull);
+ }
+ if (different(defaultValue, newColumn.defaultValue)) {
+ AlterColumn alter = getAlterColumn(tableName);
+ alter.setOldDefaultValue(defaultValue);
+ alter.setNewDefaultValue(newColumn.defaultValue);
+ }
+ if (different(checkConstraint, newColumn.checkConstraint)) {
+ AlterColumn alter = getAlterColumn(tableName);
+ alter.setOldCheckConstraint(checkConstraint);
+ alter.setNewCheckConstraint(newColumn.checkConstraint);
+ }
+ if (different(references, newColumn.references)) {
+ AlterColumn alter = getAlterColumn(tableName);
+ alter.setOldReferences(references);
+ alter.setNewReferences(newColumn.references);
+ }
+
+ if (unique != newColumn.unique) {
+ AlterColumn alter = getAlterColumn(tableName);
+ alter.setUnique(newColumn.unique);
+ }
+ if (uniqueOneToOne != newColumn.uniqueOneToOne) {
+ AlterColumn alter = getAlterColumn(tableName);
+ alter.setUniqueOneToOne(newColumn.uniqueOneToOne);
+ }
+
+ if (alterColumn != null) {
+ modelDiff.addAlterColumn(alterColumn);
+ }
+ }
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java
index 25e8b5781..950ed6416 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/MTable.java
@@ -8,9 +8,12 @@ import com.avaje.ebean.dbmigration.migration.IdentityType;
import java.math.BigInteger;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
/**
* Holds the logical model for a given Table and everything associated to it.
@@ -29,11 +32,6 @@ import java.util.Map;
*/
public class MTable {
- /**
- * Flag set to indicate
- */
- private boolean matched;
-
private final String name;
private String comment;
@@ -60,6 +58,8 @@ public class MTable {
private List compoundKeys = new ArrayList();
+ private AddColumn addColumn;
+
/**
* Construct for migration.
*/
@@ -110,12 +110,37 @@ public class MTable {
return createTable;
}
- public boolean isMatched() {
- return matched;
- }
+ public void compare(ModelDiff modelDiff, MTable newTable) {
+
+ // TODO: compare indexes?
+ // TODO: compare primary key
+
+ addColumn = null;
+
+ Set mappedColumns = new LinkedHashSet();
+
+ Collection newColumns = newTable.getColumns().values();
+ for (MColumn newColumn : newColumns) {
+ MColumn localColumn = columns.get(newColumn.getName());
+ if (localColumn == null) {
+ diffNewColumn(newColumn);
+ } else {
+ localColumn.compare(modelDiff, this, newColumn);
+ mappedColumns.add(newColumn.getName());
+ }
+ }
+
+ Collection existingColumns = columns.values();
+ for (MColumn existingColumn : existingColumns) {
+ if (!mappedColumns.contains(existingColumn.getName())) {
+ diffDropColumn(modelDiff, existingColumn);
+ }
+ }
+
+ if (addColumn != null) {
+ modelDiff.addAddColumn(addColumn);
+ }
- public void setMatched(boolean matched) {
- this.matched = matched;
}
/**
@@ -293,4 +318,24 @@ public class MTable {
addColumn(newCol);
return newCol;
}
+
+
+ private void diffNewColumn(MColumn newColumn) {
+
+ if (addColumn == null) {
+ addColumn = new AddColumn();
+ addColumn.setTableName(name);
+ }
+
+ addColumn.getColumn().add(newColumn.createColumn());
+ }
+
+ private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) {
+
+ DropColumn dropColumn = new DropColumn();
+ dropColumn.setTableName(name);
+ dropColumn.setColumnName(existingColumn.getName());
+
+ modelDiff.addDropColumn(dropColumn);
+ }
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/MigrationModel.java b/src/main/java/com/avaje/ebean/dbmigration/model/MigrationModel.java
new file mode 100644
index 000000000..1446fdcb5
--- /dev/null
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/MigrationModel.java
@@ -0,0 +1,93 @@
+package com.avaje.ebean.dbmigration.model;
+
+import com.avaje.ebean.dbmigration.migration.Migration;
+import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlReader;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+/**
+ * Build the model from the series of migrations.
+ */
+public class MigrationModel {
+
+ private static final Logger logger = LoggerFactory.getLogger(MigrationModel.class);
+
+ private final ModelContainer model = new ModelContainer();
+
+ private final Set readVersions = new LinkedHashSet();
+
+ private final String resourcePath;
+
+ public MigrationModel(String resourcePath) {
+ this.resourcePath = normaliseResourcePath(resourcePath);
+ }
+
+ private String normaliseResourcePath(String resourcePath) {
+ if (resourcePath.endsWith("/")) {
+ // trim trailing slash
+ resourcePath = resourcePath.substring(0, resourcePath.length()-1);
+ }
+ if (resourcePath.startsWith("/")) {
+ // trim leading slash
+ resourcePath = resourcePath.substring(1);
+ }
+ return resourcePath;
+ }
+
+ /**
+ * Read all the migrations returning the model with all
+ * the migrations applied in version order.
+ */
+ public ModelContainer read() {
+
+ readMigrations();
+ logger.info("read versions {}", readVersions);
+ return model;
+ }
+
+ /**
+ * Return the set of versions that were read.
+ */
+ public Set getReadVersions() {
+ return readVersions;
+ }
+
+ private void readMigrations() {
+ for (int majorVersion = 1; majorVersion < 100; majorVersion++) {
+ if (!readMinorVersions(majorVersion)){
+ // no major.0 version so stopping
+ return;
+ }
+ }
+ }
+
+ private boolean readMinorVersions(int majorVersion) {
+
+ for (int minorVersion = 0; minorVersion < 100; minorVersion++) {
+ if (!readMigration(majorVersion, minorVersion)) {
+ // continue reading next major if minorVersion 0 was read
+ return (minorVersion > 0);
+ }
+ }
+ return true;
+ }
+
+ private boolean readMigration(int majorVersion, int minorVersion) {
+
+ String version = majorVersion+"."+minorVersion;
+ String path = "/"+resourcePath+"/v"+version+".xml";
+
+ Migration migration = MigrationXmlReader.readMaybe(path);
+ if (migration == null) {
+ return false;
+ }
+ readVersions.add(version);
+ logger.trace("... read migration v{}", version);
+ model.apply(migration);
+ return true;
+ }
+
+}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java b/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java
index 7eed356cf..c57b4f392 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/ModelContainer.java
@@ -23,6 +23,9 @@ public class ModelContainer {
*/
private Map tables = new LinkedHashMap();
+ public ModelContainer() {
+
+ }
/**
* Return the map of all the tables.
@@ -73,7 +76,7 @@ public class ModelContainer {
protected void applyChange(CreateTable createTable) {
String tableName = createTable.getName();
if (tables.containsKey(tableName)) {
- throw new IllegalStateException("Table [" + tableName + "] already exists?");
+ throw new IllegalStateException("Table [" + tableName + "] already exists in model?");
}
MTable table = new MTable(createTable);
tables.put(tableName, table);
@@ -85,7 +88,7 @@ public class ModelContainer {
protected void applyChange(AddColumn addColumn) {
MTable table = tables.get(addColumn.getTableName());
if (table == null) {
- throw new IllegalStateException("Table [" + addColumn.getTableName() + "] does not exist?");
+ throw new IllegalStateException("Table [" + addColumn.getTableName() + "] does not exist in model?");
}
table.apply(addColumn);
}
@@ -96,7 +99,7 @@ public class ModelContainer {
protected void applyChange(DropColumn dropColumn) {
MTable table = tables.get(dropColumn.getTableName());
if (table == null) {
- throw new IllegalStateException("Table [" + dropColumn.getTableName() + "] does not exist?");
+ throw new IllegalStateException("Table [" + dropColumn.getTableName() + "] does not exist in model?");
}
table.apply(dropColumn);
}
diff --git a/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java b/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java
index 23be84b02..e09f027c7 100644
--- a/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java
+++ b/src/main/java/com/avaje/ebean/dbmigration/model/ModelDiff.java
@@ -1,5 +1,9 @@
package com.avaje.ebean.dbmigration.model;
+import com.avaje.ebean.dbmigration.migration.AddColumn;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
+import com.avaje.ebean.dbmigration.migration.DropColumn;
+
import java.util.ArrayList;
import java.util.List;
@@ -12,17 +16,17 @@ public class ModelDiff {
/**
* The base model to which we compare the newer model.
*/
- protected final ModelContainer baseModel;
+ private final ModelContainer baseModel;
/**
* List of 'create' type changes.
*/
- protected final List createChanges = new ArrayList();
+ private final List createChanges = new ArrayList();
/**
- * List of 'drop' type changes. Potential for putting into a separate changeSet.
+ * List of 'drop' type changes. Expected to be placed into a separate DDL script.
*/
- protected final List dropChanges = new ArrayList();
+ private final List dropChanges = new ArrayList();
/**
* Construct with a base model.
@@ -77,7 +81,6 @@ public class ModelDiff {
protected void addNewTable(MTable newTable) {
createChanges.add(newTable.createTable());
-// createChanges.add(newTable.createForeignKeys());
}
/**
@@ -85,14 +88,19 @@ public class ModelDiff {
*/
protected void compareTables(MTable currentTable, MTable newTable) {
- //TODO: compareTables()
- // changed columns
- // find additional columns
- // find removed columns
- // changes to indexes?
- // changes to primary key
- // changes to foreign key
- // changes to unique constraints?
+ currentTable.compare(this, newTable);
}
+
+ public void addAlterColumn(AlterColumn alterColumn) {
+ createChanges.add(alterColumn);
+ }
+
+ public void addDropColumn(DropColumn dropColumn) {
+ dropChanges.add(dropColumn);
+ }
+
+ public void addAddColumn(AddColumn addColumn) {
+ createChanges.add(addColumn);
+ }
}
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DatabasePlatformFactory.java b/src/main/java/com/avaje/ebeaninternal/server/core/DatabasePlatformFactory.java
index a79961e68..6c8407454 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DatabasePlatformFactory.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DatabasePlatformFactory.java
@@ -9,6 +9,7 @@ import javax.sql.DataSource;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.*;
+import com.avaje.ebean.dbmigration.DbOffline;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -30,11 +31,17 @@ public class DatabasePlatformFactory {
try {
+ String offlinePlatform = DbOffline.getPlatform();
+ if (offlinePlatform != null) {
+ logger.info("offline platform [{}]", offlinePlatform);
+ return byDatabaseName(offlinePlatform);
+ }
+
if (serverConfig.getDatabasePlatformName() != null) {
// choose based on dbName
return byDatabaseName(serverConfig.getDatabasePlatformName());
-
}
+
if (serverConfig.getDataSourceConfig().isOffline()) {
String m = "You must specify a DatabasePlatformName when you are offline";
throw new PersistenceException(m);
diff --git a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java
index da9f730f7..e6d847c03 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/core/DefaultContainer.java
@@ -11,6 +11,7 @@ import com.avaje.ebean.config.PropertyMap;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.UnderscoreNamingConvention;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
+import com.avaje.ebean.dbmigration.DbOffline;
import com.avaje.ebeaninternal.api.SpiBackgroundExecutor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.cache.DefaultServerCacheFactory;
@@ -113,9 +114,6 @@ public class DefaultContainer implements SpiContainer {
serverConfig.getDatabasePlatform().setDbEncrypt(serverConfig.getDbEncrypt());
}
- DatabasePlatform dbPlatform = serverConfig.getDatabasePlatform();
-
-
// inform the NamingConvention of the associated DatabasePlaform
serverConfig.getNamingConvention().setDatabasePlatform(serverConfig.getDatabasePlatform());
@@ -169,6 +167,7 @@ public class DefaultContainer implements SpiContainer {
// start any services after registering with clusterManager
server.start();
+ DbOffline.reset();
return server;
}
}
@@ -284,6 +283,11 @@ public class DefaultContainer implements SpiContainer {
private DataSource getDataSourceFromConfig(ServerConfig config) {
+ if (DbOffline.isSet()) {
+ logger.trace("... DbOffline using platform [{}]", DbOffline.getPlatform());
+ return null;
+ }
+
DataSource ds;
if (config.getDataSourceJndiName() != null) {
@@ -324,6 +328,10 @@ public class DefaultContainer implements SpiContainer {
*/
private boolean checkDataSource(ServerConfig serverConfig) {
+ if (DbOffline.isSet()) {
+ return false;
+ }
+
if (serverConfig.getDataSource() == null) {
if (serverConfig.getDataSourceConfig().isOffline()) {
// this is ok - offline DDL generation etc
diff --git a/src/main/java/com/avaje/ebeaninternal/server/type/ConvertInetAddresses.java b/src/main/java/com/avaje/ebeaninternal/server/type/ConvertInetAddresses.java
index d3d83dff9..2473e140a 100644
--- a/src/main/java/com/avaje/ebeaninternal/server/type/ConvertInetAddresses.java
+++ b/src/main/java/com/avaje/ebeaninternal/server/type/ConvertInetAddresses.java
@@ -185,7 +185,6 @@ public final class ConvertInetAddresses {
boolean isIpv6 = false;
// handle IPv6 forms of IPv4 addresses
- // TODO: use Ascii.toUpperCase() when available
if (ipString.toUpperCase(Locale.US).startsWith("::FFFF:")) {
ipString = ipString.substring(7);
} else if (ipString.startsWith("::")) {
diff --git a/src/main/resources/ebean-dbmigration-1.0.xsd b/src/main/resources/ebean-dbmigration-1.0.xsd
index fe72b0e0f..cbd6f4141 100644
--- a/src/main/resources/ebean-dbmigration-1.0.xsd
+++ b/src/main/resources/ebean-dbmigration-1.0.xsd
@@ -8,20 +8,20 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
@@ -201,6 +201,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -212,49 +230,49 @@
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
@@ -263,13 +281,13 @@
-
+
-
+
@@ -285,7 +303,6 @@
-
@@ -294,16 +311,17 @@
-
-
-
-
+
-
-
+
+
+
+
+
+
@@ -312,23 +330,13 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/test/java/com/avaje/ebean/config/DbMigrationConfigTest.java b/src/test/java/com/avaje/ebean/config/DbMigrationConfigTest.java
new file mode 100644
index 000000000..061ff7987
--- /dev/null
+++ b/src/test/java/com/avaje/ebean/config/DbMigrationConfigTest.java
@@ -0,0 +1,23 @@
+package com.avaje.ebean.config;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.*;
+
+
+public class DbMigrationConfigTest {
+
+
+ @Test
+ public void testLoad() {
+
+ ServerConfig config = new ServerConfig();
+ config.setName("h2other");
+ config.loadFromProperties();
+
+ DbMigrationConfig migrationConfig = config.getMigrationConfig();
+
+ assertThat(migrationConfig.getAppName()).isEqualTo("myapp");
+ assertThat(migrationConfig.getResourcePath()).isEqualTo("dbmigration/myapp");
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebean/dbmigration/DbMigrationTest.java b/src/test/java/com/avaje/ebean/dbmigration/DbMigrationTest.java
new file mode 100644
index 000000000..36c61cc79
--- /dev/null
+++ b/src/test/java/com/avaje/ebean/dbmigration/DbMigrationTest.java
@@ -0,0 +1,32 @@
+package com.avaje.ebean.dbmigration;
+
+import com.avaje.ebean.BaseTestCase;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import static org.assertj.core.api.Assertions.*;
+
+public class DbMigrationTest extends BaseTestCase {
+
+ private static final Logger logger = LoggerFactory.getLogger(DbMigrationTest.class);
+
+ //@Ignore
+ @Test
+ public void writeCurrent() {
+
+ logger.info("start");
+
+ DbOffline.asH2();
+ DbMigration migration = new DbMigration();
+ DbOffline.reset();
+
+ migration.writeCurrent();
+
+ assertThat(DbOffline.isSet()).isFalse();
+
+ logger.info("end");
+ }
+
+}
diff --git a/src/test/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlWriterTest.java b/src/test/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlWriterTest.java
index 89c1a5b38..3799057d6 100644
--- a/src/test/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlWriterTest.java
+++ b/src/test/java/com/avaje/ebean/dbmigration/migrationreader/MigrationXmlWriterTest.java
@@ -12,7 +12,7 @@ public class MigrationXmlWriterTest {
Logger logger = LoggerFactory.getLogger(MigrationXmlWriterTest.class);
@Test
- public void testWrite() throws Exception {
+ public void testReadWrite() throws Exception {
Migration migration = MigrationXmlReader.read("/container/test-create-table.xml");
diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java
new file mode 100644
index 000000000..2b3f18078
--- /dev/null
+++ b/src/test/java/com/avaje/ebean/dbmigration/model/MColumnTest.java
@@ -0,0 +1,273 @@
+package com.avaje.ebean.dbmigration.model;
+
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
+import org.jetbrains.annotations.NotNull;
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.*;
+
+
+public class MColumnTest {
+
+ MTable table = new MTable("tab");
+
+ MColumn basic() {
+ return new MColumn("col", "integer");
+ }
+
+ ModelDiff diff() {
+ return new ModelDiff();
+ }
+
+ @Test
+ public void noDiff() throws Exception {
+
+ ModelDiff diff = diff();
+ basic().compare(diff, table, basic());
+
+ assertThat(diff.getCreateChanges()).isEmpty();
+ assertThat(diff.getDropChanges()).isEmpty();
+ }
+
+ @Test
+ public void diffType() throws Exception {
+
+ ModelDiff diff = diff();
+ basic().compare(diff, table, new MColumn("col", "integer(8)"));
+
+ assertChanges(diff);
+ AlterColumn alterColumn = getAlterColumn(diff);
+ assertThat(alterColumn.getType()).isEqualTo("integer(8)");
+ }
+
+ @Test
+ public void diffNotNull() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setNotnull(true);
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ AlterColumn alterColumn = getAlterColumn(diff);
+ assertThat(alterColumn.isNotnull()).isEqualTo(true);
+
+ assertThat(alterColumn.getType()).isNull();
+ assertThat(alterColumn.isUnique()).isNull();
+ assertThat(alterColumn.isUniqueOneToOne()).isNull();
+ assertThat(alterColumn.getNewDefaultValue()).isNull();
+ }
+
+ @Test
+ public void diffCheckAdd() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setCheckConstraint("abc");
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewCheckConstraint()).isEqualTo("abc");
+ assertThat(getAlterColumn(diff).getOldCheckConstraint()).isNull();
+ }
+
+ @Test
+ public void diffCheckRemove() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ MColumn oldCol = basic();
+ oldCol.setCheckConstraint("abc");
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewCheckConstraint()).isNull();
+ assertThat(getAlterColumn(diff).getOldCheckConstraint()).isEqualTo("abc");
+ }
+
+ @Test
+ public void diffCheckChange() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setCheckConstraint("abc");
+ MColumn oldCol = basic();
+ oldCol.setCheckConstraint("d");
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewCheckConstraint()).isEqualTo("abc");
+ assertThat(getAlterColumn(diff).getOldCheckConstraint()).isEqualTo("d");
+ }
+
+ @Test
+ public void diffDefaultValueAdd() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setDefaultValue("abc");
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewDefaultValue()).isEqualTo("abc");
+ assertThat(getAlterColumn(diff).getOldDefaultValue()).isNull();
+ }
+
+ @Test
+ public void diffDefaultValueRemove() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ MColumn oldCol = basic();
+ oldCol.setDefaultValue("abc");
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewDefaultValue()).isNull();
+ assertThat(getAlterColumn(diff).getOldDefaultValue()).isEqualTo("abc");
+ }
+
+ @Test
+ public void diffDefaultValueChange() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setDefaultValue("abc");
+ MColumn oldCol = basic();
+ oldCol.setDefaultValue("d");
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewDefaultValue()).isEqualTo("abc");
+ assertThat(getAlterColumn(diff).getOldDefaultValue()).isEqualTo("d");
+ }
+
+ @Test
+ public void diffReferencesAdd() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setReferences("abc");
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewReferences()).isEqualTo("abc");
+ assertThat(getAlterColumn(diff).getOldReferences()).isNull();
+ }
+
+
+ @Test
+ public void diffReferencesRemove() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ MColumn oldCol = basic();
+ oldCol.setReferences("abc");
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewReferences()).isNull();
+ assertThat(getAlterColumn(diff).getOldReferences()).isEqualTo("abc");
+ }
+
+ @Test
+ public void diffReferencesChange() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setReferences("abc");
+ MColumn oldCol = basic();
+ oldCol.setReferences("d");
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).getNewReferences()).isEqualTo("abc");
+ assertThat(getAlterColumn(diff).getOldReferences()).isEqualTo("d");
+ }
+
+ @Test
+ public void diffUniqueAdd() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setUnique(true);
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).isUnique()).isEqualTo(true);
+ }
+
+ @Test
+ public void diffUniqueRemove() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ MColumn oldCol = basic();
+ oldCol.setUnique(true);
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).isUnique()).isEqualTo(false);
+ }
+
+ @Test
+ public void diffUniqueOneToOneAdd() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setUniqueOneToOne(true);
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).isUniqueOneToOne()).isEqualTo(true);
+ }
+
+ @Test
+ public void diffUniqueOneToOneRemove() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ MColumn oldCol = basic();
+ oldCol.setUniqueOneToOne(true);
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).isUniqueOneToOne()).isEqualTo(false);
+ }
+
+ @Test
+ public void diffHistoryExcludeAdd() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ newCol.setHistoryExclude(true);
+ basic().compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).isHistoryExclude()).isEqualTo(true);
+ }
+
+ @Test
+ public void diffHistoryExcludeRemove() throws Exception {
+
+ ModelDiff diff = diff();
+ MColumn newCol = basic();
+ MColumn oldCol = basic();
+ oldCol.setHistoryExclude(true);
+ oldCol.compare(diff, table, newCol);
+
+ assertChanges(diff);
+ assertThat(getAlterColumn(diff).isHistoryExclude()).isEqualTo(false);
+ }
+
+ @NotNull
+ private AlterColumn getAlterColumn(ModelDiff diff) {
+ return (AlterColumn) diff.getCreateChanges().get(0);
+ }
+
+ private void assertChanges(ModelDiff diff) {
+ assertThat(diff.getDropChanges()).isEmpty();
+ assertThat(diff.getCreateChanges()).hasSize(1);
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java
new file mode 100644
index 000000000..13617e9e9
--- /dev/null
+++ b/src/test/java/com/avaje/ebean/dbmigration/model/MTableTest.java
@@ -0,0 +1,110 @@
+package com.avaje.ebean.dbmigration.model;
+
+import com.avaje.ebean.dbmigration.migration.AddColumn;
+import com.avaje.ebean.dbmigration.migration.AlterColumn;
+import com.avaje.ebean.dbmigration.migration.DropColumn;
+import org.junit.Test;
+
+import java.util.List;
+
+import static org.assertj.core.api.Assertions.*;
+
+public class MTableTest {
+
+ MTable base() {
+ MTable table = new MTable("tab");
+ table.addColumn(new MColumn("id","bigint"));
+ table.addColumn(new MColumn("name","varchar(20)"));
+ table.addColumn(new MColumn("status","varchar(3)"));
+
+ return table;
+ }
+
+ MTable newTable() {
+ MTable table = new MTable("tab");
+ table.addColumn(new MColumn("id","bigint"));
+ table.addColumn(new MColumn("name","varchar(20)"));
+ table.addColumn(new MColumn("comment","varchar(1000)"));
+
+ return table;
+ }
+
+ MTable newTableAdd2Columns() {
+ MTable table = new MTable("tab");
+ table.addColumn(new MColumn("id","bigint"));
+ table.addColumn(new MColumn("name","varchar(20)"));
+ table.addColumn(new MColumn("status","varchar(3)"));
+ table.addColumn(new MColumn("comment","varchar(1000)"));
+ table.addColumn(new MColumn("note","varchar(2000)"));
+ return table;
+ }
+
+ MTable newTableModifiedColumn() {
+ MColumn modCol = new MColumn("name", "varchar(30)");// modified type
+ modCol.setNotnull(true);
+
+ MTable table = new MTable("tab");
+ table.addColumn(modCol);
+ table.addColumn(new MColumn("id","bigint"));
+ table.addColumn(new MColumn("status","varchar(3)"));
+ return table;
+ }
+
+ @Test
+ public void testCompare_addColumnDropColumn() throws Exception {
+
+ ModelDiff diff = new ModelDiff();
+ diff.compareTables(base(), newTable());
+
+ List createChanges = diff.getCreateChanges();
+ assertThat(createChanges).hasSize(1);
+ AddColumn addColumn = (AddColumn)createChanges.get(0);
+ assertThat(addColumn.getColumn()).extracting("name").contains("comment");
+ assertThat(addColumn.getColumn()).extracting("type").contains("varchar(1000)");
+
+ List dropChanges = diff.getDropChanges();
+ assertThat(dropChanges).hasSize(1);
+
+ DropColumn dropColumn = (DropColumn)dropChanges.get(0);
+ assertThat(dropColumn.getColumnName()).isEqualTo("status");
+ assertThat(dropColumn.getTableName()).isEqualTo("tab");
+ }
+
+ @Test
+ public void testCompare_addTwoColumnsToSameTable() throws Exception {
+
+ ModelDiff diff = new ModelDiff();
+ diff.compareTables(base(), newTableAdd2Columns());
+
+ List createChanges = diff.getCreateChanges();
+ assertThat(createChanges).hasSize(1);
+
+ AddColumn addColumn = (AddColumn)createChanges.get(0);
+ assertThat(addColumn.getColumn()).extracting("name").contains("comment","note");
+ assertThat(addColumn.getColumn()).extracting("type").contains("varchar(1000)","varchar(2000)");
+
+ assertThat(diff.getDropChanges()).hasSize(0);
+
+ }
+
+ @Test
+ public void testCompare_modifyColumn() throws Exception {
+
+ ModelDiff diff = new ModelDiff();
+ diff.compareTables(base(), newTableModifiedColumn());
+
+ List createChanges = diff.getCreateChanges();
+ assertThat(createChanges).hasSize(1);
+
+ AlterColumn alterColumn = (AlterColumn)createChanges.get(0);
+ assertThat(alterColumn.getColumnName()).isEqualTo("name");
+ assertThat(alterColumn.getType()).isEqualTo("varchar(30)");
+ assertThat(alterColumn.isNotnull()).isEqualTo(true);
+ assertThat(alterColumn.isUnique()).isNull();
+ assertThat(alterColumn.getNewCheckConstraint()).isNull();
+ assertThat(alterColumn.getNewReferences()).isNull();
+
+ assertThat(diff.getDropChanges()).hasSize(0);
+
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/MigrationModelTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/MigrationModelTest.java
new file mode 100644
index 000000000..1cc725e62
--- /dev/null
+++ b/src/test/java/com/avaje/ebean/dbmigration/model/MigrationModelTest.java
@@ -0,0 +1,39 @@
+package com.avaje.ebean.dbmigration.model;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.*;
+
+public class MigrationModelTest {
+
+ @Test
+ public void testRead() throws Exception {
+
+ MigrationModel migrationModel = new MigrationModel("dbmigration/app1");
+ ModelContainer model = migrationModel.read();
+
+ assertThat(migrationModel.getReadVersions()).contains("1.0","1.1","2.0");
+ assertThat(model.getTable("v10_table")).isNotNull();
+ }
+
+ @Test
+ public void testRead_leadingSlash() throws Exception {
+
+ MigrationModel migrationModel = new MigrationModel("/dbmigration/app1");
+ ModelContainer model = migrationModel.read();
+
+ assertThat(migrationModel.getReadVersions()).contains("1.0","1.1","2.0");
+ assertThat(model.getTable("v10_table")).isNotNull();
+ }
+
+ @Test
+ public void testRead_trailingSlash() throws Exception {
+
+ MigrationModel migrationModel = new MigrationModel("/dbmigration/app1/");
+ ModelContainer model = migrationModel.read();
+
+ assertThat(migrationModel.getReadVersions()).contains("1.0","1.1","2.0");
+ assertThat(model.getTable("v10_table")).isNotNull();
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java b/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java
index 57fe09f4d..c60798008 100644
--- a/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java
+++ b/src/test/java/com/avaje/ebean/dbmigration/model/ModelContainerApplyTest.java
@@ -32,7 +32,7 @@ public class ModelContainerApplyTest {
model.apply(migration);
MTable foo = model.getTable("foo");
- assertThat(foo.getRemarks()).isEqualTo("comment");
+ assertThat(foo.getComment()).isEqualTo("comment");
assertThat(foo.getTablespace()).isEqualTo("fooSpace");
assertThat(foo.getIndexTablespace()).isEqualTo("fooIndexSpace");
assertThat(foo.getWithHistory()).isEqualTo(true);
diff --git a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTimeTest.java b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTimeTest.java
new file mode 100644
index 000000000..948fee29a
--- /dev/null
+++ b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalDateTimeTest.java
@@ -0,0 +1,43 @@
+package com.avaje.ebeaninternal.server.type;
+
+import com.avaje.ebean.config.JsonConfig;
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDateTime;
+import org.junit.Test;
+
+import java.sql.Timestamp;
+
+import static org.junit.Assert.*;
+
+public class ScalarTypeJodaLocalDateTimeTest {
+
+ ScalarTypeJodaLocalDateTime type = new ScalarTypeJodaLocalDateTime(JsonConfig.DateTime.ISO8601);
+
+ @Test
+ public void testConvertFromTimestamp() throws Exception {
+
+ long now = System.currentTimeMillis();
+ Timestamp nowTs = new Timestamp(now);
+
+ LocalDateTime ldt1 = type.convertFromTimestamp(nowTs);
+ LocalDateTime ldt2 = localConvertFromTimestamp(nowTs);
+
+ assertEquals(ldt1, ldt2);
+
+ Timestamp ts1 = type.convertToTimestamp(ldt1);
+ Timestamp ts2 = localConvertToTimestamp(ldt2);
+
+ assertEquals(ts1, ts2);
+ }
+
+
+ LocalDateTime localConvertFromTimestamp(Timestamp ts) {
+ return new LocalDateTime(ts.getTime(), DateTimeZone.getDefault());
+ }
+
+
+ Timestamp localConvertToTimestamp(LocalDateTime t) {
+ return new Timestamp(t.toDateTime(DateTimeZone.getDefault()).getMillis());
+ }
+
+}
\ No newline at end of file
diff --git a/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTimeTest.java b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTimeTest.java
new file mode 100644
index 000000000..952fc765c
--- /dev/null
+++ b/src/test/java/com/avaje/ebeaninternal/server/type/ScalarTypeJodaLocalTimeTest.java
@@ -0,0 +1,32 @@
+package com.avaje.ebeaninternal.server.type;
+
+import org.joda.time.DateTimeZone;
+import org.joda.time.LocalDateTime;
+import org.junit.Test;
+
+import java.sql.Timestamp;
+
+import static org.junit.Assert.assertEquals;
+
+public class ScalarTypeJodaLocalTimeTest {
+
+ @Test
+ public void test() {
+
+ long now = System.currentTimeMillis();
+
+ //DateTimeZone timeZone = DateTimeZone.getDefault();
+ //ISOChronology instance = ISOChronology.getInstance();
+
+ LocalDateTime ldt1 = new LocalDateTime(now, DateTimeZone.getDefault());
+ LocalDateTime ldt2 = new LocalDateTime(now);
+
+ assertEquals(ldt1, ldt2);
+
+ Timestamp ts1 = new Timestamp(ldt1.toDateTime(DateTimeZone.getDefault()).getMillis());
+ Timestamp ts2 = new Timestamp(ldt2.toDateTime().getMillis());
+
+ assertEquals(ts1, ts2);
+
+ }
+}
\ No newline at end of file
diff --git a/src/test/resources/dbmigration/app1/v1.0.xml b/src/test/resources/dbmigration/app1/v1.0.xml
index 2430f2933..2bf781566 100644
--- a/src/test/resources/dbmigration/app1/v1.0.xml
+++ b/src/test/resources/dbmigration/app1/v1.0.xml
@@ -13,7 +13,7 @@
-
+
@@ -21,17 +21,6 @@
-
-
-
-
-
-
-
-
-
-
-
@@ -47,7 +36,7 @@
-
+
diff --git a/src/test/resources/dbmigration/app1/v1.1.xml b/src/test/resources/dbmigration/app1/v1.1.xml
index ee8e19b74..bf9bef4e2 100644
--- a/src/test/resources/dbmigration/app1/v1.1.xml
+++ b/src/test/resources/dbmigration/app1/v1.1.xml
@@ -13,7 +13,7 @@
-
+
@@ -21,34 +21,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/test/resources/dbmigration/app1/v10.0.xml b/src/test/resources/dbmigration/app1/v10.0.xml
deleted file mode 100644
index 382686d17..000000000
--- a/src/test/resources/dbmigration/app1/v10.0.xml
+++ /dev/null
@@ -1,53 +0,0 @@
-
-
-
-
-
-
-
- create table foo;
-
-
- drop table if exists foo;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/test/resources/dbmigration/app1/v2.0.xml b/src/test/resources/dbmigration/app1/v2.0.xml
index 800f3c876..5e5bb7815 100644
--- a/src/test/resources/dbmigration/app1/v2.0.xml
+++ b/src/test/resources/dbmigration/app1/v2.0.xml
@@ -13,39 +13,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/test/resources/dbmigration/app1/v9.0.xml b/src/test/resources/dbmigration/app1/v9.0.xml
deleted file mode 100644
index 800f3c876..000000000
--- a/src/test/resources/dbmigration/app1/v9.0.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-
-
-
-
-
-
-
- create table foo;
-
-
- drop table if exists foo;
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/test/resources/dbmigration/applications.xml b/src/test/resources/dbmigration/applications.xml
deleted file mode 100644
index 9c01f1b8f..000000000
--- a/src/test/resources/dbmigration/applications.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/test/resources/ebean.properties b/src/test/resources/ebean.properties
index 8a6a405f1..4d273cc87 100644
--- a/src/test/resources/ebean.properties
+++ b/src/test/resources/ebean.properties
@@ -23,7 +23,7 @@ ebean.autofetch.traceUsageCollection=false
ebean.ddl.generate=true
ebean.ddl.run=true
-datasource.default=ms
+datasource.default=h2
ebean.persistBatch=NONE
ebean.persistBatchOnCascade=ALL
@@ -46,6 +46,9 @@ ebean.cacheWarmingDelay=-1
##ebean.transaction.rollbackOnChecked=false
+ebean.migration.appName=myapp
+ebean.migration.resourcePath=dbmigration/myapp
+
## -------------------------------------------------------------
## DataSources (If using default Ebean DataSourceFactory)
diff --git a/src/test/resources/logback-test.xml b/src/test/resources/logback-test.xml
index 7e2ff7fee..816e4a15b 100644
--- a/src/test/resources/logback-test.xml
+++ b/src/test/resources/logback-test.xml
@@ -33,7 +33,7 @@
-
+