DB migration initial

This commit is contained in:
Robin Bygrave
2015-08-04 17:37:16 +12:00
parent 30c3a435d6
commit 3bd281bea0
93 changed files with 8350 additions and 34 deletions
+1273
View File
File diff suppressed because it is too large Load Diff
@@ -7,6 +7,7 @@ import javax.sql.DataSource;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.Query;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -145,6 +146,8 @@ public class DatabasePlatform {
*/
protected boolean disallowBatchOnCascade;
protected PlatformDdl platformDdl;
/**
* Instantiates a new database platform.
*/
@@ -164,6 +167,10 @@ public class DatabasePlatform {
return name;
}
public PlatformDdl getPlatformDdl() {
return platformDdl;
}
/**
* Return true if the JDBC driver does not allow additional queries to execute
* when a resultSet is being 'streamed' as is the case with findEach() etc.
@@ -1,6 +1,7 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import javax.sql.DataSource;
@@ -12,6 +13,7 @@ public class H2Platform extends DatabasePlatform {
public H2Platform() {
super();
this.name = "h2";
this.platformDdl = new H2Ddl(this.dbTypeMap);
this.dbEncrypt = new H2DbEncrypt();
// like ? escape'' not working in the latest version H2 so just using no
// escape clause for now noting that backslash is an escape char for like in H2
@@ -1,6 +1,8 @@
package com.avaje.ebean.config.dbplatform;
import com.avaje.ebean.BackgroundExecutor;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
import javax.sql.DataSource;
import java.sql.Types;
@@ -16,6 +18,8 @@ public class PostgresPlatform extends DatabasePlatform {
public PostgresPlatform() {
super();
this.name = "postgres";
this.platformDdl = new PostgresDdl(this.dbTypeMap);
// OnQueryOnly.CLOSE as a performance optimisation on Postgres
this.onQueryOnly = OnQueryOnly.CLOSE;
this.likeClause = "like ? escape''";
@@ -0,0 +1,59 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseColumnDdl;
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.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.io.IOException;
import java.util.List;
/**
*
*/
public class BaseDdlHandler implements DdlHandler {
protected final ColumnDdl columnDdl;
protected final TableDdl tableDdl;
public BaseDdlHandler(DdlNamingConvention namingConvention, PlatformDdl platformDdl) {
this.tableDdl = new BaseTableDdl(namingConvention, platformDdl);
this.columnDdl = new BaseColumnDdl();
}
@Override
public void generate(DdlWrite writer, ChangeSet changeSet) throws IOException {
List<Object> changeSetChildren = changeSet.getChangeSetChildren();
for (Object change : changeSetChildren) {
if (change instanceof CreateTable) {
generate(writer, (CreateTable) change);
} else if (change instanceof AddColumn) {
generate(writer, (AddColumn) change);
} else if (change instanceof DropColumn) {
generate(writer, (DropColumn) change);
}
}
}
@Override
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
tableDdl.generate(writer, createTable);
}
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
columnDdl.generate(writer, addColumn);
}
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
columnDdl.generate(writer, dropColumn);
}
}
@@ -0,0 +1,23 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.io.IOException;
/**
* Write AddColumn or DropColumn.
*/
public interface ColumnDdl {
/**
* Write a AddColumn change.
*/
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
/**
* Write a DropColumn change.
*/
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
}
@@ -0,0 +1,52 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import java.io.IOException;
/**
* Buffer to append generated DDL to.
*/
public interface DdlBuffer {
/**
* Return the configuration (default tablespaces etc).
*/
MConfiguration getConfiguration();
/**
* Append DDL content to the buffer.
*/
DdlBuffer append(String content) throws IOException;
/**
* Append DDL content to the buffer with space padding.
*/
DdlBuffer append(String type, int space) throws IOException;
/**
* Append a value that is potentially null or empty and proceed it with a space if so.
*/
DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException;
/**
* Append new line character to the buffer.
*/
DdlBuffer newLine() throws IOException;
/**
* Append the end of statement content.
*/
DdlBuffer endOfStatement() throws IOException;
/**
* End of a change - add some whitespace.
*/
DdlBuffer end() throws IOException;
/**
* Return the buffer content.
*/
String getBuffer();
}
@@ -0,0 +1,21 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.io.IOException;
/**
*/
public interface DdlHandler {
void generate(DdlWrite writer, ChangeSet changeSet) throws IOException;
void generate(DdlWrite writer, CreateTable createTable) throws IOException;
void generate(DdlWrite writer, AddColumn addColumn) throws IOException;
void generate(DdlWrite writer, DropColumn dropColumn) throws IOException;
}
@@ -0,0 +1,97 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.BaseDdlBuffer;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
/**
* Write context holding the buffers for both apply and rollback DDL.
*/
public class DdlWrite {
private final ModelContainer currentModel;
private final DdlBuffer apply;
private final DdlBuffer applyForeignKeys;
private final DdlBuffer applyHistory;
private final DdlBuffer rollbackForeignKeys;
private final DdlBuffer rollbackLast;
/**
* Create without any configuration or current model (no history support).
*/
public DdlWrite() {
this(new MConfiguration(), new ModelContainer());
}
/**
* Create with a configuration.
*/
public DdlWrite(MConfiguration configuration, ModelContainer currentModel) {
this.currentModel = currentModel;
this.apply = new BaseDdlBuffer(configuration);
this.applyForeignKeys = new BaseDdlBuffer(configuration);
this.applyHistory = new BaseDdlBuffer(configuration);
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
this.rollbackLast = new BaseDdlBuffer(configuration);
}
/**
* Return the Table information from the current model.
* <p>
* This is typically required for the history support (used to determine the list of columns
* included in the history when creating or recreating the associated trigger/stored procedure).
* </p>
*/
public MTable getTable(String tableName) {
return currentModel.getTable(tableName);
}
/**
* Return the buffer that APPLY DDL is written to.
*/
public DdlBuffer apply() {
return apply;
}
/**
* Return the buffer that APPLY DDL is written to for foreign keys and their associated indexes.
* <p>
* Statements added to this buffer are executed after all the normal apply statements and
* typically 'add foreign key' is added to this buffer.
*/
public DdlBuffer applyForeignKeys() {
return applyForeignKeys;
}
/**
* Return the buffer that apply history DDL is written to.
*/
public DdlBuffer applyHistory() {
return applyHistory;
}
/**
* Return the buffer that ROLLBACK DDL is written to for foreign keys and associated indexes.
*/
public DdlBuffer rollbackForeignKeys() {
return rollbackForeignKeys;
}
/**
* Return the buffer that ROLLBACK DDL is written to (typically drop tables).
* <p>
* Statements added to this rollback buffer are executed after foreign key rollback
* has been executed.
*/
public DdlBuffer rollback() {
return rollbackLast;
}
}
@@ -0,0 +1,16 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import java.io.IOException;
/**
* Write table DDL.
*/
public interface TableDdl {
/**
* Generate the create table DDL.
*/
void generate(DdlWrite writer, CreateTable createTable) throws IOException;
}
@@ -0,0 +1,69 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
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.Column;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.io.IOException;
import java.util.List;
/**
*/
public class BaseColumnDdl implements ColumnDdl {
@Override
public void generate(DdlWrite writer, AddColumn addColumn) throws IOException {
String tableName = addColumn.getTableName();
List<Column> columns = addColumn.getColumn();
for (Column column : columns) {
// apply
alterTableAddColumn(writer.apply(), tableName, column);
// rollback
alterTableDropColumn(writer.rollback(), tableName, column.getName());
}
}
@Override
public void generate(DdlWrite writer, DropColumn dropColumn) throws IOException {
String tableName = dropColumn.getTableName();
alterTableDropColumn(writer.apply(), tableName, dropColumn.getColumnName());
// no good rollback option here, it is best if drop columns
// are put into a separate changeSet that is run last
}
protected void alterTableDropColumn(DdlBuffer buffer, String tableName, String columnName) throws IOException {
buffer.append("alter table ").append(tableName)
.append(" drop column ").append(columnName)
.endOfStatement().end();
}
protected void alterTableAddColumn(DdlBuffer buffer, String tableName, Column column) throws IOException {
buffer.append("alter table ").append(tableName)
.append(" add column ").append(column.getName())
.append(" ").append(column.getType());
if (Boolean.TRUE.equals(column.isNotnull())) {
buffer.append(" not null");
}
if (hasValue(column.getCheckConstraint())) {
buffer.append(" ").append(column.getCheckConstraint());
}
buffer.endOfStatement().end();
}
protected boolean hasValue(String value) {
return value != null && !value.trim().isEmpty();
}
}
@@ -0,0 +1,84 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
/**
* Base implementation of DdlBuffer using an underlying writer.
*/
public class BaseDdlBuffer implements DdlBuffer {
protected final Writer writer;
protected final MConfiguration configuration;
public BaseDdlBuffer(MConfiguration configuration) {
this.configuration = configuration;
this.writer = new StringWriter();
}
@Override
public MConfiguration getConfiguration() {
return configuration;
}
@Override
public DdlBuffer appendWithSpace(String foreignKeyRestrict) throws IOException {
if (foreignKeyRestrict != null && !foreignKeyRestrict.isEmpty()) {
writer.append(" ").append(foreignKeyRestrict);
}
return this;
}
@Override
public DdlBuffer append(String content) throws IOException {
writer.append(content);
return this;
}
@Override
public DdlBuffer append(String content, int space) throws IOException {
writer.append(content);
appendSpace(space, content);
return this;
}
protected void appendSpace(int max, String content) throws IOException {
int space = max - content.length();
if (space > 0) {
for (int i = 0; i < space; i++) {
append(" ");
}
}
}
@Override
public DdlBuffer endOfStatement() throws IOException {
writer.append(";\n");
return this;
}
/**
* Used to demarcate the end of a series of statements.
* This should be just whitespace or a sql comment.
*/
@Override
public DdlBuffer end() throws IOException {
writer.append("\n");
return this;
}
@Override
public DdlBuffer newLine() throws IOException {
writer.append("\n");
return this;
}
public String getBuffer() {
return writer.toString();
}
}
@@ -0,0 +1,356 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.ddlgeneration.TableDdl;
import com.avaje.ebean.dbmigration.migration.Column;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* Base implementation for 'create table' and 'alter table' statements.
*/
public class BaseTableDdl implements TableDdl {
protected final DdlNamingConvention namingConvention;
protected final PlatformDdl platformDdl;
public BaseTableDdl(DdlNamingConvention namingConvention, PlatformDdl platformDdl) {
this.namingConvention = namingConvention;
this.platformDdl = platformDdl;
}
/**
* Generate the appropriate 'create table' and matching 'drop table' statements
* and add them to the 'apply' and 'rollback' buffers.
*/
@Override
public void generate(DdlWrite writer, CreateTable createTable) throws IOException {
String tableName = createTable.getName();
List<Column> columns = createTable.getColumn();
List<Column> pk = determinePrimaryKeyColumns(columns);
DdlBuffer apply = writer.apply();
apply.append("create table ").append(tableName).append(" (");
for (int i = 0; i < columns.size(); i++) {
apply.newLine();
writeColumnDefinition(apply, columns.get(i));
if (i < columns.size() - 1) {
apply.append(",");
}
}
writeCheckConstraints(apply, createTable);
writeUniqueConstraints(apply, createTable);
writeCompoundUniqueConstraints(apply, createTable);
if (!pk.isEmpty()) {
writePrimaryKeyConstraint(apply, tableName, pk);
}
apply.newLine().append(")").endOfStatement();
apply.end();
writeAddForeignKeys(writer, createTable);
// add drop table to the rollback buffer
dropTable(writer.rollback(), tableName);
if (isTrue(createTable.isWithHistory())) {
createWithHistory(writer, createTable.getName());
}
}
private void createWithHistory(DdlWrite writer, String name) throws IOException {
MTable table = writer.getTable(name);
platformDdl.createWithHistory(writer, table);
}
protected void writeAddForeignKeys(DdlWrite write, CreateTable createTable) throws IOException {
List<Column> columns = createTable.getColumn();
for (Column column : columns) {
String references = column.getReferences();
if (hasValue(references)) {
writeForeignKey(write, createTable.getName(), column.getName(), references);
}
}
//createTable.
}
protected void writeForeignKey(DdlWrite write, String tableName, String columnName, String references) throws IOException {
String fkName = determineForeignKeyConstraintName(tableName, columnName);
int pos = references.lastIndexOf('.');
if (pos == -1) {
throw new IllegalStateException("Expecting period '.' character for table.column split but not found in [" + references + "]");
}
String refTableName = references.substring(0, pos);
String refColumnName = references.substring(pos + 1);
String[] cols = {columnName};
String[] refCols = {refColumnName};
writeForeignKey(write, fkName, tableName, cols, refTableName, refCols);
}
protected void writeForeignKey(DdlWrite write, String fkName, String tableName, String[] columns, String refTable, String[] refColumns) throws IOException {
DdlBuffer fkeyBuffer = write.applyForeignKeys();
fkeyBuffer
.append("alter table ").append(tableName)
.append(" add constraint ").append(fkName)
.append(" foreign key (");
appendColumns(columns, fkeyBuffer);
fkeyBuffer
.append(") references ")
.append(refTable);
appendColumns(refColumns, fkeyBuffer);
fkeyBuffer.appendWithSpace(platformDdl.getForeignKeyRestrict())
.endOfStatement();
String indexName = determineForeignKeyIndexName(tableName, columns);
fkeyBuffer.append("create index ").append(indexName).append(" on ").append(tableName);
appendColumns(columns, fkeyBuffer);
fkeyBuffer.endOfStatement();
fkeyBuffer.end();
write.rollbackForeignKeys()
.append("drop index ").append(indexName)
.endOfStatement();
write.rollbackForeignKeys()
.append("alter table ").append(tableName).append(" drop constraint ").append(fkName)
.endOfStatement();
write.rollbackForeignKeys().end();
}
private void appendColumns(String[] columns, DdlBuffer buffer) throws IOException {
buffer.append(" (");
for (int i = 0; i <columns.length ; i++) {
if (i > 0) {
buffer.append(",");
}
buffer.append(columns[i]);
}
buffer.append(")");
}
/**
* Add 'drop table' statement to the buffer.
*/
protected void dropTable(DdlBuffer buffer, String tableName) throws IOException {
buffer.append("drop table ").append(tableName).endOfStatement().end();
}
/**
* Write all the check constraints.
*/
protected void writeCheckConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
List<Column> columns = createTable.getColumn();
for (Column column : columns) {
String checkConstraint = column.getCheckConstraint();
if (hasValue(checkConstraint)) {
writeCheckConstraint(apply, createTable.getName(), column, checkConstraint);
}
}
}
/**
* Write a check constraint.
*/
protected void writeCheckConstraint(DdlBuffer buffer, String tableName, Column column, String checkConstraint) throws IOException {
String ckName = determineCheckConstraintName(tableName, column.getName());
buffer.append(",").newLine();
buffer.append(" constraint ").append(ckName);
buffer.append(" ").append(checkConstraint);
}
protected void writeCompoundUniqueConstraints(DdlBuffer apply, CreateTable createTable) {
//TODO: Write compound unique constraints
}
/**
* Write the unique constraints inline with the create table statement.
*/
protected void writeUniqueConstraints(DdlBuffer apply, CreateTable createTable) throws IOException {
List<Column> columns = createTable.getColumn();
for (Column column : columns) {
if (isTrue(column.isUnique())) {
inlineUniqueConstraintSingle(apply, createTable.getName(), column);
}
}
}
/**
* Write the unique constraint inline with the create table statement.
*/
protected void inlineUniqueConstraintSingle(DdlBuffer buffer, String tableName, Column column) throws IOException {
String uqName = determineUniqueConstraintName(tableName, column.getName());
buffer.append(",").newLine();
buffer.append(" constraint ").append(uqName).append(" unique ");
buffer.append("(");
buffer.append(column.getName());
buffer.append(")");
}
/**
* Write the primary key constraint inline with the create table statement.
*/
protected void writePrimaryKeyConstraint(DdlBuffer buffer, String tableName, List<Column> pk) throws IOException {
String pkName = determinePrimaryKeyName(tableName, pk);
buffer.append(",").newLine();
buffer.append(" constraint ").append(pkName).append(" primary key ");
buffer.append("(");
for (int i = 0; i < pk.size(); i++) {
if (i > 0) {
buffer.append(",");
}
buffer.append(pk.get(i).getName());
}
buffer.append(")");
}
/**
* Write alter table add primary key statement.
*/
public void alterTableAddPrimaryKey(DdlBuffer buffer, String tableName, List<Column> pk) throws IOException {
String pkName = determinePrimaryKeyName(tableName, pk);
buffer.append("alter table ").append(tableName);
buffer.append(" add primary key ").append(pkName).append(" (");
for (int i = 0; i < pk.size(); i++) {
if (i > 0) {
buffer.append(",");
}
buffer.append(pk.get(i).getName());
}
buffer.append(")").endOfStatement();
}
/**
* Write the column definition to the create table statement.
*/
protected void writeColumnDefinition(DdlBuffer buffer, Column column) throws IOException {
String platformType = convertToPlatformType(column.getType(), isTrue(column.isIdentity()));
buffer.append(" ");
buffer.append(column.getName(), 30);
buffer.append(platformType);
if (isTrue(column.isNotnull()) || isTrue(column.isPrimaryKey())) {
buffer.append(" not null");
}
// add check constraints later as we really want to give them a nice name
// so that the database can potentially provide a nice SQL error
}
/**
* Convert the expected logical type into a platform specific one.
* <p>
* For example clob -> text for postgres.
* </p>
*/
protected String convertToPlatformType(String type, boolean identity) {
return platformDdl.convert(type, identity);
}
/**
* Return the primary key constraint name.
*/
protected String determinePrimaryKeyName(String tableName, List<Column> pkColumns) {
// collect the primary key column names
List<String> pkColumnNames = new ArrayList<String>(pkColumns.size());
for (int i = 0; i < pkColumns.size(); i++) {
pkColumnNames.add(pkColumns.get(i).getName());
}
return namingConvention.primaryKeyName(tableName, pkColumnNames);
}
/**
* Return the foreign key constraint name given a single column foreign key.
*/
protected String determineForeignKeyConstraintName(String tableName, String columnName) {
return namingConvention.foreignKeyConstraintName(tableName, columnName);
}
/**
* Return the foreign key constraint name given a single column foreign key.
*/
protected String determineForeignKeyIndexName(String tableName, String[] columns) {
return namingConvention.foreignKeyIndexName(tableName, columns);
}
/**
* Return the unique constraint name.
*/
protected String determineUniqueConstraintName(String tableName, String columnName) {
return namingConvention.uniqueConstraintName(tableName, columnName);
}
/**
* Return the constraint name.
*/
protected String determineCheckConstraintName(String tableName, String columnName) {
return namingConvention.checkConstraintName(tableName, columnName);
}
/**
* Return the list of columns that make the primary key.
*/
protected List<Column> determinePrimaryKeyColumns(List<Column> columns) {
List<Column> pk = new ArrayList<Column>(3);
for (Column column : columns) {
if (isTrue(column.isPrimaryKey())) {
pk.add(column);
}
}
return pk;
}
/**
* Return true if null or trimmed string is empty.
*/
protected boolean hasValue(String value) {
return value != null && !value.trim().isEmpty();
}
/**
* Null safe Boolean true test.
*/
protected boolean isTrue(Boolean value) {
return Boolean.TRUE.equals(value);
}
}
@@ -0,0 +1,42 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
/**
* Used to normalise table and column names which means stripping out
* quoted identifier characters and any catalog or schema prefix.
*/
public class DbNameNormalise {
protected boolean lowerCase = true;
protected String[] quotedIdentifiers = {"\"", "'", "[", "]", "`"};
/**
* Normalise the table name by trimming catalog and schema and removing any
* quoted identifier characters (",',[,] etc).
*/
public String normalise(String tableName) {
tableName = trimQuotes(tableName);
int lastPeriod = tableName.lastIndexOf('.');
if (lastPeriod > -1) {
tableName = tableName.substring(lastPeriod + 1);
}
if (lowerCase) {
tableName = tableName.toLowerCase();
}
return tableName;
}
/**
* Trim off the platform quoted identifier quotes like [ ' and ".
*/
protected String trimQuotes(String tableName) {
// remove quoted identifier characters
for (int i = 0; i < quotedIdentifiers.length; i++) {
tableName = tableName.replace(quotedIdentifiers[i], "");
}
return tableName;
}
}
@@ -0,0 +1,96 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebeaninternal.server.type.ScalarTypeBoolean;
import java.util.List;
/**
* Naming convention used for constraint names.
*/
public class DdlNamingConvention {
protected String pkPrefix = "pk_";
protected String pkSuffix = "";
protected String fkPrefix = "fk_";
protected String fkMiddle = "_";
protected String fkSuffix = "";
protected String fkIndexPrefix = "ix_";
protected String fkIndexMiddle = "_";
protected String fkIndexSuffix = "";
protected String uqPrefix = "uq_";
protected String uqSuffix = "";
protected String ckPrefix = "ck_";
protected String ckSuffix = "";
protected final DbNameNormalise normalise;
public DdlNamingConvention() {
this.normalise = new DbNameNormalise();
}
/**
* Return the primary key constraint name.
*/
public String primaryKeyName(String tableName, List<String> pkColumns) {
return pkPrefix + normalise(tableName) + pkSuffix;
}
/**
* Return the foreign key constraint name given a single column foreign key.
*/
public String foreignKeyConstraintName(String tableName, String columnName) {
return fkPrefix + normalise(tableName) + fkMiddle + normalise(columnName) + fkSuffix;
}
/**
* Return the index name associated with a foreign key constraint given a single column foreign key.
*/
public String foreignKeyIndexName(String tableName, String[] columns) {
String cols = columns.length == 1 ? normalise(columns[0]) : joinColumns(columns);
return fkIndexPrefix + normalise(tableName) + fkIndexMiddle + cols + fkIndexSuffix;
}
private String joinColumns(String[] columns) {
//TODO: Fix this to handle maximum constraint name limits
StringBuilder sb = new StringBuilder(30);
for (int i = 0; i < columns.length; i++) {
if (i > 0) {
sb.append("-");
}
sb.append(columns[i]);
}
return sb.toString();
}
/**
* Return the unique constraint name.
*/
public String uniqueConstraintName(String tableName, String columnName) {
return uqPrefix + normalise(tableName) + "_" + normalise(columnName) + uqSuffix;
}
/**
* Return the check constraint name.
*/
public String checkConstraintName(String tableName, String columnName) {
return ckPrefix + normalise(tableName) + "_" + normalise(columnName) + ckSuffix;
}
/**
* Normalise the table name by trimming catalog and schema and removing any
* quoted identifier characters (",',[,] etc).
*/
protected String normalise(String tableName) {
return normalise.normalise(tableName);
}
}
@@ -0,0 +1,14 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
/**
* H2 platform specific DDL.
*/
public class H2Ddl extends PlatformDdl {
public H2Ddl(DbTypeMap platformTypes) {
super(platformTypes, new H2HistoryDdl());
this.foreignKeyRestrict = "on delete restrict on update restrict";
}
}
@@ -0,0 +1,17 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
/**
*
*/
public class H2HistoryDdl implements PlatformHistoryDdl {
@Override
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
// does nothing, not supported yet
}
}
@@ -0,0 +1,53 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
/**
*
*/
public class PlatformDdl {
protected final PlatformHistoryDdl historyDdl;
protected final PlatformTypeConverter typeConverter;
protected String foreignKeyRestrict = "";
public PlatformDdl(DbTypeMap platformTypes, PlatformHistoryDdl historyDdl) {
this.typeConverter = new PlatformTypeConverter(platformTypes);
this.historyDdl = historyDdl;
}
/**
* Modify and return the column definition for autoincrement or identity definition.
*/
public String asIdentityColumn(String columnDefn) {
return columnDefn;
}
/**
* Return the foreign key on delete on update restrict clause.
*/
public String getForeignKeyRestrict() {
return foreignKeyRestrict;
}
/**
* Convert the standard type to the platform specific type.
*/
public String convert(String type, boolean identity) {
String platformType = typeConverter.convert(type);
return identity ? asIdentityColumn(platformType) : platformType;
}
/**
* Add history support to this table using the platform specific mechanism.
*/
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
historyDdl.createWithHistory(writer, table);
}
}
@@ -0,0 +1,17 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
/**
* Defines the implementation for adding history support to a table.
*/
public interface PlatformHistoryDdl {
/**
* Add history support to the table using platform specific mechanism.
*/
void createWithHistory(DdlWrite writer, MTable table) throws IOException;
}
@@ -0,0 +1,84 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
/**
* Converts a logical column definition into platform specific one.
*
* This translates standard sql types into platform specific ones.
*/
public class PlatformTypeConverter {
protected final DbTypeMap platformTypes;
/**
* Construct with the platform specific types.
*/
public PlatformTypeConverter(DbTypeMap platformTypes) {
this.platformTypes = platformTypes;
}
/**
* Convert the standard type to the platform specific type.
*/
public String convert(String columnDefinition) {
int open = columnDefinition.indexOf('(');
if (open > -1) {
// no scale or precision
return convertWithScale(columnDefinition, open);
} else {
return convertNoScale(columnDefinition);
}
}
/**
* Convert a type that has scale and possibly precision.
*/
protected String convertWithScale(String columnDefinition, int open) {
int close = columnDefinition.lastIndexOf(')');
if (close == -1) {
// assume already platform specific, leave as is
return columnDefinition;
}
String type = columnDefinition.substring(0,open);
try {
DbType dbType = platformTypes.lookup(type);
int comma = columnDefinition.indexOf(',',open);
if (comma > -1) {
// scale and precision - decimal(10,4)
int scale = Integer.parseInt(columnDefinition.substring(open+1, comma));
int precision = Integer.parseInt(columnDefinition.substring(comma+1, close));
return dbType.renderType(scale,precision);
} else {
// scale - varchar(10)
int scale = Integer.parseInt(columnDefinition.substring(open+1, close));
return dbType.renderType(scale,0);
}
} catch (IllegalArgumentException e) {
// assume already platform specific, leave as is
return columnDefinition;
}
}
/**
* Convert a simple type with not scale or precision.
*/
protected String convertNoScale(String columnDefinition) {
try {
DbType dbType = platformTypes.lookup(columnDefinition);
return dbType.renderType(0,0);
} catch (IllegalArgumentException e) {
// assume already platform specific, leave as is
return columnDefinition;
}
}
}
@@ -0,0 +1,31 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
/**
* Postgres specific DDL.
*/
public class PostgresDdl extends PlatformDdl {
public PostgresDdl(DbTypeMap platformTypes) {
super(platformTypes, new PostgresHistoryDdl());
this.foreignKeyRestrict = "on delete restrict on update restrict";
}
/**
* Map bigint, integer and smallint into their equivalent serial types.
*/
public String asIdentityColumn(String columnDefn) {
if ("bigint".equalsIgnoreCase(columnDefn)) {
return "bigserial";
}
if ("integer".equalsIgnoreCase(columnDefn)) {
return "serial";
}
if ("smallint".equalsIgnoreCase(columnDefn)) {
return "smallserial";
}
return columnDefn;
}
}
@@ -0,0 +1,135 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
import java.util.Collection;
/**
*
*/
public class PostgresHistoryDdl implements PlatformHistoryDdl {
DbNameNormalise normalise = new DbNameNormalise();
protected String historyTableName(String baseTableName) {
return baseTableName + "_history";
}
protected String procedureName(String baseTableName) {
return baseTableName + "_history_version";
}
protected String triggerName(String baseTableName) {
return baseTableName + "_history_upd";
}
public void createWithHistory(DdlWrite writer, MTable table) throws IOException {
// naming convention
addHistoryTable(writer, table);
addStoredFunction(writer, table);
addTrigger(writer, table);
}
public void addHistoryTable(DdlWrite writer, MTable table) throws IOException {
String baseTableName = this.normalise.normalise(table.getName());
DdlBuffer buffer = writer.applyHistory();
buffer
.append("alter table ").append(baseTableName)
.append(" add column sys_period tstzrange not null")
.endOfStatement().end();
buffer
.append("create table ").append(baseTableName).append("_history")
.append(" (like ").append(baseTableName).append(")")
.endOfStatement().end();
buffer
.append("create view ").append(baseTableName).append("_with_history")
.append(" as select * from").append(baseTableName)
.append(" union all select * from").append(baseTableName).append("_history")
.endOfStatement().end();
}
public void addTrigger(DdlWrite writer, MTable table) throws IOException {
String baseTableName = this.normalise.normalise(table.getName());
String procedureName = procedureName(baseTableName);
String triggerName = triggerName(baseTableName);
DdlBuffer buffer = writer.applyHistory();
buffer
.append("create trigger ").append(triggerName).newLine()
.append(" before insert or update or delete on ").append(baseTableName).newLine()
.append(" for each row execute procedure ").append(procedureName).append("();").newLine().newLine();
}
public void addStoredFunction(DdlWrite writer, MTable table) throws IOException {
String baseTableName = this.normalise.normalise(table.getName());
String procedureName = procedureName(baseTableName);
DdlBuffer buffer = writer.applyHistory();
buffer
.append("create or replace function ").append(procedureName).append("() returns trigger as $$").newLine()
.append("begin").newLine();
buffer
.append(" if (TG_OP = 'INSERT') then").newLine()
.append(" NEW.sys_period = tstzrange(CURRENT_TIMESTAMP,null);").newLine()
.append(" return new;").newLine().newLine();
buffer
.append(" elsif (TG_OP = 'UPDATE') then").newLine();
appendInsertIntoHistory(buffer, table);
buffer
.append(" NEW.sys_period = tstzrange(CURRENT_TIMESTAMP,null);").newLine()
.append(" return new;").newLine().newLine();
buffer
.append(" elsif (TG_OP = 'DELETE') then").newLine();
appendInsertIntoHistory(buffer, table);
buffer
.append(" return old;").newLine().newLine();
buffer
.append(" end if;").newLine()
.append("end;").newLine()
.append("$$ LANGUAGE plpgsql;").newLine();
buffer.end();
}
protected void appendInsertIntoHistory(DdlBuffer buffer, MTable table) throws IOException {
String historyTable = historyTableName(table.getName());
buffer.append(" insert into ").append(historyTable).append(" (sys_period,");
appendColumnNames(buffer, table, "");
buffer.append(") values (tstzrange(lower(OLD.sys_period), CURRENT_TIMESTAMP), ");
appendColumnNames(buffer, table, "OLD.");
buffer.append(");").newLine();
}
protected void appendColumnNames(DdlBuffer buffer, MTable table, String columnPrefix) throws IOException {
//id, line1, line2, city, country_code, version, when_created, when_updated
Collection<MColumn> columns = table.getColumns().values();
int i = 0;
for (MColumn column : columns) {
if (++i > 1) {
buffer.append(", ");
}
buffer.append(columnPrefix);
buffer.append(column.getName());
}
}
}
@@ -0,0 +1,99 @@
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.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}column" maxOccurs="unbounded"/>
* &lt;/sequence>
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"column"
})
@XmlRootElement(name = "addColumn")
public class AddColumn {
@XmlElement(required = true)
protected List<Column> column;
@XmlAttribute(name = "tableName", required = true)
protected String tableName;
/**
* Gets the value of the column property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the column property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getColumn().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Column }
*
*
*/
public List<Column> getColumn() {
if (column == null) {
column = new ArrayList<Column>();
}
return this.column;
}
/**
* 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;
}
}
@@ -0,0 +1,143 @@
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;
import javax.xml.bind.annotation.XmlValue;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;simpleContent>
* &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="columns" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="references" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/extension>
* &lt;/simpleContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"value"
})
@XmlRootElement(name = "addForeignKey")
public class AddForeignKey {
@XmlValue
protected String value;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "columns", required = true)
protected String columns;
@XmlAttribute(name = "references", required = true)
protected String references;
/**
* Gets the value of the value property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setValue(String value) {
this.value = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the columns property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getColumns() {
return columns;
}
/**
* Sets the value of the columns property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setColumns(String value) {
this.columns = value;
}
/**
* Gets the value of the references property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getReferences() {
return references;
}
/**
* Sets the value of the references property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setReferences(String value) {
this.references = value;
}
}
@@ -0,0 +1,87 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="resourcePath" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "application")
public class Application {
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "resourcePath", required = true)
protected String resourcePath;
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the resourcePath property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getResourcePath() {
return resourcePath;
}
/**
* Sets the value of the resourcePath property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setResourcePath(String value) {
this.resourcePath = value;
}
}
@@ -0,0 +1,69 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}application" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"application"
})
@XmlRootElement(name = "applications")
public class Applications {
protected List<Application> application;
/**
* Gets the value of the application property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the application property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getApplication().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Application }
*
*
*/
public List<Application> getApplication() {
if (application == null) {
application = new ArrayList<Application>();
}
return this.application;
}
}
@@ -0,0 +1,61 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;simpleContent>
* &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
* &lt;/extension>
* &lt;/simpleContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"value"
})
@XmlRootElement(name = "apply")
public class Apply {
@XmlValue
protected String value;
/**
* Gets the value of the value property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setValue(String value) {
this.value = value;
}
}
@@ -0,0 +1,160 @@
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.XmlElement;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;choice>
* &lt;group ref="{http://ebean-orm.github.io/xml/ns/dbmigration}changeSetChildren" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/choice>
* &lt;/sequence>
* &lt;attribute name="id" use="required" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
* &lt;attribute name="comment" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"changeSetChildren"
})
@XmlRootElement(name = "changeSet")
public class ChangeSet {
@XmlElements({
@XmlElement(name = "configuration", type = Configuration.class),
@XmlElement(name = "sql", type = Sql.class),
@XmlElement(name = "createTable", type = CreateTable.class),
@XmlElement(name = "dropTable", type = DropTable.class),
@XmlElement(name = "renameTable", type = RenameTable.class),
@XmlElement(name = "addHistoryTable", 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)
})
protected List<Object> changeSetChildren;
@XmlAttribute(name = "id", required = true)
@XmlSchemaType(name = "positiveInteger")
protected BigInteger id;
@XmlAttribute(name = "comment")
protected String comment;
/**
* Gets the value of the changeSetChildren property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the changeSetChildren property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getChangeSetChildren().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Configuration }
* {@link Sql }
* {@link CreateTable }
* {@link DropTable }
* {@link RenameTable }
* {@link CreateHistoryTable }
* {@link CreateView }
* {@link DropView }
* {@link RenameView }
* {@link AddColumn }
* {@link DropColumn }
* {@link RenameColumn }
* {@link AddForeignKey }
* {@link DropForeignKey }
*
*
*/
public List<Object> getChangeSetChildren() {
if (changeSetChildren == null) {
changeSetChildren = new ArrayList<Object>();
}
return this.changeSetChildren;
}
/**
* Gets the value of the id property.
*
* @return
* possible object is
* {@link BigInteger }
*
*/
public BigInteger getId() {
return id;
}
/**
* Sets the value of the id property.
*
* @param value
* allowed object is
* {@link BigInteger }
*
*/
public void setId(BigInteger value) {
this.id = value;
}
/**
* Gets the value of the comment property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getComment() {
return comment;
}
/**
* Sets the value of the comment property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setComment(String value) {
this.comment = value;
}
}
@@ -0,0 +1,402 @@
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;
import javax.xml.bind.annotation.XmlValue;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attGroup ref="{http://ebean-orm.github.io/xml/ns/dbmigration}column"/>
* &lt;attGroup ref="{http://ebean-orm.github.io/xml/ns/dbmigration}columnAttributes"/>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"content"
})
@XmlRootElement(name = "column")
public class Column {
@XmlValue
protected String content;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "type", required = true)
protected String type;
@XmlAttribute(name = "defaultValue")
protected String defaultValue;
@XmlAttribute(name = "remarks")
protected String remarks;
@XmlAttribute(name = "notnull")
protected Boolean notnull;
@XmlAttribute(name = "checkConstraint")
protected String checkConstraint;
@XmlAttribute(name = "unique")
protected Boolean unique;
@XmlAttribute(name = "primaryKey")
protected Boolean primaryKey;
@XmlAttribute(name = "identity")
protected Boolean identity;
@XmlAttribute(name = "references")
protected String references;
@XmlAttribute(name = "deleteCascade")
protected Boolean deleteCascade;
@XmlAttribute(name = "deferrable")
protected Boolean deferrable;
@XmlAttribute(name = "initiallyDeferred")
protected Boolean initiallyDeferred;
/**
* Gets the value of the content property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getContent() {
return content;
}
/**
* Sets the value of the content property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setContent(String value) {
this.content = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = 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 defaultValue property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getDefaultValue() {
return defaultValue;
}
/**
* Sets the value of the defaultValue property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setDefaultValue(String value) {
this.defaultValue = value;
}
/**
* Gets the value of the remarks property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getRemarks() {
return remarks;
}
/**
* Sets the value of the remarks property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setRemarks(String value) {
this.remarks = 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 checkConstraint property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getCheckConstraint() {
return checkConstraint;
}
/**
* Sets the value of the checkConstraint property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setCheckConstraint(String value) {
this.checkConstraint = 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 primaryKey property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isPrimaryKey() {
return primaryKey;
}
/**
* Sets the value of the primaryKey property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setPrimaryKey(Boolean value) {
this.primaryKey = value;
}
/**
* Gets the value of the identity property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isIdentity() {
return identity;
}
/**
* Sets the value of the identity property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setIdentity(Boolean value) {
this.identity = value;
}
/**
* Gets the value of the references property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getReferences() {
return references;
}
/**
* Sets the value of the references property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setReferences(String value) {
this.references = value;
}
/**
* Gets the value of the deleteCascade property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isDeleteCascade() {
return deleteCascade;
}
/**
* Sets the value of the deleteCascade property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setDeleteCascade(Boolean value) {
this.deleteCascade = value;
}
/**
* Gets the value of the deferrable property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isDeferrable() {
return deferrable;
}
/**
* Sets the value of the deferrable property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setDeferrable(Boolean value) {
this.deferrable = value;
}
/**
* Gets the value of the initiallyDeferred property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isInitiallyDeferred() {
return initiallyDeferred;
}
/**
* Sets the value of the initiallyDeferred property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setInitiallyDeferred(Boolean value) {
this.initiallyDeferred = value;
}
}
@@ -0,0 +1,64 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}defaultTablespace"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"defaultTablespace"
})
@XmlRootElement(name = "configuration")
public class Configuration {
@XmlElement(required = true)
protected DefaultTablespace defaultTablespace;
/**
* Gets the value of the defaultTablespace property.
*
* @return
* possible object is
* {@link DefaultTablespace }
*
*/
public DefaultTablespace getDefaultTablespace() {
return defaultTablespace;
}
/**
* Sets the value of the defaultTablespace property.
*
* @param value
* allowed object is
* {@link DefaultTablespace }
*
*/
public void setDefaultTablespace(DefaultTablespace value) {
this.defaultTablespace = value;
}
}
@@ -0,0 +1,60 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="baseTable" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "createDropHistoryTable", namespace = "http://ebean-orm.github.io/xml/ns/dbmigration")
public class CreateDropHistoryTable {
@XmlAttribute(name = "baseTable", required = true)
protected String baseTable;
/**
* Gets the value of the baseTable property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getBaseTable() {
return baseTable;
}
/**
* Sets the value of the baseTable property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setBaseTable(String value) {
this.baseTable = value;
}
}
@@ -0,0 +1,60 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="baseTable" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "addHistoryTable")
public class CreateHistoryTable {
@XmlAttribute(name = "baseTable", required = true)
protected String baseTable;
/**
* Gets the value of the baseTable property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getBaseTable() {
return baseTable;
}
/**
* Sets the value of the baseTable property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setBaseTable(String value) {
this.baseTable = value;
}
}
@@ -0,0 +1,237 @@
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.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}column" maxOccurs="unbounded"/>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}uniqueConstraint" maxOccurs="unbounded" minOccurs="0"/>
* &lt;/sequence>
* &lt;attGroup ref="{http://ebean-orm.github.io/xml/ns/dbmigration}tablespaceAttributes"/>
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="withHistory" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"column",
"uniqueConstraint"
})
@XmlRootElement(name = "createTable")
public class CreateTable {
@XmlElement(required = true)
protected List<Column> column;
protected List<UniqueConstraint> uniqueConstraint;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "withHistory")
protected Boolean withHistory;
@XmlAttribute(name = "tablespace")
protected String tablespace;
@XmlAttribute(name = "indexTablespace")
protected String indexTablespace;
@XmlAttribute(name = "remarks")
protected String remarks;
/**
* Gets the value of the column property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the column property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getColumn().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link Column }
*
*
*/
public List<Column> getColumn() {
if (column == null) {
column = new ArrayList<Column>();
}
return this.column;
}
/**
* Gets the value of the uniqueConstraint property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the uniqueConstraint property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getUniqueConstraint().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link UniqueConstraint }
*
*
*/
public List<UniqueConstraint> getUniqueConstraint() {
if (uniqueConstraint == null) {
uniqueConstraint = new ArrayList<UniqueConstraint>();
}
return this.uniqueConstraint;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the withHistory property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isWithHistory() {
return withHistory;
}
/**
* Sets the value of the withHistory property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setWithHistory(Boolean value) {
this.withHistory = value;
}
/**
* Gets the value of the tablespace property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getTablespace() {
return tablespace;
}
/**
* Sets the value of the tablespace property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setTablespace(String value) {
this.tablespace = value;
}
/**
* Gets the value of the indexTablespace property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getIndexTablespace() {
return indexTablespace;
}
/**
* Sets the value of the indexTablespace property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setIndexTablespace(String value) {
this.indexTablespace = value;
}
/**
* Gets the value of the remarks property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getRemarks() {
return remarks;
}
/**
* Sets the value of the remarks property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setRemarks(String value) {
this.remarks = value;
}
}
@@ -0,0 +1,116 @@
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;
import javax.xml.bind.annotation.XmlValue;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;simpleContent>
* &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="replaceIfExists" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;/extension>
* &lt;/simpleContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"value"
})
@XmlRootElement(name = "createView")
public class CreateView {
@XmlValue
protected String value;
@XmlAttribute(name = "name", required = true)
protected String name;
@XmlAttribute(name = "replaceIfExists")
protected Boolean replaceIfExists;
/**
* Gets the value of the value property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setValue(String value) {
this.value = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
/**
* Gets the value of the replaceIfExists property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isReplaceIfExists() {
return replaceIfExists;
}
/**
* Sets the value of the replaceIfExists property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setReplaceIfExists(Boolean value) {
this.replaceIfExists = value;
}
}
@@ -0,0 +1,114 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="tables" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="indexes" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="history" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "defaultTablespace")
public class DefaultTablespace {
@XmlAttribute(name = "tables")
protected String tables;
@XmlAttribute(name = "indexes")
protected String indexes;
@XmlAttribute(name = "history")
protected String history;
/**
* Gets the value of the tables property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getTables() {
return tables;
}
/**
* Sets the value of the tables property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setTables(String value) {
this.tables = value;
}
/**
* Gets the value of the indexes property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getIndexes() {
return indexes;
}
/**
* Sets the value of the indexes property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setIndexes(String value) {
this.indexes = value;
}
/**
* Gets the value of the history property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getHistory() {
return history;
}
/**
* Sets the value of the history property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setHistory(String value) {
this.history = value;
}
}
@@ -0,0 +1,87 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="columnName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "dropColumn")
public class DropColumn {
@XmlAttribute(name = "columnName", required = true)
protected String columnName;
@XmlAttribute(name = "tableName", required = true)
protected String tableName;
/**
* 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;
}
}
@@ -0,0 +1,89 @@
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;
import javax.xml.bind.annotation.XmlValue;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"content"
})
@XmlRootElement(name = "dropForeignKey")
public class DropForeignKey {
@XmlValue
protected String content;
@XmlAttribute(name = "name", required = true)
protected String name;
/**
* Gets the value of the content property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getContent() {
return content;
}
/**
* Sets the value of the content property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setContent(String value) {
this.content = value;
}
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
}
@@ -0,0 +1,60 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="baseTable" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "dropHistoryTable")
public class DropHistoryTable {
@XmlAttribute(name = "baseTable", required = true)
protected String baseTable;
/**
* Gets the value of the baseTable property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getBaseTable() {
return baseTable;
}
/**
* Sets the value of the baseTable property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setBaseTable(String value) {
this.baseTable = value;
}
}
@@ -0,0 +1,60 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "dropTable")
public class DropTable {
@XmlAttribute(name = "name", required = true)
protected String name;
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
}
@@ -0,0 +1,60 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="name" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "dropView")
public class DropView {
@XmlAttribute(name = "name", required = true)
protected String name;
/**
* Gets the value of the name property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getName() {
return name;
}
/**
* Sets the value of the name property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setName(String value) {
this.name = value;
}
}
@@ -0,0 +1,71 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.ArrayList;
import java.util.List;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}changeSet" maxOccurs="unbounded"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"changeSet"
})
@XmlRootElement(name = "migration")
public class Migration {
@XmlElement(required = true)
protected List<ChangeSet> changeSet;
/**
* Gets the value of the changeSet property.
*
* <p>
* This accessor method returns a reference to the live list,
* not a snapshot. Therefore any modification you make to the
* returned list will be present inside the JAXB object.
* This is why there is not a <CODE>set</CODE> method for the changeSet property.
*
* <p>
* For example, to add a new item, do as follows:
* <pre>
* getChangeSet().add(newItem);
* </pre>
*
*
* <p>
* Objects of the following type(s) are allowed in the list
* {@link ChangeSet }
*
*
*/
public List<ChangeSet> getChangeSet() {
if (changeSet == null) {
changeSet = new ArrayList<ChangeSet>();
}
return this.changeSet;
}
}
@@ -0,0 +1,224 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlRegistry;
/**
* This object contains factory methods for each
* Java content interface and Java element interface
* generated in the org.avaje.ebean.dbmigration.migration package.
* <p>An ObjectFactory allows you to programatically
* construct new instances of the Java representation
* for XML content. The Java representation of XML
* content can consist of schema derived interfaces
* and classes representing the binding of schema
* type definitions, element declarations and model
* groups. Factory methods for each of these are
* provided in this class.
*
*/
@XmlRegistry
public class ObjectFactory {
/**
* Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: org.avaje.ebean.dbmigration.migration
*
*/
public ObjectFactory() {
}
/**
* Create an instance of {@link Rollback }
*
*/
public Rollback createRollback() {
return new Rollback();
}
/**
* Create an instance of {@link AddColumn }
*
*/
public AddColumn createAddColumn() {
return new AddColumn();
}
/**
* Create an instance of {@link Column }
*
*/
public Column createColumn() {
return new Column();
}
/**
* Create an instance of {@link CreateTable }
*
*/
public CreateTable createCreateTable() {
return new CreateTable();
}
/**
* Create an instance of {@link UniqueConstraint }
*
*/
public UniqueConstraint createUniqueConstraint() {
return new UniqueConstraint();
}
/**
* Create an instance of {@link DropForeignKey }
*
*/
public DropForeignKey createDropForeignKey() {
return new DropForeignKey();
}
/**
* Create an instance of {@link Apply }
*
*/
public Apply createApply() {
return new Apply();
}
/**
* Create an instance of {@link Configuration }
*
*/
public Configuration createConfiguration() {
return new Configuration();
}
/**
* Create an instance of {@link DefaultTablespace }
*
*/
public DefaultTablespace createDefaultTablespace() {
return new DefaultTablespace();
}
/**
* Create an instance of {@link RenameTable }
*
*/
public RenameTable createRenameTable() {
return new RenameTable();
}
/**
* Create an instance of {@link DropHistoryTable }
*
*/
public DropHistoryTable createDropHistoryTable() {
return new DropHistoryTable();
}
/**
* 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 DropColumn }
*
*/
public DropColumn createDropColumn() {
return new DropColumn();
}
/**
* Create an instance of {@link DropView }
*
*/
public DropView createDropView() {
return new DropView();
}
/**
* Create an instance of {@link ChangeSet }
*
*/
public ChangeSet createChangeSet() {
return new ChangeSet();
}
/**
* Create an instance of {@link Sql }
*
*/
public Sql createSql() {
return new Sql();
}
/**
* Create an instance of {@link DropTable }
*
*/
public DropTable createDropTable() {
return new DropTable();
}
/**
* Create an instance of {@link CreateHistoryTable }
*
*/
public CreateHistoryTable createCreateHistoryTable() {
return new CreateHistoryTable();
}
/**
* Create an instance of {@link CreateView }
*
*/
public CreateView createCreateView() {
return new CreateView();
}
/**
* Create an instance of {@link RenameColumn }
*
*/
public RenameColumn createRenameColumn() {
return new RenameColumn();
}
/**
* Create an instance of {@link Application }
*
*/
public Application createApplication() {
return new Application();
}
/**
* Create an instance of {@link Migration }
*
*/
public Migration createMigration() {
return new Migration();
}
/**
* Create an instance of {@link Applications }
*
*/
public Applications createApplications() {
return new Applications();
}
}
@@ -0,0 +1,141 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="oldName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="newName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="tableName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="dataType" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "renameColumn")
public class RenameColumn {
@XmlAttribute(name = "oldName", required = true)
protected String oldName;
@XmlAttribute(name = "newName", required = true)
protected String newName;
@XmlAttribute(name = "tableName", required = true)
protected String tableName;
@XmlAttribute(name = "dataType")
protected String dataType;
/**
* Gets the value of the oldName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getOldName() {
return oldName;
}
/**
* Sets the value of the oldName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setOldName(String value) {
this.oldName = value;
}
/**
* Gets the value of the newName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getNewName() {
return newName;
}
/**
* Sets the value of the newName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setNewName(String value) {
this.newName = 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 dataType property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getDataType() {
return dataType;
}
/**
* Sets the value of the dataType property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setDataType(String value) {
this.dataType = value;
}
}
@@ -0,0 +1,87 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="oldName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="newName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "renameTable")
public class RenameTable {
@XmlAttribute(name = "oldName", required = true)
protected String oldName;
@XmlAttribute(name = "newName", required = true)
protected String newName;
/**
* Gets the value of the oldName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getOldName() {
return oldName;
}
/**
* Sets the value of the oldName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setOldName(String value) {
this.oldName = value;
}
/**
* Gets the value of the newName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getNewName() {
return newName;
}
/**
* Sets the value of the newName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setNewName(String value) {
this.newName = value;
}
}
@@ -0,0 +1,87 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="oldName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="newName" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "renameView")
public class RenameView {
@XmlAttribute(name = "oldName", required = true)
protected String oldName;
@XmlAttribute(name = "newName", required = true)
protected String newName;
/**
* Gets the value of the oldName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getOldName() {
return oldName;
}
/**
* Sets the value of the oldName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setOldName(String value) {
this.oldName = value;
}
/**
* Gets the value of the newName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getNewName() {
return newName;
}
/**
* Sets the value of the newName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setNewName(String value) {
this.newName = value;
}
}
@@ -0,0 +1,61 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;simpleContent>
* &lt;extension base="&lt;http://www.w3.org/2001/XMLSchema>string">
* &lt;/extension>
* &lt;/simpleContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"value"
})
@XmlRootElement(name = "rollback")
public class Rollback {
@XmlValue
protected String value;
/**
* Gets the value of the value property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getValue() {
return value;
}
/**
* Sets the value of the value property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setValue(String value) {
this.value = value;
}
}
@@ -0,0 +1,92 @@
package com.avaje.ebean.dbmigration.migration;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;sequence>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}apply"/>
* &lt;element ref="{http://ebean-orm.github.io/xml/ns/dbmigration}rollback"/>
* &lt;/sequence>
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"apply",
"rollback"
})
@XmlRootElement(name = "sql")
public class Sql {
@XmlElement(required = true)
protected Apply apply;
@XmlElement(required = true)
protected Rollback rollback;
/**
* Gets the value of the apply property.
*
* @return
* possible object is
* {@link Apply }
*
*/
public Apply getApply() {
return apply;
}
/**
* Sets the value of the apply property.
*
* @param value
* allowed object is
* {@link Apply }
*
*/
public void setApply(Apply value) {
this.apply = value;
}
/**
* Gets the value of the rollback property.
*
* @return
* possible object is
* {@link Rollback }
*
*/
public Rollback getRollback() {
return rollback;
}
/**
* Sets the value of the rollback property.
*
* @param value
* allowed object is
* {@link Rollback }
*
*/
public void setRollback(Rollback value) {
this.rollback = value;
}
}
@@ -0,0 +1,87 @@
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;
/**
* <p>Java class for anonymous complex type.
*
* <p>The following schema fragment specifies the expected content contained within this class.
*
* <pre>
* &lt;complexType>
* &lt;complexContent>
* &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
* &lt;attribute name="columnNames" use="required" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="constraintName" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;/restriction>
* &lt;/complexContent>
* &lt;/complexType>
* </pre>
*
*
*/
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "uniqueConstraint")
public class UniqueConstraint {
@XmlAttribute(name = "columnNames", required = true)
protected String columnNames;
@XmlAttribute(name = "constraintName")
protected String constraintName;
/**
* Gets the value of the columnNames property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getColumnNames() {
return columnNames;
}
/**
* Sets the value of the columnNames property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setColumnNames(String value) {
this.columnNames = value;
}
/**
* Gets the value of the constraintName property.
*
* @return
* possible object is
* {@link String }
*
*/
public String getConstraintName() {
return constraintName;
}
/**
* Sets the value of the constraintName property.
*
* @param value
* allowed object is
* {@link String }
*
*/
public void setConstraintName(String value) {
this.constraintName = value;
}
}
@@ -0,0 +1,2 @@
@javax.xml.bind.annotation.XmlSchema(namespace = "http://ebean-orm.github.io/xml/ns/dbmigration", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.avaje.ebean.dbmigration.migration;
@@ -0,0 +1,46 @@
package com.avaje.ebean.dbmigration.migrationreader;
import com.avaje.ebean.dbmigration.migration.Migration;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.InputStream;
/**
* Reads a migration xml document returning the Migration.
*/
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 read(String resourcePath) {
InputStream is = MigrationXmlReader.class.getResourceAsStream(resourcePath);
if (is == null) {
throw new IllegalArgumentException("No resource found for path [" + resourcePath + "]");
}
return INSTANCE.read(is);
}
/**
* Read and return a Migration from an xml document.
*/
public Migration read(InputStream is) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Migration.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
return (Migration) unmarshaller.unmarshal(is);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,32 @@
package com.avaje.ebean.dbmigration.migrationreader;
import com.avaje.ebean.dbmigration.migration.Migration;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.File;
/**
* Simple writer for output of the Migration/ChangeSet as an XML document.
*/
public class MigrationXmlWriter {
/**
* Write a Migration to a file as an xml document to the file.
*/
public void write(Migration migration, File file) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Migration.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty( Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(migration, file);
} catch (JAXBException e) {
throw new RuntimeException(e);
}
}
}
@@ -0,0 +1,130 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.BaseDdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DdlNamingConvention;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PlatformDdl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlWriter;
import com.avaje.ebean.dbmigration.model.build.ModelBuildBeanVisitor;
import com.avaje.ebean.dbmigration.model.build.ModelBuildContext;
import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Reads EbeanServer bean descriptors to build the current model.
*/
public class CurrentModel {
private final SpiEbeanServer server;
private DdlNamingConvention namingConvention;
private ModelContainer model;
private ChangeSet changeSet;
private DdlWrite write;
public CurrentModel(SpiEbeanServer server) {
this.server = server;
this.namingConvention = new DdlNamingConvention();
}
public ModelContainer read() {
if (model == null) {
model = new ModelContainer();
ModelBuildContext context = new ModelBuildContext(model);
ModelBuildBeanVisitor visitor = new ModelBuildBeanVisitor(context);
VisitAllUsing visit = new VisitAllUsing(visitor, server);
visit.visitAllBeans();
}
return model;
}
public ChangeSet getChangeSet() {
read();
if (changeSet == null) {
changeSet = asChangeSet();
}
return changeSet;
}
public void writeMigration(File file) {
ChangeSet changeSet = getChangeSet();
Migration migration = new Migration();
migration.getChangeSet().add(changeSet);
MigrationXmlWriter writer = new MigrationXmlWriter();
writer.write(migration, file);
}
public String getCreateDdl() throws IOException {
createDdl();
StringBuilder ddl = new StringBuilder(2000);
ddl.append(write.apply().getBuffer());
ddl.append(write.applyForeignKeys().getBuffer());
ddl.append(write.applyHistory().getBuffer());
return ddl.toString();
}
public String getDropDdl() throws IOException {
createDdl();
StringBuilder ddl = new StringBuilder(2000);
ddl.append(write.rollbackForeignKeys().getBuffer());
ddl.append(write.rollback().getBuffer());
return ddl.toString();
}
private void createDdl() throws IOException {
if (write == null) {
ChangeSet createChangeSet = getChangeSet();
write = new DdlWrite();
BaseDdlHandler handler = handler();
handler.generate(write, createChangeSet);
}
}
private BaseDdlHandler handler() {
DatabasePlatform databasePlatform = server.getDatabasePlatform();
PlatformDdl platformDdl = databasePlatform.getPlatformDdl();
return new BaseDdlHandler(namingConvention, platformDdl);
}
/**
* Convert the model into a ChangeSet.
*/
private ChangeSet asChangeSet() {
// empty diff so changes will effectively all be create
ModelDiff diff = new ModelDiff();
diff.compareTo(model);
List<Object> createChanges = diff.getCreateChanges();
// put the changes into a ChangeSet
ChangeSet createChangeSet = new ChangeSet();
createChangeSet.getChangeSetChildren().addAll(createChanges);
return createChangeSet;
}
}
@@ -0,0 +1,125 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.Column;
/**
* A column in the logical model.
*/
public class MColumn {
private final String name;
private final String type;
private String checkConstraint;
private String defaultValue;
private String references;
private boolean notnull;
private boolean primaryKey;
private boolean identity;
private boolean unique;
public MColumn(Column column) {
this.name = column.getName();
this.type = column.getType();
this.checkConstraint = column.getCheckConstraint();
this.defaultValue = column.getDefaultValue();
this.references = column.getReferences();
this.notnull = Boolean.TRUE.equals(column.isNotnull());
this.primaryKey = Boolean.TRUE.equals(column.isPrimaryKey());
this.identity = Boolean.TRUE.equals(column.isIdentity());
this.unique = Boolean.TRUE.equals(column.isUnique());
}
public MColumn(String name, String type) {
this.name = name;
this.type = type;
}
public MColumn(String name, String type, boolean notnull) {
this.name = name;
this.type = type;
this.notnull = notnull;
}
public String getName() {
return name;
}
public String getType() {
return type;
}
public boolean isPrimaryKey() {
return primaryKey;
}
public void setPrimaryKey(boolean primaryKey) {
this.primaryKey = primaryKey;
}
public boolean isIdentity() {
return identity;
}
public void setIdentity(boolean identity) {
this.identity = identity;
}
public String getCheckConstraint() {
return checkConstraint;
}
public void setCheckConstraint(String checkConstraint) {
this.checkConstraint = checkConstraint;
}
public String getDefaultValue() {
return defaultValue;
}
public void setDefaultValue(String defaultValue) {
this.defaultValue = defaultValue;
}
public String getReferences() {
return references;
}
public void setReferences(String references) {
this.references = references;
}
public boolean isNotnull() {
return notnull;
}
public void setNotnull(boolean notnull) {
this.notnull = notnull;
}
public void setUnique(boolean unique) {
this.unique = unique;
}
public boolean isUnique() {
return unique;
}
public Column createColumn() {
Column c = new Column();
c.setName(name);
c.setType(type);
c.setNotnull(notnull);
c.setCheckConstraint(checkConstraint);
c.setUnique(unique);
c.setPrimaryKey(primaryKey);
c.setIdentity(identity);
c.setReferences(references);
c.setDefaultValue(defaultValue);
//c.setDeleteCascade();
//c.setDeferrable(deferrable);
return c;
}
}
@@ -0,0 +1,27 @@
package com.avaje.ebean.dbmigration.model;
import java.util.ArrayList;
import java.util.List;
/**
* A unique constraint for multiple columns.
* <p>
* Note that unique constraint on a single column is instead
* a boolean flag on the associated MColumn.
* </p>
*/
public class MCompoundForeignKey {
private final String referenceTable;
private final List<String> columns = new ArrayList<String>();
private final List<String> referenceColumns = new ArrayList<String>();
public MCompoundForeignKey(String referenceTable) {
this.referenceTable = referenceTable;
}
public void addColumnPair(String dbCol, String refColumn) {
columns.add(dbCol);
referenceColumns.add(refColumn);
}
}
@@ -0,0 +1,24 @@
package com.avaje.ebean.dbmigration.model;
/**
* A unique constraint for multiple columns.
* <p>
* Note that unique constraint on a single column is instead
* a boolean flag on the associated MColumn.
* </p>
*/
public class MCompoundUniqueConstraint {
/**
* The columns combined to be unique.
*/
private final String[] columns;
public MCompoundUniqueConstraint(String[] columns) {
this.columns = columns;
}
public String[] getColumns() {
return columns;
}
}
@@ -0,0 +1,77 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.Configuration;
import com.avaje.ebean.dbmigration.migration.DefaultTablespace;
/**
* Holds configuration such as the default tablespaces to use for tables,
* indexes, history tables etc.
*/
public class MConfiguration {
/**
* Default tablespace for tables.
*/
protected String tableTablespace;
/**
* Default tablespace for indexes.
*/
protected String indexTablespace;
/**
* Default tablespace for history tables.
*/
protected String historyTablespace;
/**
* Apply the migration configuration.
* <p>
* It is expected that these are applied in the correct chronological order
* from earliest to latest.
* </p>
*/
public void apply(Configuration configuration) {
DefaultTablespace defaultTablespace = configuration.getDefaultTablespace();
if (defaultTablespace != null) {
String tables = defaultTablespace.getTables();
if (isNotEmpty(tables)) {
this.tableTablespace = tables;
}
String indexes = defaultTablespace.getIndexes();
if (isNotEmpty(indexes)) {
this.indexTablespace = indexes;
}
String history = defaultTablespace.getHistory();
if (isNotEmpty(history)) {
this.historyTablespace = history;
}
}
}
/**
* Return the default tablespace to use for tables.
*/
public String getTableTablespace() {
return tableTablespace;
}
/**
* Return the default tablespace to use for indexes.
*/
public String getIndexTablespace() {
return indexTablespace;
}
/**
* Return the default tablespace to use for history tables.
*/
public String getHistoryTablespace() {
return historyTablespace;
}
protected boolean isNotEmpty(String tables) {
return tables != null && !tables.trim().isEmpty();
}
}
@@ -0,0 +1,7 @@
package com.avaje.ebean.dbmigration.model;
/**
* Index as part of the logical model.
*/
public class MIndex {
}
@@ -0,0 +1,186 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.Column;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Holds the logical model for a given Table and everything associated to it.
* <p>
* This effectively represents a table, its columns and all associated
* constraints, foreign keys and indexes.
* </p>
* <p>
* Migrations can be applied to this such that it represents the state
* of a given table after various migrations have been applied.
* </p>
* <p>
* This table model can also be derived from the EbeanServer bean descriptor
* and associated properties.
* </p>
*/
public class MTable {
/**
* Flag set to indicate
*/
private boolean matched;
private final String name;
private String remarks;
private String tablespace;
private String indexTablespace;
private Boolean withHistory;
private Map<String,MColumn> columns = new LinkedHashMap<String,MColumn>();
private List<MCompoundUniqueConstraint> compoundUniqueConstraints = new ArrayList<MCompoundUniqueConstraint>();
private List<MCompoundForeignKey> compoundKeys = new ArrayList<MCompoundForeignKey>();
/**
* Construct for migration.
*/
public MTable(CreateTable createTable) {
this.name = createTable.getName();
this.remarks = createTable.getRemarks();
this.tablespace = createTable.getTablespace();
this.indexTablespace = createTable.getIndexTablespace();
this.withHistory = createTable.isWithHistory();
List<Column> cols = createTable.getColumn();
for (Column column : cols) {
addColumn(column);
}
}
/**
* Construct typically from EbeanServer meta data.
*/
public MTable(String name) {
this.name = name;
}
public CreateTable createTable() {
CreateTable createTable = new CreateTable();
createTable.setName(name);
createTable.setRemarks(remarks);
createTable.setTablespace(tablespace);
createTable.setIndexTablespace(indexTablespace);
createTable.setWithHistory(withHistory);
for (MColumn column : this.columns.values()) {
createTable.getColumn().add(column.createColumn());
}
return createTable;
}
public boolean isMatched() {
return matched;
}
public void setMatched(boolean matched) {
this.matched = matched;
}
/**
* Apply AddColumn migration.
*/
public void apply(AddColumn addColumn) {
checkTableName(addColumn.getTableName());
for (Column column : addColumn.getColumn()) {
addColumn(column);
}
}
/**
* Apply DropColumn migration.
*/
public void apply(DropColumn dropColumn) {
checkTableName(dropColumn.getTableName());
columns.remove(dropColumn.getColumnName());
}
public String getName() {
return name;
}
public String getRemarks() {
return remarks;
}
public String getTablespace() {
return tablespace;
}
public String getIndexTablespace() {
return indexTablespace;
}
public Boolean getWithHistory() {
return withHistory;
}
public Map<String, MColumn> getColumns() {
return columns;
}
public List<MCompoundUniqueConstraint> getCompoundUniqueConstraints() {
return compoundUniqueConstraints;
}
public List<MCompoundForeignKey> getCompoundKeys() {
return compoundKeys;
}
private void checkTableName(String tableName) {
if (!name.equals(tableName)) {
throw new IllegalArgumentException("addColumn tableName ["+tableName+"] does not match ["+name+"]");
}
}
/**
* Add a column via migration data.
*/
private void addColumn(Column column) {
columns.put(column.getName(), new MColumn(column));
}
/**
* Add a model column (typically from EbeanServer meta data).
*/
public void addColumn(MColumn column) {
columns.put(column.getName(), column);
}
/**
* Add a compound unique constraint.
*/
public void addCompoundUniqueConstraint(String[] columns) {
compoundUniqueConstraints.add(new MCompoundUniqueConstraint(columns));
}
/**
* Add a compound unique constraint.
*/
public void addCompoundUniqueConstraint(List<MColumn> columns) {
String[] cols = new String[columns.size()];
for (int i = 0; i < columns.size(); i++) {
cols[i] = columns.get(i).getName();
}
addCompoundUniqueConstraint(cols);
}
public void addForeignKey(MCompoundForeignKey compoundKey) {
compoundKeys.add(compoundKey);
}
}
@@ -0,0 +1,110 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.Migration;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Holds all the tables, views, indexes etc that represent the model.
* <p>
* Migration changeSets can be applied to the model.
* </p>
*/
public class ModelContainer {
/**
* All the tables in the model.
*/
private Map<String, MTable> tables = new LinkedHashMap<String, MTable>();
/**
* Return the map of all the tables.
*/
public Map<String, MTable> getTables() {
return tables;
}
/**
* Return the table by name.
*/
public MTable getTable(String tableName) {
return tables.get(tableName);
}
/**
* Apply a migration with associated changeSets to the model.
*/
public void apply(Migration migration) {
List<ChangeSet> changeSets = migration.getChangeSet();
for (ChangeSet changeSet : changeSets) {
applyChangeSet(changeSet);
}
}
/**
* Apply a changeSet to the model.
*/
protected void applyChangeSet(ChangeSet changeSet) {
List<Object> changeSetChildren = changeSet.getChangeSetChildren();
for (Object change : changeSetChildren) {
if (change instanceof CreateTable) {
applyChange((CreateTable) change);
} else if (change instanceof AddColumn) {
applyChange((AddColumn) change);
} else if (change instanceof DropColumn) {
applyChange((DropColumn) change);
}
}
}
/**
* Apply a CreateTable change to the model.
*/
protected void applyChange(CreateTable createTable) {
String tableName = createTable.getName();
if (tables.containsKey(tableName)) {
throw new IllegalStateException("Table [" + tableName + "] already exists?");
}
MTable table = new MTable(createTable);
tables.put(tableName, table);
}
/**
* Apply a AddColumn change to the model.
*/
protected void applyChange(AddColumn addColumn) {
MTable table = tables.get(addColumn.getTableName());
if (table == null) {
throw new IllegalStateException("Table [" + addColumn.getTableName() + "] does not exist?");
}
table.apply(addColumn);
}
/**
* Apply a DropColumn change to the model.
*/
protected void applyChange(DropColumn dropColumn) {
MTable table = tables.get(dropColumn.getTableName());
if (table == null) {
throw new IllegalStateException("Table [" + dropColumn.getTableName() + "] does not exist?");
}
table.apply(dropColumn);
}
/**
* Add a table (typically from reading EbeanServer meta data).
*/
public void addTable(MTable table) {
tables.put(table.getName(), table);
}
}
@@ -0,0 +1,98 @@
package com.avaje.ebean.dbmigration.model;
import java.util.ArrayList;
import java.util.List;
/**
* Used to prepare a diff in terms of changes required to migrate from
* the base model to the newer model.
*/
public class ModelDiff {
/**
* The base model to which we compare the newer model.
*/
protected final ModelContainer baseModel;
/**
* List of 'create' type changes.
*/
protected final List<Object> createChanges = new ArrayList<Object>();
/**
* List of 'drop' type changes. Potential for putting into a separate changeSet.
*/
protected final List<Object> dropChanges = new ArrayList<Object>();
/**
* Construct with a base model.
*/
public ModelDiff(ModelContainer baseModel) {
this.baseModel = baseModel;
}
/**
* Construct with a base model.
*/
public ModelDiff() {
this.baseModel = new ModelContainer();
}
/**
* Return the list of 'create' changes.
*/
public List<Object> getCreateChanges() {
return createChanges;
}
/**
* Return the list of 'drop' changes.
*/
public List<Object> getDropChanges() {
return dropChanges;
}
/**
* Compare to a 'newer' model and collect the differences.
*/
public void compareTo(ModelContainer newModel) {
for (MTable newTable : newModel.getTables().values()) {
MTable currentTable = baseModel.getTable(newTable.getName());
if (currentTable == null) {
addNewTable(newTable);
} else {
compareTables(currentTable, newTable);
}
}
//TODO: other parts of the model? views, indexes etc
}
/**
* Add CreateTable to the 'creation' changes.
*/
protected void addNewTable(MTable newTable) {
createChanges.add(newTable.createTable());
// createChanges.add(newTable.createForeignKeys());
}
/**
* Compare tables looking for add/drop/modify columns etc.
*/
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?
}
}
@@ -0,0 +1,61 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.CompoundUniqueContraint;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.visitor.BeanPropertyVisitor;
import com.avaje.ebean.dbmigration.model.visitor.BeanVisitor;
/**
* Used to build the Model objects MTable etc.
*/
public class ModelBuildBeanVisitor implements BeanVisitor {
private final ModelBuildContext ctx;
public ModelBuildBeanVisitor(ModelBuildContext ctx) {
this.ctx = ctx;
}
/**
* Return the PropertyVisitor used to read all the property meta data
* and in this case add MColumn objects to the model.
* <p>
* This creates an MTable and adds it to the model.
* </p>
*/
public BeanPropertyVisitor visitBean(BeanDescriptor<?> descriptor) {
if (!descriptor.isInheritanceRoot()) {
return null;
}
MTable table = new MTable(descriptor.getBaseTable());
// add the table to the model
ctx.addTable(table);
InheritInfo inheritInfo = descriptor.getInheritInfo();
if (inheritInfo != null && inheritInfo.isRoot()) {
// add the discriminator column
String discColumn = inheritInfo.getDiscriminatorColumn();
DbType dbType = ctx.getDbTypeMap().get(inheritInfo.getDiscriminatorType());
String discDbType = dbType.renderType(inheritInfo.getDiscriminatorLength(), 0);
table.addColumn(new MColumn(discColumn, discDbType, true));
}
CompoundUniqueContraint[] compoundUniqueConstraints = descriptor.getCompoundUniqueConstraints();
if (compoundUniqueConstraints != null) {
for (int i = 0; i < compoundUniqueConstraints.length; i++) {
table.addCompoundUniqueConstraint(compoundUniqueConstraints[i].getColumns());
}
}
return new ModelBuildPropertyVisitor(ctx, table);
}
}
@@ -0,0 +1,64 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.config.dbplatform.DbType;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
/**
* The context used during DDL generation.
*/
public class ModelBuildContext {
/**
* Use platform agnostic logical types. These types are converted to
* platform specific types in the DDL generation.
*/
private final DbTypeMap dbTypeMap = DbTypeMap.logicalTypes();
private final ModelContainer model;
public ModelBuildContext(ModelContainer model) {
this.model = model;
}
public void addTable(MTable table) {
model.addTable(table);
}
/**
* Return the map used to determine the DB specific type
* for a given bean property.
*/
public DbTypeMap getDbTypeMap() {
return dbTypeMap;
}
public String getColumnDefn(BeanProperty p) {
DbType dbType = getDbType(p);
if (dbType == null) {
throw new IllegalStateException("Unknown DbType mapping for " + p.getFullBeanName());
}
return p.renderDbType(dbType);
}
private DbType getDbType(BeanProperty p) {
if (p.isDbEncrypted()) {
return dbTypeMap.get(p.getDbEncryptedType());
}
int dbType = p.getDbType();
if (dbType == 0) {
// ScalarType<Object> scalarType = p.getScalarType();
// if (scalarType == null) {
throw new RuntimeException("No scalarType for " + p.getFullBeanName());
// }
// dbType = scalarType.getJdbcType();
}
return dbTypeMap.get(dbType);
}
}
@@ -0,0 +1,124 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.TableJoin;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
/**
* Add the intersection table to the model.
*/
public class ModelBuildIntersectionTable {
private final ModelBuildContext ctx;
private final BeanPropertyAssocMany<?> manyProp;
private final TableJoin intersectionTableJoin;
private final TableJoin tableJoin;
public ModelBuildIntersectionTable(ModelBuildContext ctx, BeanPropertyAssocMany<?> manyProp) {
this.ctx = ctx;
this.manyProp = manyProp;
this.intersectionTableJoin = manyProp.getIntersectionTableJoin();
this.tableJoin = manyProp.getTableJoin();
}
public void build() {
MTable table = createTable();
ctx.addTable(table);
//buildFkConstraints();
}
// private void buildFkConstraints(MTable table) {
//
// BeanDescriptor<?> localDesc = manyProp.getBeanDescriptor();
// String fk1 = buildFkConstraints(localDesc, intersectionTableJoin.columns(), true);
// ctx.addIntersectionTableFk(fk1);
//
// BeanDescriptor<?> targetDesc = manyProp.getTargetDescriptor();
// String fk2 = buildFkConstraints(targetDesc, tableJoin.columns(), false);
// ctx.addIntersectionTableFk(fk2);
// }
// private String buildFkConstraints(BeanDescriptor<?> desc, TableJoinColumn[] columns, boolean direction) {
//
//
// String fkName = "fk_"+intersectionTableJoin.getTable()+"_"+desc.getBaseTable();
//
// fkName = getFkNameWithSuffix(fkName);
//
// fkBuf.append("alter table ");
// fkBuf.append(intersectionTableJoin.getTable());
// fkBuf.append(" add constraint ").append(fkName);
//
// fkBuf.append(" foreign key (");
//
// for (int i = 0; i < columns.length; i++) {
// if (i > 0) {
// fkBuf.append(", ");
// }
// String col = direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn();
// fkBuf.append(col);
// }
// fkBuf.append(") references ").append(desc.getBaseTable()).append(" (");
//
// for (int i = 0; i < columns.length; i++) {
// if (i > 0) {
// fkBuf.append(", ");
// }
// String col = !direction ? columns[i].getForeignDbColumn() : columns[i].getLocalDbColumn();
// fkBuf.append(col);
// }
// fkBuf.append(")");
//
// String fkeySuffix = ctx.getDdlSyntax().getForeignKeySuffix();
// if (fkeySuffix != null){
// fkBuf.append(" ");
// fkBuf.append(fkeySuffix);
// }
// fkBuf.append(";").append(NEW_LINE);
//
// return fkBuf.toString();
// }
private MTable createTable() {
BeanDescriptor<?> localDesc = manyProp.getBeanDescriptor();
BeanDescriptor<?> targetDesc = manyProp.getTargetDescriptor();
MTable table = new MTable(intersectionTableJoin.getTable());
TableJoinColumn[] columns = intersectionTableJoin.columns();
for (int i = 0; i < columns.length; i++) {
addColumn(table, localDesc, columns[i].getForeignDbColumn(), columns[i].getLocalDbColumn());
}
TableJoinColumn[] otherColumns = tableJoin.columns();
for (int i = 0; i < otherColumns.length; i++) {
addColumn(table, targetDesc, otherColumns[i].getLocalDbColumn(), otherColumns[i].getForeignDbColumn());
}
return table;
}
private void addColumn(MTable table, BeanDescriptor<?> desc, String column, String findPropColumn) {
BeanProperty p = desc.getIdBinder().findBeanProperty(findPropColumn);
if (p == null) {
throw new RuntimeException("Could not find id property for " + findPropColumn);
}
MColumn col = new MColumn(column, ctx.getColumnDefn(p), true);
col.setPrimaryKey(true);
table.addColumn(col);
}
}
@@ -0,0 +1,147 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.dbmigration.model.MCompoundForeignKey;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.TableJoinColumn;
import com.avaje.ebeaninternal.server.deploy.id.ImportedId;
import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.visitor.BaseTablePropertyVisitor;
import java.util.ArrayList;
import java.util.List;
/**
* Used as part of ModelBuildBeanVisitor and generally adds the MColumn to the associated
* MTable model objects.
*/
public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
private final ModelBuildContext ctx;
private final MTable table;
public ModelBuildPropertyVisitor(ModelBuildContext ctx, MTable table) {
this.ctx = ctx;
this.table = table;
}
@Override
public void visitMany(BeanPropertyAssocMany<?> p) {
if (p.isManyToMany()) {
if (p.getMappedBy() == null) {
// only create on other 'owning' side
//TableJoin intersectionTableJoin = p.getIntersectionTableJoin();
// check if the intersection table has already been created
// build the create table and fkey constraints
// putting the DDL into ctx for later output as we are
// in the middle of rendering the create table DDL
new ModelBuildIntersectionTable(ctx, p).build();
}
}
}
@Override
public void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p) {
visitScalar(p);
}
@Override
public void visitCompound(BeanPropertyCompound p) {
// do nothing
}
@Override
public void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded) {
//this.embedded = embedded;
visitScalar(p);
}
@Override
public void visitOneImported(BeanPropertyAssocOne<?> p) {
TableJoinColumn[] columns = p.getTableJoin().columns();
if (columns.length == 0) {
String msg = "No join columns for " + p.getFullBeanName();
throw new RuntimeException(msg);
}
ImportedId importedId = p.getImportedId();
List<MColumn> modelColumns = new ArrayList<MColumn>(columns.length);
MCompoundForeignKey compoundKey = null;
if (columns.length > 1) {
// compound foreign key
String refTable = p.getTargetDescriptor().getBaseTable();
compoundKey = new MCompoundForeignKey(refTable);
table.addForeignKey(compoundKey);
}
for (int i = 0; i < columns.length; i++) {
String dbCol = columns[i].getLocalDbColumn();
BeanProperty importedProperty = importedId.findMatchImport(dbCol);
if (importedProperty == null) {
throw new RuntimeException("Imported BeanProperty not found?");
}
String columnDefn = ctx.getColumnDefn(importedProperty);
String refColumn = importedProperty.getDbColumn();
MColumn col = new MColumn(dbCol, columnDefn, !p.isNullable());
if (columns.length == 1) {
// single references column (put it on the column)
String refTable = importedProperty.getBeanDescriptor().getBaseTable();
col.setReferences(refTable + "." + refColumn);
} else {
compoundKey.addColumnPair(dbCol, refColumn);
}
modelColumns.add(col);
table.addColumn(col);
}
if (p.isOneToOne()) {
// Adding the unique constraint restricts the cardinality from OneToMany down to OneToOne
if (modelColumns.size() == 1) {
modelColumns.get(0).setUnique(true);
} else {
table.addCompoundUniqueConstraint(modelColumns);
}
}
}
@Override
public void visitScalar(BeanProperty p) {
if (p.isSecondaryTable()) {
return;
}
MColumn col = new MColumn(p.getDbColumn(), ctx.getColumnDefn(p));
if (p.isId()){
col.setPrimaryKey(true);
if (p.getBeanDescriptor().isUseIdGenerator()) {
col.setIdentity(true);
}
} else if (!p.isNullable() || p.isDDLNotNull()) {
col.setNotnull(true);
}
if (p.isUnique() && !p.isId()) {
col.setUnique(true);
}
col.setCheckConstraint(p.getDbConstraintExpression());
table.addColumn(col);
}
}
@@ -0,0 +1,59 @@
package com.avaje.ebean.dbmigration.model.visitor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Used to help mark PropertyVisitor methods that need to be implemented
* to visit base table properties.
*/
public abstract class BaseTablePropertyVisitor implements BeanPropertyVisitor {
/**
* Not required in that you can use the visitEmbeddedScalar.
*/
public void visitEmbedded(BeanPropertyAssocOne<?> p) {
}
/**
* Override this method.
*/
public abstract void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded);
/**
* Not part of base table.
*/
public void visitMany(BeanPropertyAssocMany<?> p) {
}
/**
* Not part of base table.
*/
public void visitOneExported(BeanPropertyAssocOne<?> p) {
}
/**
* Override this method for the foreign key.
*/
public abstract void visitOneImported(BeanPropertyAssocOne<?> p);
/**
* Override this method for normal scalar property.
*/
public abstract void visitScalar(BeanProperty p);
/**
* Not required in that the scalar properties map to the columns.
*/
public void visitCompound(BeanPropertyCompound p) {
}
/**
* Override this method for scalar property inside a Immutable Compound Value object.
*/
public abstract void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p);
}
@@ -0,0 +1,53 @@
package com.avaje.ebean.dbmigration.model.visitor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
/**
* Used to visit a BeanProperty given the type of bean property it is.
*/
public interface BeanPropertyVisitor {
/**
* Visit a OneToMany or ManyToMany property.
*/
void visitMany(BeanPropertyAssocMany<?> p);
/**
* Visit the imported side of a OneToOne property.
*/
void visitOneImported(BeanPropertyAssocOne<?> p);
/**
* Visit the exported side of a OneToOne property.
*/
void visitOneExported(BeanPropertyAssocOne<?> p);
/**
* Visit an embedded property.
*/
void visitEmbedded(BeanPropertyAssocOne<?> p);
/**
* Visit the scalar property of an embedded bean.
*/
void visitEmbeddedScalar(BeanProperty p, BeanPropertyAssocOne<?> embedded);
/**
* Visit a scalar property.
*/
void visitScalar(BeanProperty p);
/**
* Visit a compound value object.
*/
void visitCompound(BeanPropertyCompound p);
/**
* Visit the scalar value inside a compound value object.
*/
void visitCompoundScalar(BeanPropertyCompound compound, BeanProperty p);
}
@@ -0,0 +1,16 @@
package com.avaje.ebean.dbmigration.model.visitor;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
/**
* Visitor pattern for visiting a BeanDescriptor and potentially all its bean
* properties.
*/
public interface BeanVisitor {
/**
* Visit a BeanDescriptor and return a PropertyVisitor to use to visit each
* property on the entity bean (return null to skip visiting this bean).
*/
BeanPropertyVisitor visitBean(BeanDescriptor<?> descriptor);
}
@@ -0,0 +1,158 @@
package com.avaje.ebean.dbmigration.model.visitor;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.deploy.BeanDescriptor;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocMany;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyAssocOne;
import com.avaje.ebeaninternal.server.deploy.BeanPropertyCompound;
import com.avaje.ebeaninternal.server.deploy.InheritInfo;
import com.avaje.ebeaninternal.server.deploy.InheritInfoVisitor;
import java.util.List;
/**
* Makes use of BeanVisitor and PropertyVisitor to navigate BeanDescriptors
* and their properties.
*/
public class VisitAllUsing {
protected final BeanVisitor visitor;
protected final List<BeanDescriptor<?>> descriptors;
/**
* Visit all the descriptors for a given server.
*/
public VisitAllUsing(BeanVisitor visitor, SpiEbeanServer server) {
this(visitor, server.getBeanDescriptors());
}
/**
* Visit all the descriptors in the list.
*/
public VisitAllUsing(BeanVisitor visitor, List<BeanDescriptor<?>> descriptors) {
this.visitor = visitor;
this.descriptors = descriptors;
}
public void visitAllBeans() {
for (BeanDescriptor<?> desc : descriptors) {
if (desc.getBaseTable() != null) {
visitBean(desc, visitor);
}
}
}
/**
* Visit the bean using a visitor.
*/
protected void visitBean(BeanDescriptor<?> desc, BeanVisitor visitor) {
BeanPropertyVisitor propertyVisitor = visitor.visitBean(desc);
if (propertyVisitor != null) {
BeanProperty idProp = desc.getIdProperty();
if (idProp != null) {
visit(propertyVisitor, idProp);
}
BeanPropertyAssocOne<?> unidirectional = desc.getUnidirectional();
if (unidirectional != null) {
visit(propertyVisitor, unidirectional);
}
BeanProperty[] propertiesNonTransient = desc.propertiesNonTransient();
for (int i = 0; i < propertiesNonTransient.length; i++) {
BeanProperty p = propertiesNonTransient[i];
if (!p.isFormula() && !p.isSecondaryTable()) {
visit(propertyVisitor, p);
}
}
visitInheritanceProperties(desc, propertyVisitor);
}
}
/**
* Visit the property.
*/
protected void visit(BeanPropertyVisitor pv, BeanProperty p) {
if (p instanceof BeanPropertyAssocMany<?>) {
// oneToMany or manyToMany
pv.visitMany((BeanPropertyAssocMany<?>) p);
} else if (p instanceof BeanPropertyAssocOne<?>) {
BeanPropertyAssocOne<?> assocOne = (BeanPropertyAssocOne<?>) p;
if (assocOne.isEmbedded()) {
// Embedded bean
pv.visitEmbedded(assocOne);
BeanProperty[] embProps = assocOne.getProperties();
for (int i = 0; i < embProps.length; i++) {
pv.visitEmbeddedScalar(embProps[i], assocOne);
}
} else if (assocOne.isOneToOneExported()) {
// associated one exported
pv.visitOneExported(assocOne);
} else {
// associated one imported
pv.visitOneImported(assocOne);
}
} else if (p instanceof BeanPropertyCompound) {
// compound type
BeanPropertyCompound compound = (BeanPropertyCompound) p;
pv.visitCompound(compound);
BeanProperty[] properties = compound.getScalarProperties();
for (int i = 0; i < properties.length; i++) {
pv.visitCompoundScalar(compound, properties[i]);
}
} else {
// simple scalar type
pv.visitScalar(p);
}
}
/**
* Visit all the other inheritance properties that are not on the root.
*/
protected void visitInheritanceProperties(BeanDescriptor<?> descriptor, BeanPropertyVisitor pv) {
InheritInfo inheritInfo = descriptor.getInheritInfo();
if (inheritInfo != null && inheritInfo.isRoot()) {
// add all properties on the children objects
InheritChildVisitor childVisitor = new InheritChildVisitor(this, pv);
inheritInfo.visitChildren(childVisitor);
}
}
/**
* Helper used to visit all the inheritInfo/BeanDescriptor in
* the inheritance hierarchy (to add their 'local' properties).
*/
protected class InheritChildVisitor implements InheritInfoVisitor {
private final VisitAllUsing owner;
private final BeanPropertyVisitor pv;
protected InheritChildVisitor(VisitAllUsing owner, BeanPropertyVisitor pv) {
this.owner = owner;
this.pv = pv;
}
public void visit(InheritInfo inheritInfo) {
BeanProperty[] propertiesLocal = inheritInfo.getBeanDescriptor().propertiesLocal();
for (int i = 0; i <propertiesLocal.length ; i++) {
owner.visit(pv, propertiesLocal[i]);
}
}
}
}
@@ -15,6 +15,7 @@ import java.util.List;
import javax.persistence.PersistenceException;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -39,6 +40,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
private boolean generateDdl;
private boolean runDdl;
private CurrentModel currentModel;
private String dropContent;
private String createContent;
@@ -70,6 +72,10 @@ public class DdlGenerator implements SpiEbeanPlugin {
if (generateDdl) {
writeDrop(getDropFileName());
writeCreate(getCreateFileName());
String mn = server.getName() + "-migration.xml";
File migrationXml = new File(mn);
writeMigration(migrationXml);
}
}
@@ -122,44 +128,60 @@ public class DdlGenerator implements SpiEbeanPlugin {
public String generateDropDdl() {
DdlGenContext ctx = createContext();
if (ctx.getDdlSyntax().isDropKeyConstraints()) {
// generate drop foreign key constraint statements (sql server joy)
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(false, ctx);
VisitorUtil.visit(server, fkeys);
ctx.writeNewLine();
try {
dropContent = currentModel().getDropDdl();
return dropContent;
} catch (IOException e) {
throw new RuntimeException(e);
}
// DdlGenContext ctx = createContext();
//
// if (ctx.getDdlSyntax().isDropKeyConstraints()) {
// // generate drop foreign key constraint statements (sql server joy)
// AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(false, ctx);
// VisitorUtil.visit(server, fkeys);
// ctx.writeNewLine();
// }
//
// DropTableVisitor drop = new DropTableVisitor(ctx);
// VisitorUtil.visit(server, drop);
//
// DropSequenceVisitor dropSequence = new DropSequenceVisitor(ctx);
// VisitorUtil.visit(server, dropSequence);
//
// ctx.flush();
// dropContent = ctx.getContent();
// return dropContent;
}
public void writeMigration(File file) {
DropTableVisitor drop = new DropTableVisitor(ctx);
VisitorUtil.visit(server, drop);
DropSequenceVisitor dropSequence = new DropSequenceVisitor(ctx);
VisitorUtil.visit(server, dropSequence);
ctx.flush();
dropContent = ctx.getContent();
return dropContent;
currentModel().writeMigration(file);
}
public String generateCreateDdl() {
DdlGenContext ctx = createContext();
CreateTableVisitor create = new CreateTableVisitor(ctx);
VisitorUtil.visit(server, create);
CreateSequenceVisitor createSequence = new CreateSequenceVisitor(ctx);
VisitorUtil.visit(server, createSequence);
AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(true, ctx);
VisitorUtil.visit(server, fkeys);
CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
VisitorUtil.visit(server, indexes);
ctx.flush();
createContent = ctx.getContent();
return createContent;
try {
createContent = currentModel().getCreateDdl();
return createContent;
} catch (IOException e) {
throw new RuntimeException(e);
}
// DdlGenContext ctx = createContext();
// CreateTableVisitor create = new CreateTableVisitor(ctx);
// VisitorUtil.visit(server, create);
//
// CreateSequenceVisitor createSequence = new CreateSequenceVisitor(ctx);
// VisitorUtil.visit(server, createSequence);
//
// AddForeignKeysVisitor fkeys = new AddForeignKeysVisitor(true, ctx);
// VisitorUtil.visit(server, fkeys);
//
// CreateIndexVisitor indexes = new CreateIndexVisitor(ctx);
// VisitorUtil.visit(server, indexes);
//
// ctx.flush();
// createContent = ctx.getContent();
// return createContent;
}
protected String getDropFileName() {
@@ -174,6 +196,15 @@ public class DdlGenerator implements SpiEbeanPlugin {
return new DdlGenContext(dbPlatform, namingConvention);
}
protected CurrentModel currentModel() {
if (currentModel == null) {
currentModel = new CurrentModel(server);
}
return currentModel;
}
protected void writeFile(String fileName, String fileContent) throws IOException {
File f = new File(fileName);
@@ -199,7 +230,7 @@ public class DdlGenerator implements SpiEbeanPlugin {
FileReader fr = new FileReader(f);
LineNumberReader lr = new LineNumberReader(fr);
try {
String s = null;
String s;
while ((s = lr.readLine()) != null) {
buf.append(s).append("\n");
}
@@ -0,0 +1,328 @@
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://ebean-orm.github.io/xml/ns/dbmigration"
targetNamespace="http://ebean-orm.github.io/xml/ns/dbmigration" elementFormDefault="qualified">
<!-- =========================================================== -->
<!-- APPLICATIONS -->
<!-- =========================================================== -->
<!-- Root level type : applications -->
<xsd:element name="applications">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="application" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="application">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="resourcePath" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- =========================================================== -->
<!-- CHANGE LOG -->
<!-- =========================================================== -->
<!-- Root level type : migration -->
<xsd:element name="migration">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="changeSet" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="changeSet">
<xsd:complexType>
<xsd:sequence>
<xsd:choice>
<xsd:group ref="changeSetChildren" minOccurs="0" maxOccurs="unbounded"/>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="id" type="xsd:positiveInteger" use="required"/>
<xsd:attribute name="comment" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<!-- =========================================================== -->
<!-- CHANGE SET CHILDREN -->
<!-- =========================================================== -->
<xsd:element name="sql">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="apply" minOccurs="1" maxOccurs="1"/>
<xsd:element ref="rollback" minOccurs="1" maxOccurs="1"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="apply">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="rollback">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<!-- CONFIGURATION -->
<xsd:element name="configuration">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="defaultTablespace"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="defaultTablespace">
<xsd:complexType>
<xsd:attribute name="tables" type="xsd:string"/>
<xsd:attribute name="indexes" type="xsd:string"/>
<xsd:attribute name="history" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<!-- TABLE -->
<xsd:element name="createTable">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="column" minOccurs="1" maxOccurs="unbounded"/>
<xsd:element ref="uniqueConstraint" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="foreignKey" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element ref="primaryKey" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="withHistory" type="xsd:boolean"/>
<xsd:attributeGroup ref="tablespaceAttributes"/>
</xsd:complexType>
</xsd:element>
<!-- Only expected to be used for compound unique constraint -->
<xsd:element name="uniqueConstraint">
<xsd:complexType>
<xsd:attribute name="columnNames" type="xsd:string" use="required"/>
<xsd:attribute name="constraintName" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<!-- Only expected to be used for compound foreign keys -->
<xsd:element name="foreignKey">
<xsd:complexType>
<xsd:attribute name="columnNames" type="xsd:string" use="required"/>
<xsd:attribute name="refColumnNames" type="xsd:string" use="required"/>
<xsd:attribute name="refTableName" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- Only expected to be used for compound primary key -->
<xsd:element name="primaryKey">
<xsd:complexType>
<xsd:attribute name="columnNames" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="dropTable">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="renameTable">
<xsd:complexType>
<xsd:attribute name="oldName" type="xsd:string" use="required"/>
<xsd:attribute name="newName" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- HISTORY -->
<xsd:element name="createHistoryTable">
<xsd:complexType>
<xsd:attribute name="baseTable" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="dropHistoryTable">
<xsd:complexType>
<xsd:attribute name="baseTable" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- COLUMN -->
<xsd:element name="addColumn">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="column" minOccurs="1" maxOccurs="unbounded"/>
</xsd:sequence>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="dropColumn">
<xsd:complexType>
<xsd:attribute name="columnName" type="xsd:string" use="required"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="renameColumn">
<xsd:complexType>
<xsd:attribute name="oldName" type="xsd:string" use="required"/>
<xsd:attribute name="newName" type="xsd:string" use="required"/>
<xsd:attribute name="tableName" type="xsd:string" use="required"/>
<xsd:attribute name="dataType" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<!-- VIEW -->
<xsd:element name="createView">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="replaceIfExists" type="xsd:boolean"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="dropView">
<xsd:complexType>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="renameView">
<xsd:complexType>
<xsd:attribute name="oldName" type="xsd:string" use="required"/>
<xsd:attribute name="newName" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- FOREIGN KEY -->
<xsd:element name="addForeignKey">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="columns" type="xsd:string" use="required"/>
<xsd:attribute name="references" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="dropForeignKey">
<xsd:complexType mixed="true">
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
<!-- ============================================ -->
<xsd:element name="column">
<xsd:complexType mixed="true">
<xsd:attributeGroup ref="column"/>
<xsd:attributeGroup ref="columnAttributes"/>
</xsd:complexType>
</xsd:element>
<xsd:attributeGroup name="tablespaceAttributes">
<xsd:attribute name="tablespace" type="xsd:string"/>
<xsd:attribute name="indexTablespace" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
</xsd:attributeGroup>
<xsd:attributeGroup name="columnAttributes">
<xsd:attribute name="notnull" type="xsd:boolean"/>
<xsd:attribute name="checkConstraint" type="xsd:string"/>
<xsd:attribute name="unique" type="xsd:boolean"/>
<xsd:attribute name="primaryKey" type="xsd:boolean"/>
<xsd:attribute name="identity" type="xsd:boolean"/> <!-- aka autoincrement/identity -->
<xsd:attribute name="references" type="xsd:string"/>
<!--<xsd:attribute name="primaryKeyTablespace" type="xsd:string"/>-->
<!--<xsd:attribute name="deleteCascade" type="xsd:boolean"/>-->
<!--<xsd:attribute name="deferrable" type="xsd:boolean"/>-->
<!--<xsd:attribute name="initiallyDeferred" type="xsd:boolean"/>-->
</xsd:attributeGroup>
<xsd:attributeGroup name="column">
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="type" type="xsd:string" use="required"/>
<xsd:attribute name="defaultValue" type="xsd:string"/>
<xsd:attribute name="remarks" type="xsd:string"/>
</xsd:attributeGroup>
<!-- Children for changeSet -->
<xsd:group name="changeSetChildren">
<xsd:choice>
<xsd:element ref="configuration" maxOccurs="1"/>
<xsd:element ref="sql" maxOccurs="unbounded"/>
<xsd:element ref="createTable" maxOccurs="unbounded"/>
<xsd:element ref="dropTable" maxOccurs="unbounded"/>
<xsd:element ref="renameTable" maxOccurs="unbounded"/>
<xsd:element ref="createHistoryTable" maxOccurs="unbounded"/>
<xsd:element ref="createView" maxOccurs="unbounded"/>
<xsd:element ref="dropView" maxOccurs="unbounded"/>
<xsd:element ref="renameView" maxOccurs="unbounded"/>
<xsd:element ref="addColumn" maxOccurs="unbounded"/>
<xsd:element ref="dropColumn" maxOccurs="unbounded"/>
<xsd:element ref="renameColumn" maxOccurs="unbounded"/>
<xsd:element ref="addForeignKey" maxOccurs="unbounded"/>
<xsd:element ref="dropForeignKey" maxOccurs="unbounded"/>
<!--<xsd:element ref="createIndex" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="dropIndex" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="createSequence" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="alterSequence" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="dropSequence" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="addNotNullConstraint" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="dropNotNullConstraint" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="addPrimaryKey" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="dropPrimaryKey" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="addUniqueConstraint" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="dropUniqueConstraint" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="addDefaultValue" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="dropDefaultValue" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="sql" maxOccurs="unbounded"/>-->
<!--<xsd:element ref="createProcedure" maxOccurs="unbounded"/>-->
</xsd:choice>
</xsd:group>
</xsd:schema>
@@ -0,0 +1,131 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.DdlNamingConvention;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.H2Ddl;
import com.avaje.ebean.dbmigration.ddlgeneration.platform.PostgresDdl;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class BaseDdlHandlerTest extends BaseTestCase {
private BaseDdlHandler h2Handler() {
DbTypeMap types = new H2Platform().getDbTypeMap();
return new BaseDdlHandler(new DdlNamingConvention(), new H2Ddl(types));
}
private BaseDdlHandler postgresHandler() {
DbTypeMap pgTypes = new PostgresPlatform().getDbTypeMap();
PostgresDdl pgDdl = new PostgresDdl(pgTypes);
return new BaseDdlHandler(new DdlNamingConvention(), pgDdl);
}
@Test
public void addColumn_nullable_noConstraint() throws Exception {
DdlWrite write = new DdlWrite();
BaseDdlHandler handler = h2Handler();
handler.generate(write, Helper.getAddColumn());
assertThat(write.apply().getBuffer()).isEqualTo("alter table foo add column added_to_foo varchar(20);\n\n");
assertThat(write.rollback().getBuffer()).isEqualTo("alter table foo drop column added_to_foo;\n\n");
}
@Test
public void dropColumn() throws Exception {
DdlWrite write = new DdlWrite();
BaseDdlHandler handler = h2Handler();
handler.generate(write, Helper.getDropColumn());
assertThat(write.apply().getBuffer()).isEqualTo("alter table foo drop column col2;\n\n");
assertThat(write.rollback().getBuffer()).isEqualTo("");
}
@Test
public void createTable() throws Exception {
DdlWrite write = new DdlWrite();
BaseDdlHandler handler = h2Handler();
handler.generate(write, Helper.getCreateTable());
String createTableDDL = Helper.asText(this, "/assert/create-table.txt");
assertThat(write.apply().getBuffer()).isEqualTo(createTableDDL);
assertThat(write.rollback().getBuffer()).isEqualTo("drop table foo;\n\n");
}
@Test
public void generateChangeSet() throws Exception {
DdlWrite write = new DdlWrite();
BaseDdlHandler handler = h2Handler();
handler.generate(write, Helper.getChangeSet());
String apply = Helper.asText(this, "/assert/BaseDdlHandlerTest/apply.sql");
String rollbackLast = Helper.asText(this, "/assert/BaseDdlHandlerTest/rollback.sql");
assertThat(write.apply().getBuffer()).isEqualTo(apply);
assertThat(write.rollback().getBuffer()).isEqualTo(rollbackLast);
}
@Test
public void generateChangeSetFromModel() throws Exception {
SpiEbeanServer defaultServer = (SpiEbeanServer) Ebean.getDefaultServer();
ChangeSet createChangeSet = new CurrentModel(defaultServer).getChangeSet();
DdlWrite write = new DdlWrite();
BaseDdlHandler handler = h2Handler();
handler.generate(write, createChangeSet);
String apply = Helper.asText(this, "/assert/changeset-apply.txt");
String rollbackLast = Helper.asText(this, "/assert/changeset-rollback.txt");
assertThat(write.apply().getBuffer()).isEqualTo(apply);
assertThat(write.rollback().getBuffer()).isEqualTo(rollbackLast);
}
@Test
public void generateChangeSetFromModel_given_postgresTypes() throws Exception {
SpiEbeanServer defaultServer = (SpiEbeanServer) Ebean.getDefaultServer();
ChangeSet createChangeSet = new CurrentModel(defaultServer).getChangeSet();
DdlWrite write = new DdlWrite();
BaseDdlHandler handler = postgresHandler();
handler.generate(write, createChangeSet);
String apply = Helper.asText(this, "/assert/changeset-pg-apply.sql");
String applyLast = Helper.asText(this, "/assert/changeset-pg-applyLast.sql");
String rollbackFirst = Helper.asText(this, "/assert/changeset-pg-rollbackFirst.sql");
String rollbackLast = Helper.asText(this, "/assert/changeset-pg-rollbackLast.sql");
assertThat(write.apply().getBuffer()).isEqualTo(apply);
assertThat(write.applyForeignKeys().getBuffer()).isEqualTo(applyLast);
assertThat(write.rollbackForeignKeys().getBuffer()).isEqualTo(rollbackFirst);
assertThat(write.rollback().getBuffer()).isEqualTo(rollbackLast);
}
}
@@ -0,0 +1,76 @@
package com.avaje.ebean.dbmigration.ddlgeneration;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.util.List;
/**
* Helper for testing to return some basic migration objects.
*/
public class Helper {
static Migration migration = MigrationXmlReader.read("/container/test-create-table.xml");
static ChangeSet changeSet;
static List<Object> changeSetChildren;
static {
List<ChangeSet> changeSets = migration.getChangeSet();
changeSet = changeSets.get(0);
changeSetChildren = changeSet.getChangeSetChildren();
}
public static ChangeSet getChangeSet() {
return changeSet;
}
public static CreateTable getCreateTable() {
return (CreateTable) changeSetChildren.get(0);
}
public static AddColumn getAddColumn() {
return (AddColumn) changeSetChildren.get(1);
}
public static DropColumn getDropColumn() {
return (DropColumn) changeSetChildren.get(2);
}
public static String asText(Object instance, String relativePath) throws IOException {
InputStream is = instance.getClass().getResourceAsStream(relativePath);
if (is == null) {
throw new IllegalArgumentException("resource "+relativePath+" not found");
}
return asText(is);
}
public static String asText(InputStream in) throws IOException {
try {
InputStreamReader reader = new InputStreamReader(in);
LineNumberReader lineNumberReader = new LineNumberReader(reader);
StringBuilder builder = new StringBuilder(400);
String line;
while ((line = lineNumberReader.readLine()) != null) {
builder.append(line).append("\n");
}
return builder.toString();
} finally {
in.close();
}
}
}
@@ -0,0 +1,70 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.ddlgeneration.Helper;
import com.avaje.ebean.dbmigration.migration.Column;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class BaseTableDdlTest {
@Test
public void testGenerate() throws Exception {
BaseTableDdl ddlGen = new BaseTableDdl(new DdlNamingConvention(), new H2Ddl(new DbTypeMap()));
DdlWrite write = new DdlWrite();
ddlGen.generate(write, createTable());
String apply = write.apply().getBuffer();
String applyLast = write.applyForeignKeys().getBuffer();
String rollbackFirst = write.rollbackForeignKeys().getBuffer();
String rollbackLast = write.rollback().getBuffer();
assertThat(apply).isEqualTo( Helper.asText(this, "/assert/BaseTableDdlTest/createTable-apply.txt"));
assertThat(applyLast).isEqualTo( Helper.asText(this, "/assert/BaseTableDdlTest/createTable-applyLast.txt"));
assertThat(rollbackFirst).isEqualTo( Helper.asText(this, "/assert/BaseTableDdlTest/createTable-rollbackFirst.txt"));
assertThat(rollbackLast).isEqualTo( Helper.asText(this, "/assert/BaseTableDdlTest/createTable-rollback.txt"));
}
private CreateTable createTable() {
CreateTable createTable = new CreateTable();
createTable.setName("mytable");
List<Column> columns = createTable.getColumn();
Column col = new Column();
col.setName("id");
col.setType("integer");
col.setPrimaryKey(true);
columns.add(col);
Column col2 = new Column();
col2.setName("status");
col2.setType("varchar(1)");
col2.setNotnull(true);
col2.setCheckConstraint("check (status in ('A','B'))");
columns.add(col2);
Column col3 = new Column();
col3.setName("order_id");
col3.setType("integer");
col3.setNotnull(true);
col3.setReferences("orders.id");
columns.add(col3);
return createTable;
}
}
@@ -0,0 +1,29 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class DbNameNormaliseTest {
DbNameNormalise normalise = new DbNameNormalise();
@Test
public void testNormalise() throws Exception {
assertThat(normalise.normalise("cat.sch.foo_bar]")).isEqualTo("foo_bar");
assertThat(normalise.normalise("sch.foo_bar]")).isEqualTo("foo_bar");
assertThat(normalise.normalise("foo_bar]")).isEqualTo("foo_bar");
}
@Test
public void testTrimQuotes() throws Exception {
assertThat(normalise.trimQuotes("[foo]")).isEqualTo("foo");
assertThat(normalise.trimQuotes("'foo'")).isEqualTo("foo");
assertThat(normalise.trimQuotes("\"foo\"")).isEqualTo("foo");
assertThat(normalise.trimQuotes("`foo`")).isEqualTo("foo");
assertThat(normalise.trimQuotes("`fo_o`")).isEqualTo("fo_o");
}
}
@@ -0,0 +1,43 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class DdlNamingConventionTest {
DdlNamingConvention defaultNaming = new DdlNamingConvention();
@Test
public void testPrimaryKeyName() throws Exception {
List<String> cols = new ArrayList<String>();
cols.add("[jim]");
cols.add("`jack`");
assertThat(defaultNaming.primaryKeyName("[cat].[sce].[foo_bar]", cols)).isEqualTo("pk_foo_bar");
}
@Test
public void testUniqueConstraintName() throws Exception {
assertThat(defaultNaming.uniqueConstraintName("[foo_bar]", "[jim]")).isEqualTo("uq_foo_bar_jim");
}
@Test
public void testCheckConstraintName() throws Exception {
assertThat(defaultNaming.checkConstraintName("[foo_bar]", "[jim]")).isEqualTo("ck_foo_bar_jim");
}
@Test
public void testNormalise() throws Exception {
assertThat(defaultNaming.normalise("cat.sch.foo_bar]")).isEqualTo("foo_bar");
assertThat(defaultNaming.normalise("sch.foo_bar]")).isEqualTo("foo_bar");
assertThat(defaultNaming.normalise("foo_bar]")).isEqualTo("foo_bar");
}
}
@@ -0,0 +1,80 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.config.dbplatform.DbTypeMap;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.config.dbplatform.PostgresPlatform;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class PlatformTypeConverterTest {
@Test
public void testConvert_given_postgres() throws Exception {
PostgresPlatform pg = new PostgresPlatform();
DbTypeMap dbTypeMap = pg.getDbTypeMap();
PlatformTypeConverter converter = new PlatformTypeConverter(dbTypeMap);
assertThat(converter.convert("varchar(10)")).isEqualTo("varchar(10)");
assertThat(converter.convert("decimal(10,2)")).isEqualTo("decimal(10,2)");
assertThat(converter.convert("clob")).isEqualTo("text");
assertThat(converter.convert("blob")).isEqualTo("bytea");
assertThat(converter.convert("tinyint")).isEqualTo("smallint");
assertThat(converter.convert("funky")).isEqualTo("funky"); // unknown
assertThat(converter.convert("integer(8)")).isEqualTo("integer"); // removes scale
assertThat(converter.convert("funky(")).isEqualTo("funky(");
assertThat(converter.convert("funky()")).isEqualTo("funky()");
assertThat(converter.convert("funky)")).isEqualTo("funky)");
}
@Test
public void testConvert_given_h2() throws Exception {
H2Platform platform = new H2Platform();
DbTypeMap dbTypeMap = platform.getDbTypeMap();
PlatformTypeConverter converter = new PlatformTypeConverter(dbTypeMap);
assertThat(converter.convert("varchar(10)")).isEqualTo("varchar(10)");
assertThat(converter.convert("decimal(10,2)")).isEqualTo("decimal(10,2)");
assertThat(converter.convert("clob")).isEqualTo("clob");
assertThat(converter.convert("blob")).isEqualTo("blob");
assertThat(converter.convert("tinyint")).isEqualTo("tinyint");
assertThat(converter.convert("integer(8)")).isEqualTo("integer(8)");
assertThat(converter.convert("funky")).isEqualTo("funky"); // unknown
}
@Test
public void testConvertJsonTypes_given_postgres() {
PostgresPlatform platform = new PostgresPlatform();
DbTypeMap dbTypeMap = platform.getDbTypeMap();
PlatformTypeConverter converter = new PlatformTypeConverter(dbTypeMap);
assertThat(converter.convert("jsonblob")).isEqualTo("bytea");
assertThat(converter.convert("jsonclob")).isEqualTo("text");
assertThat(converter.convert("jsonvarchar(200)")).isEqualTo("varchar(200)");
assertThat(converter.convert("json")).isEqualTo("json");
assertThat(converter.convert("jsonb")).isEqualTo("jsonb");
}
@Test
public void testConvertJsonTypes_given_h2() {
H2Platform platform = new H2Platform();
DbTypeMap dbTypeMap = platform.getDbTypeMap();
PlatformTypeConverter converter = new PlatformTypeConverter(dbTypeMap);
assertThat(converter.convert("jsonblob")).isEqualTo("blob");
assertThat(converter.convert("jsonclob")).isEqualTo("clob");
assertThat(converter.convert("jsonvarchar(200)")).isEqualTo("varchar(200)");
assertThat(converter.convert("json")).isEqualTo("clob");
assertThat(converter.convert("jsonb")).isEqualTo("clob");
}
}
@@ -0,0 +1,26 @@
package com.avaje.ebean.dbmigration.migrationreader;
import com.avaje.ebean.dbmigration.migration.Migration;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
public class MigrationXmlWriterTest {
Logger logger = LoggerFactory.getLogger(MigrationXmlWriterTest.class);
@Test
public void testWrite() throws Exception {
Migration migration = MigrationXmlReader.read("/test/container/test-create-table.xml");
File temp = File.createTempFile("migrationWrite",".xml");
MigrationXmlWriter writer = new MigrationXmlWriter();
writer.write(migration, temp);
logger.info("wrote migration file: "+temp.getAbsolutePath());
}
}
@@ -0,0 +1,41 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
import com.avaje.ebean.dbmigration.migration.CreateTable;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.Migration;
import com.avaje.ebean.dbmigration.migrationreader.MigrationXmlReader;
import org.junit.Test;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class ModelContainerApplyTest {
@Test
public void testApply() throws Exception {
Migration migration = MigrationXmlReader.read("/test/container/test-create-table.xml");
List<ChangeSet> changeSets = migration.getChangeSet();
ChangeSet changeSet = changeSets.get(0);
List<Object> changeSetChildren = changeSet.getChangeSetChildren();
assertThat(changeSetChildren).hasSize(3);
assertThat(changeSetChildren.get(0)).isInstanceOf(CreateTable.class);
assertThat(changeSetChildren.get(1)).isInstanceOf(AddColumn.class);
assertThat(changeSetChildren.get(2)).isInstanceOf(DropColumn.class);
ModelContainer model = new ModelContainer();
model.apply(migration);
MTable foo = model.getTable("foo");
assertThat(foo.getRemarks()).isEqualTo("comment");
assertThat(foo.getTablespace()).isEqualTo("fooSpace");
assertThat(foo.getIndexTablespace()).isEqualTo("fooIndexSpace");
assertThat(foo.getWithHistory()).isEqualTo(true);
assertThat(foo.getColumns()).containsKeys("col1", "col3", "added_to_foo");
}
}
@@ -0,0 +1,33 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.Ebean;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
import com.avaje.ebean.dbmigration.model.visitor.VisitAllUsing;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class ModelBuildBeanVisitorTest extends BaseTestCase {
@Test
public void test() {
SpiEbeanServer defaultServer = (SpiEbeanServer)Ebean.getDefaultServer();
ModelContainer model = new ModelContainer();
ModelBuildContext ctx = new ModelBuildContext(model);
ModelBuildBeanVisitor addTable = new ModelBuildBeanVisitor(ctx);
new VisitAllUsing(addTable, defaultServer).visitAllBeans();
MTable customer = model.getTable("o_customer");
assertThat(customer).isNotNull();
}
}
@@ -0,0 +1,51 @@
package com.avaje.ebean.dbmigration.model.build;
import com.avaje.ebean.BaseTestCase;
import com.avaje.ebean.EbeanServerFactory;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebean.dbmigration.model.MTable;
import com.avaje.ebean.dbmigration.model.ModelContainer;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.tests.model.basic.CKeyAssoc;
import com.avaje.tests.model.basic.CKeyDetail;
import com.avaje.tests.model.basic.CKeyParent;
import com.avaje.tests.model.basic.CKeyParentId;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class ModelBuild_compoundKeyTest extends BaseTestCase {
@Test
public void test() {
ServerConfig config = new ServerConfig();
config.setName("h2");
config.loadFromProperties();
config.setName("h2other");
config.setDdlGenerate(false);
config.setDdlRun(false);
config.setDefaultServer(false);
config.setRegister(false);
config.addClass(CKeyDetail.class);
config.addClass(CKeyParent.class);
config.addClass(CKeyAssoc.class);
config.addClass(CKeyParentId.class);
SpiEbeanServer ebeanServer = (SpiEbeanServer)EbeanServerFactory.create(config);
CurrentModel currentModel = new CurrentModel(ebeanServer);
ModelContainer model = currentModel.read();
MTable parent = model.getTable("ckey_parent");
MTable detail = model.getTable("ckey_detail");
assertThat(parent).isNotNull();
assertThat(detail).isNotNull();
}
}
@@ -4,7 +4,7 @@ import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class CKeyAssoc {
public class CKeyAssoc {
@Id
Integer id;
@@ -0,0 +1,8 @@
create table mytable (
id integer not null,
status varchar(1) not null,
order_id integer not null,
constraint ck_mytable_status check (status in ('A','B')),
constraint pk_mytable primary key (id)
);
@@ -0,0 +1,3 @@
alter table mytable add constraint fk_mytable_order_id foreign key (order_id) references orders (id) on delete restrict on update restrict;
create index ix_mytable_order_id on mytable (order_id);
@@ -0,0 +1,2 @@
drop table mytable;
@@ -0,0 +1,3 @@
drop index ix_mytable_order_id;
alter table mytable drop constraint fk_mytable_order_id;
@@ -0,0 +1,182 @@
create table o_address (
id bigint not null,
line1 varchar(100),
line2 varchar(100),
city varchar(100),
country_code varchar(2),
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint pk_o_address primary key (id)
);
create table blob_holder (
id bigint not null,
text_content clob,
binary_content blob,
file_content blob,
version bigint not null,
constraint pk_blob_holder primary key (id)
);
create table car_accessory (
id bigint not null,
name varchar(255),
car_id bigint,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint pk_car_accessory primary key (id)
);
create table be_contact (
id bigint not null,
first_name varchar(50),
last_name varchar(50),
email varchar(200),
phone varchar(20),
customer_id bigint not null,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint pk_be_contact primary key (id)
);
create table contact_note (
id bigint not null,
contact_id bigint not null,
title varchar(255),
note clob,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint pk_contact_note primary key (id)
);
create table o_country (
code varchar(2) not null,
name varchar(60),
constraint pk_o_country primary key (code)
);
create table be_customer (
id bigint not null,
inactive boolean,
name varchar(100),
registered timestamp,
comments varchar(1000),
billing_address_id bigint,
shipping_address_id bigint,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint uq_be_customer_name unique (name),
constraint pk_be_customer primary key (id)
);
create table document (
id bigint not null,
title varchar(255),
author varchar(255),
content clob,
version bigint not null,
constraint pk_document primary key (id)
);
create table mrole (
id integer not null,
role_name varchar(255),
constraint pk_mrole primary key (id)
);
create table mrole_muser (
mrole_id integer not null,
muser_id integer not null,
constraint pk_mrole_muser primary key (mrole_id,muser_id)
);
create table muser (
id integer not null,
user_name varchar(255),
user_type_id integer,
constraint pk_muser primary key (id)
);
create table muser_type (
id integer not null,
name varchar(255),
constraint pk_muser_type primary key (id)
);
create table o_booking (
id bigint not null,
booking_date date,
invoice_id bigint,
constraint uq_o_booking_invoice_id unique (invoice_id),
constraint pk_o_booking primary key (id)
);
create table o_invoice (
id bigint not null,
invoice_date date,
constraint pk_o_invoice primary key (id)
);
create table o_order (
id bigint not null,
status varchar(1),
order_date date,
ship_date date,
customer_id bigint,
shipping_address_id bigint,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint ck_o_order_status check (status in ('N','C','A','S')),
constraint pk_o_order primary key (id)
);
create table o_order_detail (
id bigint not null,
order_id bigint,
order_qty integer,
ship_qty integer,
unit_price double,
product_id bigint,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint pk_o_order_detail primary key (id)
);
create table o_product (
id bigint not null,
sku varchar(20),
name varchar(255),
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
constraint pk_o_product primary key (id)
);
create table truck_ref (
id integer not null,
something varchar(255),
constraint pk_truck_ref primary key (id)
);
create table vehicle (
dtype varchar(3) not null,
id bigint not null,
license_number varchar(255),
registration_date timestamp,
version bigint not null,
when_created timestamp not null,
when_modified timestamp not null,
truck_ref_id integer,
capacity double,
driver varchar(255),
car_ref_id integer,
constraint pk_vehicle primary key (id)
);
@@ -0,0 +1,38 @@
drop table o_address;
drop table blob_holder;
drop table car_accessory;
drop table be_contact;
drop table contact_note;
drop table o_country;
drop table be_customer;
drop table document;
drop table mrole;
drop table mrole_muser;
drop table muser;
drop table muser_type;
drop table o_booking;
drop table o_invoice;
drop table o_order;
drop table o_order_detail;
drop table o_product;
drop table truck_ref;
drop table vehicle;
@@ -0,0 +1,7 @@
create table foo (
col1 varchar(4) not null,
col2 varchar(30) not null,
col3 varchar(30) not null,
constraint pk_foo primary key (col1)
);
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ebean-orm.github.io/xml/ns/dbmigration http://ebean-orm.github.io/xml/ns/dbmigration-1.0.xsd">
<changeSet id="1">
<createTable name="ckey_detail">
<column name="id" type="integer" primaryKey="true" identity="true"/>
<column name="something" type="varchar(255)" />
<column name="one_key" type="integer" />
<column name="two_key" type="varchar(255)" />
</createTable>
<createTable name="ckey_parent">
<column name="one_key" type="integer" primaryKey="true" />
<column name="two_key" type="varchar(255)" primaryKey="true" />
<column name="name" type="varchar(255)" />
<column name="assoc_id" type="integer" references="ckey_assoc.id"/>
<column name="version" type="integer" notnull="true" />
</createTable>
</changeSet>
</migration>
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ebean-orm.github.io/xml/ns/dbmigration http://ebean-orm.github.io/xml/ns/dbmigration-1.0.xsd">
<changeSet id="1">
<createTable name="foo" withHistory="true" tablespace="fooSpace" indexTablespace="fooIndexSpace" remarks="comment">
<column name="col1" type="varchar(4)" notnull="true" primaryKey="true"/>
<column name="col2" type="varchar(30)" notnull="true"/>
<column name="col3" type="varchar(30)" notnull="true"/>
</createTable>
<addColumn tableName="foo">
<column name="added_to_foo" type="varchar(20)"/>
</addColumn>
<dropColumn columnName="col2" tableName="foo"/>
</changeSet>
</migration>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="UTF-8"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ebean-orm.github.io/xml/ns/dbmigration http://ebean-orm.github.io/xml/ns/dbmigration-1.0.xsd">
<changeSet id="1">
<sql>
<apply>
create table foo;
</apply>
<rollback>
drop table if exists foo;
</rollback>
</sql>
<createTable name="dbmigration">
<column name="application" type="varchar(30)" notnull="true"/>
<column name="change_log" type="integer" notnull="true"/>
<column name="change_set" type="integer" notnull="true"/>
<column name="locked_by" type="varchar(30)"/>
<column name="locked_at" type="timestamp"/>
</createTable>
<createTable name="dbmigration_changeset">
<column name="id" type="integer" primaryKey="true"/>
<column name="application" type="varchar(30)" notnull="true" references="dbmigration.application"/>
<column name="change_log" type="integer" notnull="true"/>
<column name="change_set" type="integer" notnull="true"/>
<column name="run_at" type="timestamp" notnull="true"/>
<column name="run_by" type="varchar(30)" notnull="true"/>
<column name="run_ddl" type="clob"/>
<column name="run_log" type="clob"/>
</createTable>
<createTable name="hello_world" withHistory="true">
<column name="id" type="integer" primaryKey="true"/>
<column name="name" type="varchar(20)" notnull="true"/>
<column name="type" type="varchar(20)" notnull="true"/>
<column name="description" type="varchar(20)" notnull="true"/>
<uniqueConstraint columnNames="name,type"/>
</createTable>
<addColumn tableName="hello_world">
<column name="fooe" type="varchar(20)"/>
</addColumn>
<dropColumn columnName="fooe" tableName="hello_world"/>
<createHistoryTable baseTable="hello_world"/>
<addForeignKey name="fk_hello_world_x" columns="x" references="asdsad.asd"/>
</changeSet>
</migration>
@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<migration xmlns="http://ebean-orm.github.io/xml/ns/dbmigration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ebean-orm.github.io/xml/ns/dbmigration http://ebean-orm.github.io/xml/ns/dbmigration-1.0.xsd">
<changeSet id="1">
<sql>
<apply>
create table foo;
</apply>
<rollback>
drop table if exists foo;
</rollback>
</sql>
<createTable name="dbmigration">
<column name="application" type="varchar(30)" notnull="true"/>
<column name="change_log" type="integer" notnull="true"/>
<column name="change_set" type="integer" notnull="true"/>
<column name="locked_by" type="varchar(30)"/>
<column name="locked_at" type="timestamp"/>
</createTable>
<createTable name="dbmigration_changeset">
<column name="id" type="integer" primaryKey="true"/>
<column name="application" type="varchar(30)" notnull="true" references="dbmigration.application"/>
<column name="change_log" type="integer" notnull="true"/>
<column name="change_set" type="integer" notnull="true"/>
<column name="run_at" type="timestamp" notnull="true"/>
<column name="run_by" type="varchar(30)" notnull="true"/>
<column name="run_ddl" type="clob"/>
<column name="run_log" type="clob"/>
</createTable>
<createTable name="hello_world" withHistory="true">
<column name="id" type="integer" primaryKey="true"/>
<column name="name" type="varchar(20)" notnull="true"/>
<column name="description" type="varchar(20)" notnull="true"/>
</createTable>
<addColumn tableName="hello_world">
<column name="fooe" type="varchar(20)"/>
</addColumn>
<dropColumn columnName="fooe" tableName="hello_world"/>
<createHistoryTable baseTable="hello_world"/>
</changeSet>
</migration>
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<applications xmlns="http://ebean-orm.github.io/xml/ns/dbmigration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://ebean-orm.github.io/xml/ns/dbmigration http://ebean-orm.github.io/xml/ns/dbmigration-1.0.xsd">
<application name="myapp" resourcePath="dbmigration/app1"/>
</applications>