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
@@ -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");
}