Compare commits

..
Author SHA1 Message Date
Robin Bygrave 9fbfca5f73 [maven-release-plugin] prepare release avaje-ebeanorm-6.16.5 2016-02-10 20:53:29 +13:00
Robin Bygrave 9e70ba915f #556 - DDL - DB Migration for History - change treatment of dropped columns such that they are still included in apply script 2016-02-10 16:05:59 +13:00
Robin Bygrave a1a5dcd035 #556 - DDL - DB Migration for History - change treatment of dropped columns such that they are still included in apply script 2016-02-10 16:04:46 +13:00
Robin Bygrave d2b048b0b4 No effective change - reformat code 2016-02-09 14:51:26 +13:00
Robin Bygrave 4272c17689 #555 - Use a common timestamp value for @WhenCreated and @WhenModified 2016-02-09 14:48:41 +13:00
Robin Bygrave 11723e3a32 #554 - DDL - DB Migration with @History and Postgres - views need to be dropped early to support migration changes 2016-02-05 11:54:52 +13:00
Robin Bygrave 237cdcdd3d #554 - DDL - DB Migration with @History and Postgres - views need to be dropped early to support migration changes 2016-02-05 11:52:06 +13:00
Robin Bygrave e96bee74ae [maven-release-plugin] prepare for next development iteration 2016-02-05 00:15:30 +13:00
Robin Bygrave c8b57c3302 [maven-release-plugin] prepare release avaje-ebeanorm-6.16.4 2016-02-05 00:15:04 +13:00
Robin Bygrave f65ea96b89 #553 - DDL - DB Migration with @History and Postgres needs to re-create the "with_history" view when columns dropped 2016-02-05 00:11:25 +13:00
Robin Bygrave a1bd0b469a #551 - DDL - DB Migration with @History and @Draftable - @DraftOnly columns added when not part of change 2016-02-04 22:31:07 +13:00
Robin Bygrave fd5563e3da No effective change - javadoc update for RawSql tableAliasMapping 2016-02-02 15:35:31 +13:00
Robin Bygrave f9156ede55 No effective change - add tests for RawSql tableAlias mapping of root type to null path and not mapping it 2016-02-02 14:58:59 +13:00
Robin Bygrave 10d2d591db [maven-release-plugin] prepare for next development iteration 2016-02-02 13:38:09 +13:00
56 changed files with 1353 additions and 720 deletions
+1 -1
View File
@@ -9,7 +9,7 @@
<groupId>org.avaje.ebeanorm</groupId>
<artifactId>avaje-ebeanorm</artifactId>
<version>6.16.3</version>
<version>6.16.5</version>
<packaging>jar</packaging>
<name>avaje-ebeanorm</name>
@@ -585,6 +585,9 @@ public final class RawSql implements Serializable {
* <p>
* For example modify all mappings with table alias "c" to have the path prefix "customer".
* </p>
* <p>
* For the "Root type" you don't need to specify a tableAliasMapping.
* </p>
*/
public void tableAliasMapping(String tableAlias, String path) {
@@ -106,6 +106,9 @@ public class RawSqlBuilder {
* <p>
* For example modify all mappings with table alias "c" to have the path prefix "customer".
* </p>
* <p>
* For the "Root type" you don't need to specify a tableAliasMapping.
* </p>
*/
public RawSqlBuilder tableAliasMapping(String tableAlias, String path) {
columnMapping.tableAliasMapping(tableAlias, path);
@@ -236,7 +236,7 @@ public class DbMigration {
if (databasePlatform != null) {
// writer needs the current model to provide table/column details for
// history ddl generation (triggers, history tables etc)
DdlWrite write = new DdlWrite(new MConfiguration(), currentModel.read());
DdlWrite write = new DdlWrite(new MConfiguration(), current);
PlatformDdlWriter writer = createDdlWriter(databasePlatform, "");
writer.processMigration(dbMigration, write, migrationDir , fullVersion);
}
@@ -10,14 +10,24 @@ import com.avaje.ebean.dbmigration.model.ModelContainer;
*/
public class DdlWrite {
public enum Mode {
APPLY,
ROLLBACK,
DROP
}
private final ModelContainer currentModel;
private final DdlBuffer applyDropDependencies;
private final DdlBuffer apply;
private final DdlBuffer applyForeignKeys;
private final DdlBuffer applyHistory;
private final DdlBuffer rollbackDropDependencies;
private final DdlBuffer rollbackForeignKeys;
private final DdlBuffer rollback;
@@ -39,6 +49,11 @@ public class DdlWrite {
*/
private final DdlBuffer dropHistory;
/**
* Buffer used to drop dependencies early in the 'drop script'.
*/
private final DdlBuffer dropDropDependencies;
/**
* Create without any configuration or current model (no history support).
*/
@@ -51,13 +66,16 @@ public class DdlWrite {
*/
public DdlWrite(MConfiguration configuration, ModelContainer currentModel) {
this.currentModel = currentModel;
this.applyDropDependencies = new BaseDdlBuffer(configuration);
this.apply = new BaseDdlBuffer(configuration);
this.applyForeignKeys = new BaseDdlBuffer(configuration);
this.applyHistory = new BaseDdlBuffer(configuration);
this.rollbackDropDependencies = new BaseDdlBuffer(configuration);
this.rollbackForeignKeys = new BaseDdlBuffer(configuration);
this.rollback = new BaseDdlBuffer(configuration);
this.drop = new BaseDdlBuffer(configuration);
this.dropHistory = new BaseDdlBuffer(configuration);
this.dropDropDependencies = new BaseDdlBuffer(configuration);
}
/**
@@ -77,7 +95,8 @@ public class DdlWrite {
public boolean isApplyEmpty() {
return apply.getBuffer().isEmpty()
&& applyForeignKeys.getBuffer().isEmpty()
&& applyHistory.getBuffer().isEmpty();
&& applyHistory.getBuffer().isEmpty()
&& applyDropDependencies.getBuffer().isEmpty();
}
/**
@@ -85,9 +104,51 @@ public class DdlWrite {
*/
public boolean isApplyRollbackEmpty() {
return rollback.getBuffer().isEmpty()
&& rollbackForeignKeys.getBuffer().isEmpty();
&& rollbackForeignKeys.getBuffer().isEmpty()
&& rollbackDropDependencies.getBuffer().isEmpty();
}
/**
* Return the apply or rollback buffer.
*/
public DdlBuffer buffer(Mode mode) {
switch (mode) {
case APPLY: return apply();
case ROLLBACK: return rollback();
case DROP: return drop();
default:
throw new IllegalStateException("Invalid mode" + mode);
}
}
/**
* Return the apply or rollback buffer.
*/
public DdlBuffer historyBuffer(Mode mode) {
switch (mode) {
case APPLY: return applyHistory();
case ROLLBACK: return rollback();
case DROP: return dropHistory();
default:
throw new IllegalStateException("Invalid mode" + mode);
}
}
/**
* Return the apply or rollback drop dependencies buffer.
*/
public DdlBuffer dropDependencies(Mode mode) {
switch (mode) {
case APPLY: return applyDropDependencies();
case ROLLBACK: return rollbackDropDependencies();
case DROP: return dropDropDependencies();
default:
throw new IllegalStateException("Invalid mode" + mode);
}
}
/**
* Return true the drop buffers are empty.
*/
@@ -102,6 +163,13 @@ public class DdlWrite {
return apply;
}
/**
* Return the buffer that executes early to drop dependencies like views etc.
*/
public DdlBuffer applyDropDependencies() {
return applyDropDependencies;
}
/**
* Return the buffer that APPLY DDL is written to for foreign keys and their associated indexes.
* <p>
@@ -119,6 +187,13 @@ public class DdlWrite {
return applyHistory;
}
/**
* Return the buffer that rollback executes early to drop dependencies like views.
*/
public DdlBuffer rollbackDropDependencies() {
return rollbackDropDependencies;
}
/**
* Return the buffer that ROLLBACK DDL is written to for foreign keys and associated indexes.
*/
@@ -156,5 +231,11 @@ public class DdlWrite {
return dropHistory;
}
/**
* Return the buffer that executes early for 'drop' script.
*/
public DdlBuffer dropDropDependencies() {
return dropDropDependencies;
}
}
@@ -10,7 +10,6 @@ import com.avaje.ebean.dbmigration.model.MColumn;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -45,21 +44,71 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
this.historySuffix = serverConfig.getHistoryTableSuffix();
this.constraintNaming = serverConfig.getConstraintNaming();
this.sysPeriodStart = sysPeriod+"_start";
this.sysPeriodEnd = sysPeriod+"_end";
this.sysPeriodStart = sysPeriod + "_start";
this.sysPeriodEnd = sysPeriod + "_end";
}
@Override
public void regenerateHistoryTriggers(DdlWrite writer, HistoryTableUpdate update) throws IOException {
public void updateTriggers(DdlWrite writer, HistoryTableUpdate update) throws IOException {
MTable table = writer.getTable(update.getBaseTable());
if (table == null) {
throw new IllegalStateException("MTable "+update.getBaseTable()+" not found in writer? (required for history DDL)");
throw new IllegalStateException("MTable " + update.getBaseTable() + " not found in writer? (required for history DDL)");
}
regenerateHistoryTriggers(writer, table, update);
updateTriggers(writer, table, update);
}
protected abstract void regenerateHistoryTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException;
/**
* Replace the existing triggers/stored procedures/views for history table support given the included columns.
*/
protected abstract void updateHistoryTriggers(DbTriggerUpdate triggerUpdate) throws IOException;
/**
* Process the HistoryTableUpdate which can result in changes to the apply, rollback
* and drop scripts.
*/
protected void updateTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
DbTriggerUpdate triggerUpdate = createDbTriggerUpdate(writer, table);
if (update.hasApplyChanges()) {
// includes add, include and exclude column changes
String applyChangeDescription = update.descriptionForApply();
List<String> includedColumns = columnNamesForApply(table);
DdlBuffer apply = writer.applyHistory();
apply.append("-- changes: ").append(applyChangeDescription).newLine();
triggerUpdate.prepare(DdlWrite.Mode.APPLY, includedColumns);
updateHistoryTriggers(triggerUpdate);
// put a reverted version into the rollback buffer
update.toRevertedColumns(includedColumns);
DdlBuffer rollback = writer.rollback();
rollback.append("-- revert changes: ").append(applyChangeDescription).newLine();
triggerUpdate.prepare(DdlWrite.Mode.ROLLBACK, includedColumns);
updateHistoryTriggers(triggerUpdate);//writer, DdlWrite.Mode.ROLLBACK, baseTableName, historyTableName, includedColumns);
}
if (update.hasDropChanges()) {
// effectively applies the dropped columns changes to history triggers
DdlBuffer drop = writer.dropHistory();
drop.append("-- changes: ").append(update.descriptionForDrop()).newLine();
triggerUpdate.prepare(DdlWrite.Mode.DROP, columnNamesForDrop(table));
updateHistoryTriggers(triggerUpdate);//writer, DdlWrite.Mode.DROP, baseTableName, historyTableName, columnNamesForDrop(table));
}
}
protected DbTriggerUpdate createDbTriggerUpdate(DdlWrite writer, MTable table) {
String baseTableName = table.getName();
String historyTableName = historyTableName(baseTableName);
return new DbTriggerUpdate(baseTableName, historyTableName, writer);
}
@Override
public void dropHistoryTable(DdlWrite writer, DropHistoryTable dropHistoryTable) throws IOException {
@@ -78,7 +127,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
String baseTable = addHistoryTable.getBaseTable();
MTable table = writer.getTable(baseTable);
if (table == null) {
throw new IllegalStateException("MTable "+baseTable+" not found in writer? (required for history DDL)");
throw new IllegalStateException("MTable " + baseTable + " not found in writer? (required for history DDL)");
}
createWithHistory(writer, table);
@@ -95,7 +144,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
dropHistoryTableEtc(writer.rollback(), baseTable);
addHistoryTable(writer, table, whenCreatedColumn);
addStoredFunction(writer, table, null);
createStoredFunction(writer, table);
createTriggers(writer, table);
}
@@ -103,7 +152,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
protected abstract void dropTriggers(DdlBuffer buffer, String baseTable) throws IOException;
protected void addStoredFunction(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
protected void createStoredFunction(DdlWrite writer, MTable table) throws IOException {
// do nothing
}
@@ -158,7 +207,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
apply.append("create table ").append(table.getName()).append(historySuffix).append("(").newLine();
Collection<MColumn> cols = table.getColumns().values();
Collection<MColumn> cols = table.allColumns();
for (MColumn column : cols) {
if (!column.isDraftOnly()) {
writeColumnDefinition(apply, column.getName(), column.getType());
@@ -191,6 +240,26 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
.endOfStatement().end();
}
/**
* Create or replace the with_history view with explicit columns.
*/
protected void createWithHistoryView(DbTriggerUpdate update) throws IOException {
DdlBuffer apply = update.historyBuffer();
apply.append("create or replace view ").append(update.getBaseTable()).append(viewSuffix).append(" as select ");
appendColumnNames(apply, update.getColumns(), "");
appendSysPeriodColumns(apply, ", ");
apply.append(" from ").append(update.getBaseTable()).append(" union all select ");
appendColumnNames(apply, update.getColumns(), "");
appendSysPeriodColumns(apply, ", ");
apply.append(" from ").append(update.getHistoryTable()).endOfStatement().end();
}
protected void appendSysPeriodColumns(DdlBuffer apply, String prefix) throws IOException {
appendColumnName(apply, prefix, sysPeriodStart);
appendColumnName(apply, prefix, sysPeriodEnd);
}
protected void dropHistoryTableEtc(DdlBuffer buffer, String baseTableName) throws IOException {
buffer.append("drop view ").append(baseTableName).append(viewSuffix).endOfStatement();
@@ -203,8 +272,6 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
buffer.append("alter table ").append(baseTableName).append(" drop column ").append(sysPeriodEnd).endOfStatement();
}
//protected abstract void addFunction(DdlBuffer apply, String procedureName, String historyTable, List<String> includedColumns) throws IOException;
protected void appendInsertIntoHistory(DdlBuffer buffer, String historyTable, List<String> columns) throws IOException {
buffer.append(" insert into ").append(historyTable).append(" (").append(sysPeriodStart).append(",").append(sysPeriodEnd).append(",");
@@ -216,7 +283,7 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
protected void appendColumnNames(DdlBuffer buffer, List<String> columns, String columnPrefix) throws IOException {
for (int i=0; i< columns.size(); i++) {
for (int i = 0; i < columns.size(); i++) {
if (i > 0) {
buffer.append(", ");
}
@@ -226,18 +293,33 @@ public abstract class DbTriggerBasedHistoryDdl implements PlatformHistoryDdl {
}
/**
* Return the list of included columns in order.
* Append a single column to the buffer if it is not null.
*/
protected List<String> includedColumnNames(MTable table) throws IOException {
protected void appendColumnName(DdlBuffer buffer, String prefix, String columnName) throws IOException {
Collection<MColumn> columns = table.getColumns().values();
List<String> includedColumns = new ArrayList<String>(columns.size());
for (MColumn column : columns) {
if (column.isIncludeInHistory()) {
includedColumns.add(column.getName());
}
if (columnName != null) {
buffer.append(prefix).append(columnName);
}
return includedColumns;
}
/**
* Return the column names included in history for the apply script.
* <p>
* Note that dropped columns are actually still included at this point as they are going
* to be removed from the history handling when the drop script runs that also deletes
* the column.
* </p>
*/
protected List<String> columnNamesForApply(MTable table) throws IOException {
return table.allHistoryColumns(true);
}
/**
* Return the column names included in history for the drop script.
*/
protected List<String> columnNamesForDrop(MTable table) throws IOException {
return table.allHistoryColumns(false);
}
}
@@ -0,0 +1,72 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import java.util.List;
/**
* DB trigger update when a change occurs on a table with history.
*/
public class DbTriggerUpdate {
private final String baseTableName;
private final String historyTableName;
private final DdlWrite writer;
private DdlWrite.Mode mode;
private List<String> includedColumns;
public DbTriggerUpdate(String baseTableName, String historyTableName, DdlWrite writer) {
this.baseTableName = baseTableName;
this.historyTableName = historyTableName;
this.writer = writer;
}
/**
* Prepare for use given the mode and columns included in history.
*/
public void prepare(DdlWrite.Mode mode, List<String> includedColumns) {
this.mode = mode;
this.includedColumns = includedColumns;
}
/**
* Return the appropriate buffer for the current mode.
*/
public DdlBuffer historyBuffer() {
return writer.historyBuffer(mode);
}
/**
* Return the appropriate drop dependency buffer for the current mode.
*/
public DdlBuffer dropDependencyBuffer() {
return writer.dropDependencies(mode);
}
/**
* Return the base table name.
*/
public String getBaseTable() {
return baseTableName;
}
/**
* Return the history table name.
*/
public String getHistoryTable() {
return historyTableName;
}
/**
* Return the included columns.
*/
public List<String> getColumns() {
return includedColumns;
}
}
@@ -6,7 +6,6 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
import java.util.List;
/**
* H2 history support using DB triggers to maintain a history table.
@@ -28,40 +27,20 @@ public class H2HistoryDdl extends DbTriggerBasedHistoryDdl {
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
String baseTableName = table.getName();
String historyTableName = historyTableName(baseTableName);
List<String> includedColumns = includedColumnNames(table);
DdlBuffer apply = writer.applyHistory();
addCreateTrigger(apply, updateTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
addCreateTrigger(apply, updateTriggerName(baseTableName), baseTableName);
}
@Override
protected void regenerateHistoryTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
String baseTableName = table.getName();
String historyTableName = historyTableName(baseTableName);
List<String> includedColumns = includedColumnNames(table);
DdlBuffer apply = writer.applyHistory();
apply.append("-- Regenerated ").newLine();
apply.append("-- changes: ").append(update.description()).newLine();
dropTriggers(apply, baseTableName);
addCreateTrigger(apply, updateTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
// put a reverted version into the rollback buffer
update.toRevertedColumns(includedColumns);
DdlBuffer rollback = writer.rollback();
rollback.append("-- Revert regenerated ").newLine();
rollback.append("-- revert changes: ").append(update.description()).newLine();
dropTriggers(rollback, baseTableName);
addCreateTrigger(rollback, updateTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
DdlBuffer buffer = update.historyBuffer();
dropTriggers(buffer, update.getBaseTable());
addCreateTrigger(buffer, updateTriggerName(update.getBaseTable()), update.getBaseTable());
}
private void addCreateTrigger(DdlBuffer apply, String triggerName, String baseTable, String historyTable, List<String> includedColumns) throws IOException {
private void addCreateTrigger(DdlBuffer apply, String triggerName, String baseTable) throws IOException {
// Note that this does not take into account the historyTable name (excepts _history suffix) and
// does not take into account excluded columns (all columns included in history)
@@ -21,10 +21,12 @@ public class HistoryTableUpdate {
EXCLUDE
}
public static class Column {
private static class Column {
final Change change;
final String column;
public final Change change;
public final String column;
public Column(Change change, String column) {
this.change = change;
this.column = column;
@@ -34,18 +36,23 @@ public class HistoryTableUpdate {
return change.name().toLowerCase()+" "+column;
}
public void apply(List<String> includedColumns) {
private boolean isChangeFor(boolean apply) {
return apply ? change != Change.DROP : change == Change.DROP;
}
private void revert(List<String> includedColumns) {
switch (change) {
case ADD:
case INCLUDE: {
includedColumns.remove(column);
break;
}
case DROP:
case EXCLUDE: {
includedColumns.add(column);
break;
}
case DROP:
break;
default:
throw new IllegalStateException("Unexpected change "+change);
}
@@ -63,29 +70,73 @@ public class HistoryTableUpdate {
this.baseTable = baseTable;
}
private boolean isChangeFor(boolean apply) {
for (Column columnChange : columnChanges) {
if (columnChange.isChangeFor(apply)) {
return true;
}
}
return false;
}
/**
* Return true if the change includes apply changes (ADD, INCLUDE, EXCLUDE).
*/
public boolean hasApplyChanges() {
return isChangeFor(true);
}
/**
* Return true if the change includes DROP column.
*/
public boolean hasDropChanges() {
return isChangeFor(false);
}
/**
* Return a description of the changes that cause the history trigger/function
* to be regenerated (added, dropped, included or excluded columns).
* to be regenerated (added, included or excluded columns).
*/
public String description() {
public String descriptionForApply() {
return descriptionFor(true);
}
/**
* Return a description of the changes that cause the history trigger/function
* to be regenerated in the drop script (dropped columns only).
*/
public String descriptionForDrop() {
return descriptionFor(false);
}
private String descriptionFor(boolean apply) {
StringBuilder sb = new StringBuilder(90);
for (int i = 0; i < columnChanges.size(); i++) {
if (i > 0) {
sb.append(", ");
boolean first = true;
for (Column column : columnChanges) {
if (column.isChangeFor(apply)) {
if (first) {
first = false;
} else {
sb.append(", ");
}
sb.append(column.description());
}
sb.append(columnChanges.get(i).description());
}
return sb.toString();
}
/**
* Reverse the apply changes which equates to removing any newly added or
* included columns.
*/
public void toRevertedColumns(List<String> includedColumns) {
for (Column columnChange : columnChanges) {
columnChange.apply(includedColumns);
columnChange.revert(includedColumns);
}
}
/**
* Add a comment for column added, dropped, included or excluded.
*/
@@ -100,10 +151,4 @@ public class HistoryTableUpdate {
return baseTable;
}
/**
* Return the comments.
*/
public List<Column> getColumnChanges() {
return columnChanges;
}
}
@@ -5,7 +5,6 @@ import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.MTable;
import java.io.IOException;
import java.util.List;
/**
* MySql history support using DB triggers to maintain a history table.
@@ -26,67 +25,48 @@ public class MySqlHistoryDdl extends DbTriggerBasedHistoryDdl {
@Override
protected void createTriggers(DdlWrite writer, MTable table) throws IOException {
String baseTableName = table.getName();
String historyTableName = historyTableName(baseTableName);
List<String> includedColumns = includedColumnNames(table);
DbTriggerUpdate update = createDbTriggerUpdate(writer, table);
DdlBuffer apply = writer.applyHistory();
update.prepare(DdlWrite.Mode.APPLY, columnNamesForApply(table));
addBeforeUpdate(apply, updateTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
addBeforeDelete(apply, deleteTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
addBeforeUpdate(updateTriggerName(update.getBaseTable()), update);
addBeforeDelete(deleteTriggerName(update.getBaseTable()), update);
}
@Override
protected void regenerateHistoryTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
String baseTableName = table.getName();
String historyTableName = historyTableName(baseTableName);
List<String> includedColumns = includedColumnNames(table);
DdlBuffer buffer = update.historyBuffer();
String baseTable = update.getBaseTable();
DdlBuffer apply = writer.applyHistory();
apply.append("-- Regenerated ").newLine();
apply.append("-- changes: ").append(update.description()).newLine();
// lock the base table while we drop and recreate the triggers
apply.append("lock tables ").append(baseTableName).append(" write").endOfStatement();
dropTriggers(apply, baseTableName);
addBeforeUpdate(apply, updateTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
addBeforeDelete(apply, deleteTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
apply.append("unlock tables").endOfStatement();
// put a reverted version into the rollback buffer
update.toRevertedColumns(includedColumns);
DdlBuffer rollback = writer.rollback();
rollback.append("-- Revert regenerated ").newLine();
rollback.append("-- revert changes: ").append(update.description()).newLine();
// lock the base table while we drop and recreate the triggers
rollback.append("lock tables ").append(baseTableName).append(" write").endOfStatement();
dropTriggers(rollback, baseTableName);
addBeforeUpdate(rollback, updateTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
addBeforeDelete(rollback, deleteTriggerName(baseTableName), baseTableName, historyTableName, includedColumns);
rollback.append("unlock tables").endOfStatement();
buffer.append("lock tables ").append(baseTable).append(" write").endOfStatement();
dropTriggers(buffer, baseTable);
addBeforeUpdate(updateTriggerName(baseTable), update);
addBeforeDelete(deleteTriggerName(baseTable), update);
buffer.append("unlock tables").endOfStatement();
}
private void addBeforeUpdate(DdlBuffer apply, String triggerName, String baseTable, String historyTable, List<String> includedColumns) throws IOException {
private void addBeforeUpdate(String triggerName, DbTriggerUpdate update) throws IOException {
DdlBuffer apply = update.historyBuffer();
apply
.append("delimiter $$").newLine()
.append("create trigger ").append(triggerName).append(" before update on ").append(baseTable)
.append("create trigger ").append(triggerName).append(" before update on ").append(update.getBaseTable())
.append(" for each row begin").newLine();
appendInsertIntoHistory(apply, historyTable, includedColumns);
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
apply
.append(" set NEW.").append(sysPeriod).append("_start = now(6)").endOfStatement()
.append("end$$").newLine();
}
private void addBeforeDelete(DdlBuffer apply, String triggerName, String baseTable, String historyTable, List<String> includedColumns) throws IOException {
private void addBeforeDelete(String triggerName, DbTriggerUpdate update) throws IOException {
DdlBuffer apply = update.historyBuffer();
apply
.append("delimiter $$").newLine()
.append("create trigger ").append(triggerName).append(" before delete on ").append(baseTable)
.append("create trigger ").append(triggerName).append(" before delete on ").append(update.getBaseTable())
.append(" for each row begin").newLine();
appendInsertIntoHistory(apply, historyTable, includedColumns);
appendInsertIntoHistory(apply, update.getHistoryTable(), update.getColumns());
apply.append("end$$").newLine();
}
@@ -35,7 +35,7 @@ public class NoHistorySupportDdl implements PlatformHistoryDdl {
}
@Override
public void regenerateHistoryTriggers(DdlWrite write, HistoryTableUpdate update) {
public void updateTriggers(DdlWrite write, HistoryTableUpdate update) {
// does nothing
}
}
@@ -200,7 +200,7 @@ public class PlatformDdl {
* Regenerate the history triggers (or function) due to a column being added/dropped/excluded or included.
*/
public void regenerateHistoryTriggers(DdlWrite write, HistoryTableUpdate update) throws IOException {
historyDdl.regenerateHistoryTriggers(write, update);
historyDdl.updateTriggers(write, update);
}
/**
@@ -36,5 +36,5 @@ public interface PlatformHistoryDdl {
/**
* Regenerate the history triggers/stored function due to column added/dropped/included or excluded.
*/
void regenerateHistoryTriggers(DdlWrite write, HistoryTableUpdate baseTable) throws IOException;
void updateTriggers(DdlWrite write, HistoryTableUpdate baseTable) throws IOException;
}
@@ -45,6 +45,11 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
}
}
@Override
protected void appendSysPeriodColumns(DdlBuffer apply, String prefix) throws IOException {
appendColumnName(apply, prefix, sysPeriod);
}
@Override
protected void dropSysPeriodColumns(DdlBuffer buffer, String baseTableName) throws IOException {
buffer.append("alter table ").append(baseTableName).append(" drop column ").append(sysPeriod).endOfStatement();
@@ -72,7 +77,7 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
buffer.end();
}
protected void addFunction(DdlBuffer apply, String procedureName, String historyTable, List<String> includedColumns) throws IOException {
protected void createOrReplaceFunction(DdlBuffer apply, String procedureName, String historyTable, List<String> includedColumns) throws IOException {
apply
.append("create or replace function ").append(procedureName).append("() returns trigger as $$").newLine()
.append("begin").newLine();
@@ -96,40 +101,36 @@ public class PostgresHistoryDdl extends DbTriggerBasedHistoryDdl {
}
@Override
protected void regenerateHistoryTriggers(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
// just replace the stored function with 'create or replace'
addStoredFunction(writer, table, update);
}
@Override
protected void addStoredFunction(DdlWrite writer, MTable table, HistoryTableUpdate update) throws IOException {
protected void createStoredFunction(DdlWrite writer, MTable table) throws IOException {
String procedureName = procedureName(table.getName());
String historyTable = historyTableName(table.getName());
List<String> includedColumns = includedColumnNames(table);
List<String> columnNames = columnNamesForApply(table);
createOrReplaceFunction(writer.applyHistory(), procedureName, historyTable, columnNames);
}
DdlBuffer apply = writer.applyHistory();
@Override
protected void updateHistoryTriggers(DbTriggerUpdate update) throws IOException {
if (update != null) {
apply.append("-- Regenerated ").append(procedureName).newLine();
apply.append("-- changes: ").append(update.description()).newLine();
}
String procedureName = procedureName(update.getBaseTable());
addFunction(apply, procedureName, historyTable, includedColumns);
recreateHistoryView(update);
createOrReplaceFunction(update.historyBuffer(), procedureName, update.getHistoryTable(), update.getColumns());
}
/**
* For postgres we need to drop and recreate the view. Well, we could add columns to the end of the view
* but otherwise we need to drop and create it.
*/
private void recreateHistoryView(DbTriggerUpdate update) throws IOException {
if (update != null) {
// put a reverted version into the rollback buffer
update.toRevertedColumns(includedColumns);
DdlBuffer buffer = update.dropDependencyBuffer();
// we need to drop the view early/first before any changes to the tables etc
buffer.append("drop view if exists ").append(update.getBaseTable()).append(viewSuffix).endOfStatement();
DdlBuffer rollback = writer.rollback();
rollback.append("-- Revert regenerated ").append(procedureName).newLine();
rollback.append("-- revert changes: ").append(update.description()).newLine();
addFunction(rollback, procedureName, historyTable, includedColumns);
}
// recreate the view with specific columns specified (the columns generally are not dropped until later)
createWithHistoryView(update);
}
@Override
@@ -30,6 +30,7 @@ import javax.xml.bind.annotation.XmlType;
* &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;attribute name="draft" type="{http://www.w3.org/2001/XMLSchema}boolean" />
* &lt;attribute name="identityType" type="{http://ebean-orm.github.io/xml/ns/dbmigration}identityType" />
* &lt;attribute name="sequenceName" type="{http://www.w3.org/2001/XMLSchema}string" />
* &lt;attribute name="sequenceInitial" type="{http://www.w3.org/2001/XMLSchema}positiveInteger" />
@@ -59,6 +60,8 @@ public class CreateTable {
protected String name;
@XmlAttribute(name = "withHistory")
protected Boolean withHistory;
@XmlAttribute(name = "draft")
protected Boolean draft;
@XmlAttribute(name = "identityType")
protected IdentityType identityType;
@XmlAttribute(name = "sequenceName")
@@ -213,6 +216,30 @@ public class CreateTable {
this.withHistory = value;
}
/**
* Gets the value of the draft property.
*
* @return
* possible object is
* {@link Boolean }
*
*/
public Boolean isDraft() {
return draft;
}
/**
* Sets the value of the draft property.
*
* @param value
* allowed object is
* {@link Boolean }
*
*/
public void setDraft(Boolean value) {
this.draft = value;
}
/**
* Gets the value of the identityType property.
*
@@ -283,7 +283,6 @@ public class MColumn {
/**
* Compare the column meta data and return true if there is a change that means
* the history table column needs
*/
public void compare(ModelDiff modelDiff, MTable table, MColumn newColumn) {
@@ -10,13 +10,15 @@ import com.avaje.ebean.dbmigration.migration.DropHistoryTable;
import com.avaje.ebean.dbmigration.migration.DropTable;
import com.avaje.ebean.dbmigration.migration.IdentityType;
import com.avaje.ebean.dbmigration.migration.UniqueConstraint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -38,6 +40,8 @@ import java.util.Set;
*/
public class MTable {
private static final Logger logger = LoggerFactory.getLogger(MTable.class);
/**
* Table name.
*/
@@ -118,6 +122,8 @@ public class MTable {
*/
private AddColumn addColumn;
private List<DroppedColumn> droppedColumns = new ArrayList<DroppedColumn>();
/**
* Create a copy of this table structure as a 'draft' table.
*
@@ -133,7 +139,7 @@ public class MTable {
// compoundUniqueConstraints
draftTable.identityType = identityType;
for (MColumn col: columns.values()) {
for (MColumn col: allColumns()) {
draftTable.addColumn(col.copyForDraft());
}
@@ -150,6 +156,7 @@ public class MTable {
this.tablespace = createTable.getTablespace();
this.indexTablespace = createTable.getIndexTablespace();
this.withHistory = Boolean.TRUE.equals(createTable.isWithHistory());
this.draft = Boolean.TRUE.equals(createTable.isDraft());
this.sequenceName = createTable.getSequenceName();
this.sequenceInitial = toInt(createTable.getSequenceInitial());
this.sequenceAllocate = toInt(createTable.getSequenceAllocate());
@@ -194,8 +201,11 @@ public class MTable {
if (withHistory) {
createTable.setWithHistory(Boolean.TRUE);
}
if (draft) {
createTable.setDraft(Boolean.TRUE);
}
for (MColumn column : this.columns.values()) {
for (MColumn column : allColumns()) {
// filter out draftOnly columns from the base table
if (draft || !column.isDraftOnly()) {
createTable.getColumn().add(column.createColumn());
@@ -244,26 +254,33 @@ public class MTable {
addColumn = null;
Set<String> mappedColumns = new LinkedHashSet<String>();
Map<String, MColumn> newColumnMap = newTable.getColumns();
Collection<MColumn> newColumns = newTable.getColumns().values();
for (MColumn newColumn : newColumns) {
MColumn localColumn = columns.get(newColumn.getName());
// compare newColumns to existing columns (look for new and diff columns)
for (MColumn newColumn : newColumnMap.values()) {
MColumn localColumn = getColumn(newColumn.getName());
if (localColumn == null) {
diffNewColumn(newColumn);
// can ignore if draftOnly column and non-draft table
if (!newColumn.isDraftOnly() || draft) {
diffNewColumn(newColumn);
}
} else {
// note that if there are alter column changes in here then
// the table withHistory is taken into account
localColumn.compare(modelDiff, this, newColumn);
mappedColumns.add(newColumn.getName());
}
}
Collection<MColumn> existingColumns = columns.values();
for (MColumn existingColumn : existingColumns) {
if (!mappedColumns.contains(existingColumn.getName())) {
diffDropColumn(modelDiff, existingColumn);
// compare existing columns (look for dropped columns)
int columnPosition = 0;
for (MColumn existingColumn : allColumns()) {
MColumn newColumn = newColumnMap.get(existingColumn.getName());
if (newColumn == null) {
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
} else if (newColumn.isDraftOnly() && !draft) {
// effectively a drop column (draft only column on a non-draft table)
logger.trace("... drop column {} from table {} as now draftOnly", newColumn.getName(), name);
diffDropColumn(modelDiff, existingColumn, columnPosition, newTable);
}
columnPosition++;
}
if (addColumn != null) {
@@ -287,7 +304,7 @@ public class MTable {
public void apply(AlterColumn alterColumn) {
checkTableName(alterColumn.getTableName());
String columnName = alterColumn.getColumnName();
MColumn existingColumn = columns.get(columnName);
MColumn existingColumn = getColumn(columnName);
if (existingColumn == null) {
throw new IllegalStateException("Column [" + columnName + "] does not exist for AlterColumn change?");
}
@@ -299,7 +316,10 @@ public class MTable {
*/
public void apply(DropColumn dropColumn) {
checkTableName(dropColumn.getTableName());
columns.remove(dropColumn.getColumnName());
MColumn removed = columns.remove(dropColumn.getColumnName());
if (removed == null) {
throw new IllegalStateException("Column [" + dropColumn.getColumnName() + "] does not exist for DropColumn change on table [" + dropColumn.getTableName() + "]?");
}
}
public String getName() {
@@ -313,10 +333,6 @@ public class MTable {
return draft;
}
public String getPkName() {
return pkName;
}
public void setPkName(String pkName) {
this.pkName = pkName;
}
@@ -345,7 +361,43 @@ public class MTable {
this.withHistory = withHistory;
}
public Map<String, MColumn> getColumns() {
public List<String> allHistoryColumns(boolean includeDropped) {
List<String> columnNames = new ArrayList<String>(columns.size());
for (MColumn column : columns.values()) {
if (column.isIncludeInHistory()) {
columnNames.add(column.getName());
}
}
if (includeDropped && !droppedColumns.isEmpty()) {
Collections.sort(droppedColumns);
for (DroppedColumn droppedColumn : droppedColumns) {
if (droppedColumn.columnPosition >= columnNames.size()) {
columnNames.add(droppedColumn.name);
} else {
columnNames.add(droppedColumn.columnPosition, droppedColumn.name);
}
}
}
return columnNames;
}
/**
* Return all the columns (excluding columns marked as dropped).
*/
public Collection<MColumn> allColumns() {
return columns.values();
}
/**
* Return the column by name.
*/
public MColumn getColumn(String name) {
return columns.get(name);
}
private Map<String, MColumn> getColumns() {
return columns;
}
@@ -357,26 +409,14 @@ public class MTable {
return compoundKeys;
}
public String getSequenceName() {
return sequenceName;
}
public void setSequenceName(String sequenceName) {
this.sequenceName = sequenceName;
}
public int getSequenceInitial() {
return sequenceInitial;
}
public void setSequenceInitial(int sequenceInitial) {
this.sequenceInitial = sequenceInitial;
}
public int getSequenceAllocate() {
return sequenceAllocate;
}
public void setSequenceAllocate(int sequenceAllocate) {
this.sequenceAllocate = sequenceAllocate;
}
@@ -399,22 +439,12 @@ public class MTable {
this.identityType = identityType;
}
/**
* Returns the identity type to use for this table.
* <p>
* If set then this overrides the platform default so for UUID generated values
* or DB's supporting both sequences and autoincrement.
*/
public IdentityType getIdentityType() {
return identityType;
}
/**
* Return the list of columns that make the primary key.
*/
public List<MColumn> primaryKeyColumns() {
List<MColumn> pk = new ArrayList<MColumn>(3);
for (MColumn column : columns.values()) {
for (MColumn column : allColumns()) {
if (column.isPrimaryKey()) {
pk.add(column);
}
@@ -473,7 +503,7 @@ public class MTable {
*/
public MColumn addColumn(String dbCol, String columnDefn, boolean notnull) {
MColumn existingColumn = columns.get(dbCol);
MColumn existingColumn = getColumn(dbCol);
if (existingColumn != null) {
if (notnull) {
existingColumn.setNotnull(true);
@@ -507,20 +537,46 @@ public class MTable {
/**
* Add a 'drop column' to the diff.
*/
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn) {
private void diffDropColumn(ModelDiff modelDiff, MColumn existingColumn, int columnPosition, MTable newTable) {
DropColumn dropColumn = new DropColumn();
dropColumn.setTableName(name);
dropColumn.setColumnName(existingColumn.getName());
if (withHistory) {
if (withHistory && !existingColumn.isHistoryExclude()) {
// These dropColumns should occur on the history
// table as well as the base table
dropColumn.setWithHistory(Boolean.TRUE);
newTable.registerDroppedColumn(existingColumn.getName(), columnPosition);
}
modelDiff.addDropColumn(dropColumn);
}
/**
* Register a dropped column with it's previous column position.
* We need this for history triggers and views as we don't actually drop the
* column until the 'drop script' is run so the 'apply script' for history changes
* still needs to include the columns that are going to be dropped.
*/
protected void registerDroppedColumn(String name, int columnPosition) {
droppedColumns.add(new DroppedColumn(name, columnPosition));
}
private static class DroppedColumn implements Comparable<DroppedColumn> {
final String name;
final int columnPosition;
DroppedColumn(String name, int columnPosition) {
this.name = name;
this.columnPosition = columnPosition;
}
@Override
public int compareTo(DroppedColumn o) {
return Integer.compare(o.columnPosition, columnPosition);
}
}
private int toInt(BigInteger value) {
return (value == null) ? 0 : value.intValue();
}
@@ -563,7 +619,7 @@ public class MTable {
*/
public void adjustReferences(ModelContainer modelContainer) {
Collection<MColumn> cols = columns.values();
Collection<MColumn> cols = allColumns();
for (MColumn col : cols) {
String references = col.getReferences();
if (references != null) {
@@ -3,6 +3,7 @@ package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.config.DbMigrationConfig;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebean.config.dbplatform.DatabasePlatform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlBuffer;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlHandler;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.migration.ChangeSet;
@@ -116,6 +117,8 @@ public class PlatformDdlWriter {
protected void writeApplyDdl(Writer writer, DdlWrite write) throws IOException {
// merge the apply buffers in the appropriate order
prependDropDependencies(writer, write.applyDropDependencies());
writer.append("-- apply changes\n");
writer.append(write.apply().getBuffer());
writer.append(write.applyForeignKeys().getBuffer());
writer.append(write.applyHistory().getBuffer());
@@ -127,6 +130,8 @@ public class PlatformDdlWriter {
protected void writeApplyRollbackDdl(Writer writer, DdlWrite write) throws IOException {
// merge the rollback buffers in the appropriate order
prependDropDependencies(writer, write.rollbackDropDependencies());
writer.append("-- reverse changes\n");
writer.append(write.rollbackForeignKeys().getBuffer());
writer.append(write.rollback().getBuffer());
}
@@ -137,10 +142,19 @@ public class PlatformDdlWriter {
protected void writeDropDdl(Writer writer, DdlWrite write) throws IOException {
// merge the rollback buffers in the appropriate order
prependDropDependencies(writer, write.dropDropDependencies());
writer.append(write.dropHistory().getBuffer());
writer.append(write.drop().getBuffer());
}
private void prependDropDependencies(Writer writer, DdlBuffer buffer) throws IOException {
if (!buffer.isEmpty()) {
writer.append("-- drop dependencies\n");
writer.append(buffer.getBuffer());
writer.append("\n");
}
}
/**
* Return the platform specific DdlHandler (to generate DDL).
*/
@@ -158,7 +158,7 @@ public class ModelBuildContext {
int fkCount = 0;
int ixCount = 0;
int uqCount = 0;
Collection<MColumn> cols = draftTable.getColumns().values();
Collection<MColumn> cols = draftTable.allColumns();
for (MColumn col: cols) {
if (col.getForeignKeyName() != null) {
// Note that we adjust the 'references' table later in a second pass
@@ -84,7 +84,7 @@ public class ModelBuildPropertyVisitor extends BaseTablePropertyVisitor {
table.setPkName(determinePrimaryKeyName());
// check if indexes on foreign keys should be suppressed
for (MColumn column : table.getColumns().values()) {
for (MColumn column : table.allColumns()) {
if (hasValue(column.getForeignKeyIndex())) {
if (indexSet.contains(column.getName())) {
// suppress index on foreign key as there is already
@@ -1,13 +1,12 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import javax.persistence.PersistenceException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Types;
import javax.persistence.PersistenceException;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
/**
* Creates "Counter" GeneratedProperty for various types of number.
* <p>
@@ -16,49 +15,49 @@ import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
*/
public class CounterFactory {
final GeneratedCounterInteger integerCounter = new GeneratedCounterInteger();
final GeneratedCounterInteger integerCounter = new GeneratedCounterInteger();
final GeneratedCounterLong longCounter = new GeneratedCounterLong();
final GeneratedCounterLong longCounter = new GeneratedCounterLong();
public void setCounter(DeployBeanProperty property) {
public void setCounter(DeployBeanProperty property) {
property.setGeneratedProperty(createCounter(property));
}
/**
* Create the GeneratedProperty based on the property type.
*/
private GeneratedProperty createCounter(DeployBeanProperty property) {
Class<?> propType = property.getPropertyType();
if (propType.equals(Integer.class) || propType.equals(int.class)) {
return integerCounter;
}
if (propType.equals(Long.class) || propType.equals(long.class)) {
return longCounter;
}
int type = getType(propType);
return new GeneratedCounter(type);
}
private int getType(Class<?> propType){
if (propType.equals(Short.class) || propType.equals(short.class)){
return Types.TINYINT;
}
if (propType.equals(BigDecimal.class)){
return Types.DECIMAL;
}
if (propType.equals(Double.class) || propType.equals(double.class)){
return Types.DOUBLE;
}
if (propType.equals(Float.class) || propType.equals(float.class)){
return Types.REAL;
}
if (propType.equals(BigInteger.class)){
return Types.BIGINT;
}
String msg = "Can not support Counter for type "+propType.getName();
throw new PersistenceException(msg);
}
property.setGeneratedProperty(createCounter(property));
}
/**
* Create the GeneratedProperty based on the property type.
*/
private GeneratedProperty createCounter(DeployBeanProperty property) {
Class<?> propType = property.getPropertyType();
if (propType.equals(Integer.class) || propType.equals(int.class)) {
return integerCounter;
}
if (propType.equals(Long.class) || propType.equals(long.class)) {
return longCounter;
}
int type = getType(propType);
return new GeneratedCounter(type);
}
private int getType(Class<?> propType) {
if (propType.equals(Short.class) || propType.equals(short.class)) {
return Types.TINYINT;
}
if (propType.equals(BigDecimal.class)) {
return Types.DECIMAL;
}
if (propType.equals(Double.class) || propType.equals(double.class)) {
return Types.DOUBLE;
}
if (propType.equals(Float.class) || propType.equals(float.class)) {
return Types.REAL;
}
if (propType.equals(BigInteger.class)) {
return Types.BIGINT;
}
String msg = "Can not support Counter for type " + propType.getName();
throw new PersistenceException(msg);
}
}
@@ -9,49 +9,51 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
*/
public class GeneratedCounter implements GeneratedProperty {
final int numberType;
final int numberType;
public GeneratedCounter(int numberType) {
this.numberType = numberType;
}
public GeneratedCounter(int numberType) {
this.numberType = numberType;
}
/**
* Always returns a 1.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return BasicTypeConverter.convert(1, numberType);
}
/**
* Always returns a 1.
*/
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return BasicTypeConverter.convert(1, numberType);
}
/**
* Increments the current value by one.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
Number currVal = (Number) prop.getValue(bean);
Integer nextVal = currVal.intValue() + 1;
return BasicTypeConverter.convert(nextVal, numberType);
}
/**
* Increments the current value by one.
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Number currVal = (Number) prop.getValue(bean);
Integer nextVal = currVal.intValue() + 1;
return BasicTypeConverter.convert(nextVal, numberType);
}
/**
* Include this in every update.
*/
public boolean includeInUpdate() {
return true;
}
/**
* Include this in every update.
*/
public boolean includeInUpdate() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
/**
* Include this in every insert setting initial counter value to 1.
*/
public boolean includeInInsert() {
return true;
}
/**
* Include this in every insert setting initial counter value to 1.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -8,46 +8,48 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
*/
public class GeneratedCounterInteger implements GeneratedProperty {
public GeneratedCounterInteger() {
public GeneratedCounterInteger() {
}
}
/**
* Always returns a 1.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return 1;
}
/**
* Always returns a 1.
*/
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return 1;
}
/**
* Increments the current value by one.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
Integer i = (Integer) prop.getValue(bean);
return i + 1;
}
/**
* Increments the current value by one.
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Integer i = (Integer) prop.getValue(bean);
return i + 1;
}
/**
* Include this in every update.
*/
public boolean includeInUpdate() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
/**
* Include this in every update.
*/
public boolean includeInUpdate() {
return true;
}
/**
* Include this in every insert setting initial counter value to 1.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Include this in every insert setting initial counter value to 1.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -8,46 +8,48 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
*/
public class GeneratedCounterLong implements GeneratedProperty {
public GeneratedCounterLong() {
public GeneratedCounterLong() {
}
}
/**
* Always returns a 1.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return (long) 1;
}
/**
* Always returns a 1.
*/
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return (long) 1;
}
/**
* Increments the current value by one.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
Long i = (Long) prop.getValue(bean);
return i + 1;
}
/**
* Increments the current value by one.
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
Long i = (Long) prop.getValue(bean);
return i + 1;
}
/**
* Include this in every update.
*/
public boolean includeInUpdate() {
return true;
}
/**
* Include this in every update.
*/
public boolean includeInUpdate() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
/**
* Include this in every insert setting initial counter value to 1.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Include this in every insert setting initial counter value to 1.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -1,50 +1,52 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.util.Date;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import java.util.Date;
/**
* Used to generate a (java.util.Date) timestamp when a bean is inserted.
*/
public class GeneratedInsertDate implements GeneratedProperty {
/**
* Return the current time as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new Date(System.currentTimeMillis());
}
/**
* Return the current time as a Timestamp.
*/
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new Date(now);
}
/**
* Just returns the beans original insert timestamp value.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return prop.getValue(bean);
}
/**
* Just returns the beans original insert timestamp value.
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return prop.getValue(bean);
}
/**
* Return false.
*/
public boolean includeInUpdate() {
return false;
}
/**
* Return false.
*/
public boolean includeInUpdate() {
return false;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
/**
* Return true.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Return true.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -3,10 +3,6 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
/**
* Support java.time types as GeneratedProperty.
*/
@@ -35,7 +31,7 @@ public class GeneratedInsertJavaTime {
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return prop.getValue(bean);
}
}
@@ -46,8 +42,8 @@ public class GeneratedInsertJavaTime {
public static class LocalDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return LocalDateTime.now();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toLocalDateTime(now);
}
}
@@ -57,8 +53,8 @@ public class GeneratedInsertJavaTime {
public static class OffsetDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return OffsetDateTime.now();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toOffsetDateTime(now);
}
}
@@ -69,8 +65,8 @@ public class GeneratedInsertJavaTime {
public static class ZonedDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return ZonedDateTime.now();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toZonedDateTime(now);
}
}
@@ -2,9 +2,8 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import org.joda.time.LocalDateTime;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
/**
* Support joda time types as GeneratedProperty.
@@ -34,7 +33,7 @@ public class GeneratedInsertJodaTime {
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return prop.getValue(bean);
}
}
@@ -45,8 +44,8 @@ public class GeneratedInsertJodaTime {
public static class LocalDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new LocalDateTime();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new LocalDateTime(now);
}
}
@@ -56,8 +55,8 @@ public class GeneratedInsertJodaTime {
public static class DateTimeDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new DateTime();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new DateTime(now);
}
}
@@ -8,41 +8,43 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
*/
public class GeneratedInsertLong implements GeneratedProperty {
/**
* Return the current time as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return System.currentTimeMillis();
}
/**
* Return the current time as a Timestamp.
*/
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return now;
}
/**
* Just returns the beans original insert timestamp value.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return prop.getValue(bean);
}
/**
* Just returns the beans original insert timestamp value.
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return prop.getValue(bean);
}
/**
* Return false.
*/
public boolean includeInUpdate() {
return false;
}
/**
* Return false.
*/
public boolean includeInUpdate() {
return false;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
/**
* Return true.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Return true.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -1,50 +1,52 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.sql.Timestamp;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import java.sql.Timestamp;
/**
* Used to generate a timestamp when a bean is inserted.
*/
public class GeneratedInsertTimestamp implements GeneratedProperty, GeneratedWhenCreated {
/**
* Return the current time as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new Timestamp(System.currentTimeMillis());
}
/**
* Return the current time as a Timestamp.
*/
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new Timestamp(now);
}
/**
* Just returns the beans original insert timestamp value.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return prop.getValue(bean);
}
/**
* Just returns the beans original insert timestamp value.
*/
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return prop.getValue(bean);
}
/**
* Return false.
*/
public boolean includeInUpdate() {
return false;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
/**
* Return false.
*/
public boolean includeInUpdate() {
return false;
}
/**
* Return true.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return false;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Return true.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -9,39 +9,39 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
*/
public interface GeneratedProperty {
/**
* Get the generated insert value for a specific property of a bean.
*/
Object getInsertValue(BeanProperty prop, EntityBean bean);
/**
* Get the generated insert value for a specific property of a bean.
*/
Object getInsertValue(BeanProperty prop, EntityBean bean, long now);
/**
* Get the generated update value for a specific property of a bean.
*/
Object getUpdateValue(BeanProperty prop, EntityBean bean);
/**
* Get the generated update value for a specific property of a bean.
*/
Object getUpdateValue(BeanProperty prop, EntityBean bean, long now);
/**
* Return true if this should always be includes in an update statement.
* <p>
* Used to include GeneratedUpdateTimestamp in dynamic table updates.
* </p>
*/
boolean includeInUpdate();
/**
* Return true if the property should be included in an update even if
* it is not loaded (ie. Last Updated Timestamp).
*/
boolean includeInAllUpdates();
/**
* Return true if this should always be includes in an update statement.
* <p>
* Used to include GeneratedUpdateTimestamp in dynamic table updates.
* </p>
*/
boolean includeInUpdate();
/**
* Return true if this should be included in insert statements.
*/
boolean includeInInsert();
/**
* Return true if the property should be included in an update even if
* it is not loaded (ie. Last Updated Timestamp).
*/
boolean includeInAllUpdates();
/**
* Return true if the GeneratedProperty implies the DDL to create the DB
* column should have a not null constraint.
*/
boolean isDDLNotNullable();
/**
* Return true if this should be included in insert statements.
*/
boolean includeInInsert();
/**
* Return true if the GeneratedProperty implies the DDL to create the DB
* column should have a not null constraint.
*/
boolean isDDLNotNullable();
}
@@ -1,19 +1,19 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.math.BigDecimal;
import java.util.HashSet;
import com.avaje.ebean.config.ClassLoadConfig;
import com.avaje.ebean.config.CurrentUserProvider;
import com.avaje.ebean.config.ServerConfig;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import java.math.BigDecimal;
import java.util.HashSet;
/**
* Default implementation of GeneratedPropertyFactory.
*/
public class GeneratedPropertyFactory {
private final CounterFactory counterFactory = new CounterFactory();
private final CounterFactory counterFactory = new CounterFactory();
private final InsertTimestampFactory insertFactory;
@@ -34,7 +34,7 @@ public class GeneratedPropertyFactory {
this.updateFactory = new UpdateTimestampFactory(classLoadConfig);
CurrentUserProvider currentUserProvider = serverConfig.getCurrentUserProvider();
if (currentUserProvider != null) {
if (currentUserProvider != null) {
generatedWhoCreated = new GeneratedWhoCreated(currentUserProvider);
generatedWhoModified = new GeneratedWhoModified(currentUserProvider);
} else {
@@ -42,47 +42,47 @@ public class GeneratedPropertyFactory {
generatedWhoModified = null;
}
numberTypes.add(Integer.class.getName());
numberTypes.add(int.class.getName());
numberTypes.add(Long.class.getName());
numberTypes.add(long.class.getName());
numberTypes.add(Short.class.getName());
numberTypes.add(short.class.getName());
numberTypes.add(Double.class.getName());
numberTypes.add(double.class.getName());
numberTypes.add(BigDecimal.class.getName());
}
numberTypes.add(Integer.class.getName());
numberTypes.add(int.class.getName());
numberTypes.add(Long.class.getName());
numberTypes.add(long.class.getName());
numberTypes.add(Short.class.getName());
numberTypes.add(short.class.getName());
numberTypes.add(Double.class.getName());
numberTypes.add(double.class.getName());
numberTypes.add(BigDecimal.class.getName());
}
public ClassLoadConfig getClassLoadConfig() {
return classLoadConfig;
}
private boolean isNumberType(String typeClassName) {
return numberTypes.contains(typeClassName);
}
public void setVersion(DeployBeanProperty property) {
if (isNumberType(property.getPropertyType().getName())) {
setCounter(property);
} else {
setUpdateTimestamp(property);
}
}
public void setCounter(DeployBeanProperty property) {
counterFactory.setCounter(property);
}
return numberTypes.contains(typeClassName);
}
public void setInsertTimestamp(DeployBeanProperty property) {
insertFactory.setInsertTimestamp(property);
}
public void setVersion(DeployBeanProperty property) {
if (isNumberType(property.getPropertyType().getName())) {
setCounter(property);
} else {
setUpdateTimestamp(property);
}
}
public void setUpdateTimestamp(DeployBeanProperty property) {
updateFactory.setUpdateTimestamp(property);
}
public void setCounter(DeployBeanProperty property) {
counterFactory.setCounter(property);
}
public void setInsertTimestamp(DeployBeanProperty property) {
insertFactory.setInsertTimestamp(property);
}
public void setUpdateTimestamp(DeployBeanProperty property) {
updateFactory.setUpdateTimestamp(property);
}
public void setWhoCreated(DeployBeanProperty property) {
if (generatedWhoCreated == null) {
@@ -1,51 +1,51 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.util.Date;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import java.util.Date;
/**
* Generate a (java.util.Date) Timestamp whenever the bean is inserted or
* updated.
*/
public class GeneratedUpdateDate implements GeneratedProperty {
/**
* Return now as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new Date(System.currentTimeMillis());
}
/**
* Return now as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new Date(now);
}
/**
* Return now as a Timestamp.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return new Date(System.currentTimeMillis());
}
/**
* Return now as a Timestamp.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return new Date(now);
}
/**
* For dynamic table updates make sure this is included.
*/
public boolean includeInUpdate() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return true;
}
/**
* For dynamic table updates make sure this is included.
*/
public boolean includeInUpdate() {
return true;
}
/**
* Include this in every insert.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Include this in every insert.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -3,10 +3,6 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
/**
* Support java.time DateTime types as GeneratedProperty.
*/
@@ -41,13 +37,13 @@ public class GeneratedUpdateJavaTime {
public static class LocalDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return LocalDateTime.now();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toLocalDateTime(now);
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return LocalDateTime.now();
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toLocalDateTime(now);
}
}
@@ -57,13 +53,13 @@ public class GeneratedUpdateJavaTime {
public static class OffsetDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return OffsetDateTime.now();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toOffsetDateTime(now);
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return OffsetDateTime.now();
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toOffsetDateTime(now);
}
}
@@ -73,13 +69,13 @@ public class GeneratedUpdateJavaTime {
public static class ZonedDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return ZonedDateTime.now();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toZonedDateTime(now);
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return ZonedDateTime.now();
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return JavaTimeUtils.toZonedDateTime(now);
}
}
@@ -2,9 +2,8 @@ package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import org.joda.time.LocalDateTime;
import org.joda.time.DateTime;
import org.joda.time.LocalDateTime;
/**
* Support java.time DateTime types as GeneratedProperty.
@@ -40,13 +39,13 @@ public class GeneratedUpdateJodaTime {
public static class LocalDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new LocalDateTime();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new LocalDateTime(now);
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return new LocalDateTime();
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return new LocalDateTime(now);
}
}
@@ -56,13 +55,13 @@ public class GeneratedUpdateJodaTime {
public static class DateTimeDT extends Base {
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new DateTime();
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new DateTime(now);
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return new DateTime();
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return new DateTime(now);
}
}
@@ -8,41 +8,41 @@ import com.avaje.ebeaninternal.server.deploy.BeanProperty;
*/
public class GeneratedUpdateLong implements GeneratedProperty {
/**
* Return now as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return System.currentTimeMillis();
}
/**
* Return now as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return now;
}
/**
* Return now as a Timestamp.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return System.currentTimeMillis();
}
/**
* Return now as a Timestamp.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return now;
}
/**
* For dynamic table updates make sure this is included.
*/
public boolean includeInUpdate() {
return true;
}
/**
* For dynamic table updates make sure this is included.
*/
public boolean includeInUpdate() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return true;
}
/**
* Include this in every insert.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Include this in every insert.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -1,50 +1,50 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.sql.Timestamp;
import com.avaje.ebean.bean.EntityBean;
import com.avaje.ebeaninternal.server.deploy.BeanProperty;
import java.sql.Timestamp;
/**
* Generate a Timestamp whenever the bean is inserted or updated.
*/
public class GeneratedUpdateTimestamp implements GeneratedProperty, GeneratedWhenModified {
/**
* Return now as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
return new Timestamp(System.currentTimeMillis());
}
/**
* Return now as a Timestamp.
*/
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return new Timestamp(now);
}
/**
* Return now as a Timestamp.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
return new Timestamp(System.currentTimeMillis());
}
/**
* Return now as a Timestamp.
*/
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return new Timestamp(now);
}
/**
* For dynamic table updates make sure this is included.
*/
public boolean includeInUpdate() {
return true;
}
/**
* For dynamic table updates make sure this is included.
*/
public boolean includeInUpdate() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return true;
}
/**
* Include this in every insert.
*/
public boolean includeInInsert() {
return true;
}
@Override
public boolean includeInAllUpdates() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
/**
* Include this in every insert.
*/
public boolean includeInInsert() {
return true;
}
public boolean isDDLNotNullable() {
return true;
}
}
@@ -16,12 +16,12 @@ public class GeneratedWhoCreated implements GeneratedProperty {
}
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return currentUserProvider.currentUser();
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return null;
}
@@ -16,12 +16,12 @@ public class GeneratedWhoModified implements GeneratedProperty {
}
@Override
public Object getInsertValue(BeanProperty prop, EntityBean bean) {
public Object getInsertValue(BeanProperty prop, EntityBean bean, long now) {
return currentUserProvider.currentUser();
}
@Override
public Object getUpdateValue(BeanProperty prop, EntityBean bean) {
public Object getUpdateValue(BeanProperty prop, EntityBean bean, long now) {
return currentUserProvider.currentUser();
}
@@ -1,5 +1,9 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebean.config.ClassLoadConfig;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import javax.persistence.PersistenceException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -7,17 +11,12 @@ import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.PersistenceException;
import com.avaje.ebean.config.ClassLoadConfig;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
/**
* Helper for creating Insert timestamp GeneratedProperty objects.
*/
public class InsertTimestampFactory {
final GeneratedInsertLong longTime = new GeneratedInsertLong();
final GeneratedInsertLong longTime = new GeneratedInsertLong();
final Map<Class<?>, GeneratedProperty> map = new HashMap<Class<?>, GeneratedProperty>();
@@ -41,21 +40,21 @@ public class InsertTimestampFactory {
public void setInsertTimestamp(DeployBeanProperty property) {
property.setGeneratedProperty(createInsertTimestamp(property));
}
/**
* Create the insert GeneratedProperty depending on the property type.
*/
public GeneratedProperty createInsertTimestamp(DeployBeanProperty property) {
Class<?> propType = property.getPropertyType();
property.setGeneratedProperty(createInsertTimestamp(property));
}
/**
* Create the insert GeneratedProperty depending on the property type.
*/
public GeneratedProperty createInsertTimestamp(DeployBeanProperty property) {
Class<?> propType = property.getPropertyType();
GeneratedProperty generatedProperty = map.get(propType);
if (generatedProperty != null) {
return generatedProperty;
}
throw new PersistenceException("Generated Insert Timestamp not supported on "+propType.getName());
}
throw new PersistenceException("Generated Insert Timestamp not supported on " + propType.getName());
}
}
@@ -0,0 +1,34 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import java.sql.Timestamp;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
/**
* Helper methods for Java time conversion.
*/
public class JavaTimeUtils {
/**
* Return the system millis time as a LocalDateTime.
*/
public static Object toLocalDateTime(long systemMillis) {
return new Timestamp(systemMillis).toLocalDateTime();
}
/**
* Return the system millis time as a OffsetDateTime.
*/
public static Object toOffsetDateTime(long systemMillis) {
return OffsetDateTime.ofInstant(Instant.ofEpochMilli(systemMillis), ZoneId.systemDefault());
}
/**
* Return the system millis time as a ZonedDateTime.
*/
public static Object toZonedDateTime(long systemMillis) {
return ZonedDateTime.ofInstant(Instant.ofEpochMilli(systemMillis), ZoneId.systemDefault());
}
}
@@ -1,5 +1,9 @@
package com.avaje.ebeaninternal.server.deploy.generatedproperty;
import com.avaje.ebean.config.ClassLoadConfig;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
import javax.persistence.PersistenceException;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
@@ -7,17 +11,12 @@ import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import javax.persistence.PersistenceException;
import com.avaje.ebean.config.ClassLoadConfig;
import com.avaje.ebeaninternal.server.deploy.meta.DeployBeanProperty;
/**
* Helper for creating Update timestamp GeneratedProperty objects.
*/
public class UpdateTimestampFactory {
final GeneratedUpdateLong longTime = new GeneratedUpdateLong();
final GeneratedUpdateLong longTime = new GeneratedUpdateLong();
final Map<Class<?>, GeneratedProperty> map = new HashMap<Class<?>, GeneratedProperty>();
@@ -38,15 +37,15 @@ public class UpdateTimestampFactory {
}
}
public void setUpdateTimestamp(DeployBeanProperty property) {
public void setUpdateTimestamp(DeployBeanProperty property) {
property.setGeneratedProperty(createUpdateTimestamp(property));
}
/**
* Create the update GeneratedProperty depending on the property type.
*/
protected GeneratedProperty createUpdateTimestamp(DeployBeanProperty property) {
property.setGeneratedProperty(createUpdateTimestamp(property));
}
/**
* Create the update GeneratedProperty depending on the property type.
*/
protected GeneratedProperty createUpdateTimestamp(DeployBeanProperty property) {
Class<?> propType = property.getPropertyType();
GeneratedProperty generatedProperty = map.get(propType);
@@ -54,7 +53,7 @@ public class UpdateTimestampFactory {
return generatedProperty;
}
throw new PersistenceException("Generated update Timestamp not supported on "+propType.getName());
}
throw new PersistenceException("Generated update Timestamp not supported on " + propType.getName());
}
}
@@ -1,7 +1,7 @@
<HTML>
<HEAD>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Counter, Insert Timestamp, Update Timestamp support</TITLE>
<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
<TITLE>Counter, Insert Timestamp, Update Timestamp support</TITLE>
</HEAD>
<Body BGCOLOR="#ffffff">
Counter, Insert Timestamp, Update Timestamp support
@@ -39,6 +39,8 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
protected final boolean logLevelSql;
protected final long now;
/**
* The PreparedStatement used for the dml.
*/
@@ -49,6 +51,7 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
protected ArrayList<UpdateGenValue> updateGenValues;
protected DmlHandler(PersistRequestBean<?> persistRequest, boolean emptyStringToNull) {
this.now = System.currentTimeMillis();
this.persistRequest = persistRequest;
this.emptyStringToNull = emptyStringToNull;
this.transaction = persistRequest.getTransaction();
@@ -60,6 +63,11 @@ public abstract class DmlHandler implements PersistHandler, BindableRequest {
}
}
@Override
public long now() {
return now;
}
@Override
public PersistRequestBean<?> getPersistRequest() {
return persistRequest;
@@ -24,7 +24,7 @@ public class BindablePropertyInsertGenerated extends BindableProperty {
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = gen.getInsertValue(prop, bean);
Object value = gen.getInsertValue(prop, bean, request.now());
// generated value should be the correct type
if (bean != null) {
@@ -37,7 +37,7 @@ public class BindablePropertyUpdateGenerated extends BindableProperty {
public void dmlBind(BindableRequest request, EntityBean bean) throws SQLException {
Object value = gen.getUpdateValue(prop, bean);
Object value = gen.getUpdateValue(prop, bean, request.now());
// generated value should be the correct type
request.bind(value, prop);
@@ -56,4 +56,11 @@ public interface BindableRequest {
PersistRequestBean<?> getPersistRequest();
void registerDerivedRelationship(DerivedRelationshipData assocBean);
/**
* Return the system current time in millis. This is expected to the same time used
* by multiple generated properties for a single request.
*/
long now();
}
@@ -98,6 +98,7 @@
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
<xsd:attribute name="withHistory" type="xsd:boolean"/>
<xsd:attribute name="draft" type="xsd:boolean"/>
<xsd:attribute name="identityType" type="identityType"/>
<xsd:attribute name="sequenceName" type="xsd:string"/>
<xsd:attribute name="sequenceInitial" type="xsd:positiveInteger"/>
@@ -0,0 +1,46 @@
package com.avaje.ebean.dbmigration.ddlgeneration.platform;
import com.avaje.ebean.Ebean;
import com.avaje.ebean.config.dbplatform.H2Platform;
import com.avaje.ebean.dbmigration.ddlgeneration.DdlWrite;
import com.avaje.ebean.dbmigration.model.CurrentModel;
import com.avaje.ebean.dbmigration.model.MConfiguration;
import com.avaje.ebean.dbmigration.model.ModelContainer;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
public class H2HistoryDdlTest {
@Test
public void testRegenerateHistoryTriggers() throws Exception {
SpiEbeanServer ebeanServer = (SpiEbeanServer)Ebean.getDefaultServer();
HistoryTableUpdate update = new HistoryTableUpdate("c_user");
update.add(HistoryTableUpdate.Change.ADD, "one");
update.add(HistoryTableUpdate.Change.DROP, "two");
CurrentModel currentModel = new CurrentModel(ebeanServer);
ModelContainer modelContainer = currentModel.read();
DdlWrite write = new DdlWrite(new MConfiguration(), modelContainer);
H2Platform h2Platform = new H2Platform();
PlatformDdl h2Ddl = h2Platform.getPlatformDdl();
h2Ddl.configure(ebeanServer.getServerConfig());
h2Ddl.regenerateHistoryTriggers(write, update);
assertThat(write.dropHistory().isEmpty()).isFalse();
assertThat(write.dropHistory().getBuffer()).contains("drop two");
assertThat(write.applyHistory().isEmpty()).isFalse();
assertThat(write.applyHistory().getBuffer()).contains("add one");
assertThat(write.applyHistory().getBuffer()).doesNotContain("two");
assertThat(write.rollback().isEmpty()).isFalse();
}
}
@@ -14,7 +14,11 @@ public class HistoryTableUpdateTest {
public void testToRevertedColumns_add() throws Exception {
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
assertThat(upd.getBaseTable()).isEqualTo("mytab");
upd.add(HistoryTableUpdate.Change.ADD, "two");
assertThat(upd.hasApplyChanges()).isTrue();
assertThat(upd.hasDropChanges()).isFalse();
List<String> current = current();
upd.toRevertedColumns(current);
@@ -26,6 +30,8 @@ public class HistoryTableUpdateTest {
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
upd.add(HistoryTableUpdate.Change.INCLUDE, "two");
assertThat(upd.hasApplyChanges()).isTrue();
assertThat(upd.hasDropChanges()).isFalse();
List<String> current = current();
upd.toRevertedColumns(current);
@@ -36,11 +42,13 @@ public class HistoryTableUpdateTest {
public void testToRevertedColumns_drop() throws Exception {
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
upd.add(HistoryTableUpdate.Change.DROP, "four");
upd.add(HistoryTableUpdate.Change.DROP, "three");
assertThat(upd.hasApplyChanges()).isFalse();
assertThat(upd.hasDropChanges()).isTrue();
List<String> current = current();
upd.toRevertedColumns(current);
assertThat(current).contains("one","two","three","four");
assertThat(current).contains("one","two","three");
}
@Test
@@ -48,6 +56,8 @@ public class HistoryTableUpdateTest {
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
upd.add(HistoryTableUpdate.Change.EXCLUDE, "four");
assertThat(upd.hasApplyChanges()).isTrue();
assertThat(upd.hasDropChanges()).isFalse();
List<String> current = current();
upd.toRevertedColumns(current);
@@ -61,8 +71,26 @@ public class HistoryTableUpdateTest {
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
upd.add(HistoryTableUpdate.Change.ADD, "two");
upd.add(HistoryTableUpdate.Change.DROP, "four");
assertThat(upd.hasApplyChanges()).isTrue();
assertThat(upd.hasDropChanges()).isTrue();
assertThat(upd.description()).isEqualTo("add two, drop four");
assertThat(upd.descriptionForApply()).isEqualTo("add two");
assertThat(upd.descriptionForDrop()).isEqualTo("drop four");
}
@Test
public void testDescription_withIncludeExclude() throws Exception {
HistoryTableUpdate upd = new HistoryTableUpdate("mytab");
upd.add(HistoryTableUpdate.Change.ADD, "two");
upd.add(HistoryTableUpdate.Change.INCLUDE, "five");
upd.add(HistoryTableUpdate.Change.EXCLUDE, "six");
upd.add(HistoryTableUpdate.Change.DROP, "four");
assertThat(upd.hasApplyChanges()).isTrue();
assertThat(upd.hasDropChanges()).isTrue();
assertThat(upd.descriptionForApply()).isEqualTo("add two, include five, exclude six");
assertThat(upd.descriptionForDrop()).isEqualTo("drop four");
}
List<String> current() {
@@ -1,8 +1,11 @@
package com.avaje.ebean.dbmigration.model;
import com.avaje.ebean.dbmigration.migration.AddColumn;
import com.avaje.ebean.dbmigration.migration.AddHistoryTable;
import com.avaje.ebean.dbmigration.migration.AlterColumn;
import com.avaje.ebean.dbmigration.migration.DropColumn;
import com.avaje.ebean.dbmigration.migration.DropHistoryTable;
import com.avaje.ebean.dbmigration.migration.DropTable;
import org.junit.Test;
import java.util.List;
@@ -51,7 +54,26 @@ public class MTableTest {
}
@Test
public void testCompare_addColumnDropColumn() throws Exception {
public void test_allHistoryColumns() throws Exception {
MTable base = base();
base.registerDroppedColumn("fullName",2);
base.registerDroppedColumn("last",4);
assertThat(base.allHistoryColumns(false)).containsExactly("id","name","status");
assertThat(base.allHistoryColumns(true)).containsExactly("id","name","fullName","status","last");
}
@Test
public void test_dropTable() {
MTable base = base();
DropTable dropTable = base.dropTable();
assertThat(dropTable.getName()).isEqualTo(base.getName());
}
@Test
public void test_compare_addColumnDropColumn() throws Exception {
ModelDiff diff = new ModelDiff();
diff.compareTables(base(), newTable());
@@ -71,7 +93,7 @@ public class MTableTest {
}
@Test
public void testCompare_addTwoColumnsToSameTable() throws Exception {
public void test_compare_addTwoColumnsToSameTable() throws Exception {
ModelDiff diff = new ModelDiff();
diff.compareTables(base(), newTableAdd2Columns());
@@ -88,7 +110,7 @@ public class MTableTest {
}
@Test
public void testCompare_modifyColumn() throws Exception {
public void test_compare_modifyColumn() throws Exception {
ModelDiff diff = new ModelDiff();
diff.compareTables(base(), newTableModifiedColumn());
@@ -107,4 +129,99 @@ public class MTableTest {
assertThat(diff.getDropChanges()).hasSize(0);
}
@Test
public void test_apply_dropColumn() {
MTable base = base();
DropColumn dropColumn = new DropColumn();
dropColumn.setTableName("tab");
dropColumn.setColumnName("name");
base.apply(dropColumn);
assertThat(base.getColumn("name")).isNull();
}
@Test(expected = IllegalStateException.class)
public void test_apply_dropColumn_doesNotExist() {
MTable base = base();
DropColumn dropColumn = new DropColumn();
dropColumn.setTableName(base.getName());
dropColumn.setColumnName("DoesNotExist");
base.apply(dropColumn);
}
@Test(expected = IllegalStateException.class)
public void test_apply_alterColumn_doesNotExist() {
MTable base = base();
AlterColumn alterColumn = new AlterColumn();
alterColumn.setTableName(base.getName());
alterColumn.setColumnName("DoesNotExist");
alterColumn.setType("integer");
base.apply(alterColumn);
}
@Test
public void test_apply_alterColumn_type() {
MTable base = base();
AlterColumn alterColumn = new AlterColumn();
alterColumn.setTableName(base.getName());
alterColumn.setColumnName("id");
alterColumn.setType("uuid");
base.apply(alterColumn);
assertThat(base.getColumn("id").getType()).isEqualTo("uuid");
}
@Test
public void test_compare_addAndDropColumn() throws Exception {
MTable base = base();
MTable newTable = newTable();
ModelDiff diff = new ModelDiff();
base.compare(diff, newTable);
assertThat(diff.getApplyChanges()).hasSize(1);
assertThat(diff.getDropChanges()).hasSize(1);
}
@Test
public void test_compare_addHistoryToTable() {
MTable base = base();
MTable withHistory = base();
withHistory.setWithHistory(true);
ModelDiff diff = new ModelDiff();
base.compare(diff, withHistory);
assertThat(diff.getDropChanges()).isEmpty();
assertThat(diff.getApplyChanges()).hasSize(1);
assertThat(diff.getApplyChanges().get(0)).isInstanceOf(AddHistoryTable.class);
}
@Test
public void test_compare_removeHistoryFromTable() throws Exception {
MTable withHistory = base();
withHistory.setWithHistory(true);
MTable noHistory = base();
ModelDiff diff = new ModelDiff();
withHistory.compare(diff, noHistory);
assertThat(diff.getApplyChanges()).isEmpty();
assertThat(diff.getDropChanges()).hasSize(1);
assertThat(diff.getDropChanges().get(0)).isInstanceOf(DropHistoryTable.class);
}
}
@@ -36,6 +36,6 @@ public class ModelContainerApplyTest {
assertThat(foo.getTablespace()).isEqualTo("fooSpace");
assertThat(foo.getIndexTablespace()).isEqualTo("fooIndexSpace");
assertThat(foo.isWithHistory()).isEqualTo(false);
assertThat(foo.getColumns()).containsKeys("col1", "col3", "added_to_foo");
assertThat(foo.allColumns()).extracting("name").contains("col1", "col3", "added_to_foo");
}
}
@@ -37,8 +37,6 @@ public class ModelBuildBeanVisitorTest extends BaseTestCase {
assertThat(item.primaryKeyColumns()).hasSize(2);
MTable customer = model.getTable("o_customer");
assertThat(customer).isNotNull();
assertThat(customer.getSequenceName()).isNull();
}
}
@@ -8,7 +8,7 @@ import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import static org.junit.Assert.*;
import static org.junit.Assert.assertTrue;
public class InsertTimestampFactoryTest {
@@ -20,7 +20,7 @@ public class InsertTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, LocalDateTime.class, null, null);
GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop);
Object value = insertTimestamp.getInsertValue(null, null);
Object value = insertTimestamp.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof LocalDateTime);
}
@@ -30,7 +30,7 @@ public class InsertTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, OffsetDateTime.class, null, null);
GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop);
Object value = insertTimestamp.getInsertValue(null, null);
Object value = insertTimestamp.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof OffsetDateTime);
}
@@ -40,7 +40,7 @@ public class InsertTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, Timestamp.class, null, null);
GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop);
Object value = insertTimestamp.getInsertValue(null, null);
Object value = insertTimestamp.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof Timestamp);
}
@@ -50,7 +50,7 @@ public class InsertTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, java.util.Date.class, null, null);
GeneratedProperty insertTimestamp = factory.createInsertTimestamp(prop);
Object value = insertTimestamp.getInsertValue(null, null);
Object value = insertTimestamp.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof java.util.Date);
}
@@ -21,7 +21,7 @@ public class UpdateTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, LocalDateTime.class, null, null);
GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop);
Object value = generatedProperty.getInsertValue(null, null);
Object value = generatedProperty.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof LocalDateTime);
}
@@ -31,7 +31,7 @@ public class UpdateTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, OffsetDateTime.class, null, null);
GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop);
Object value = generatedProperty.getInsertValue(null, null);
Object value = generatedProperty.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof OffsetDateTime);
}
@@ -41,7 +41,7 @@ public class UpdateTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, Timestamp.class, null, null);
GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop);
Object value = generatedProperty.getInsertValue(null, null);
Object value = generatedProperty.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof Timestamp);
}
@@ -51,7 +51,7 @@ public class UpdateTimestampFactoryTest {
DeployBeanProperty prop = new DeployBeanProperty(null, java.util.Date.class, null, null);
GeneratedProperty generatedProperty = factory.createUpdateTimestamp(prop);
Object value = generatedProperty.getInsertValue(null, null);
Object value = generatedProperty.getInsertValue(null, null, System.currentTimeMillis());
assertTrue(value instanceof java.util.Date);
}
}
@@ -5,6 +5,7 @@ import com.avaje.ebean.Ebean;
import com.avaje.tests.model.EGenProps;
import org.junit.Test;
import static org.assertj.core.api.StrictAssertions.assertThat;
import static org.junit.Assert.assertNotNull;
public class TestGeneratedProperties extends BaseTestCase {
@@ -31,9 +32,16 @@ public class TestGeneratedProperties extends BaseTestCase {
assertNotNull(bean.getLongCreated());
assertNotNull(bean.getLongUpdated());
assertThat(bean.getWhenCreated().toInstant().toEpochMilli()).isEqualTo(bean.getLongCreated());
assertThat(bean.getWhenModified().toInstant().toEpochMilli()).isEqualTo(bean.getLongCreated());
assertThat(bean.getWhenModified().toInstant().toEpochMilli()).isEqualTo(bean.getLongCreated());
bean.setName("updating...");
Ebean.save(bean);
assertThat(bean.getWhenModified()).isNotEqualTo(bean.getLongCreated());
assertThat(bean.getWhenModified().toInstant().toEpochMilli()).isEqualTo(bean.getLongUpdated());
Ebean.delete(bean);
}
}
@@ -13,6 +13,7 @@ import org.junit.Test;
import java.util.List;
import java.util.Random;
import static org.assertj.core.api.StrictAssertions.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -127,6 +128,50 @@ public class TestRawSqlMasterDetail extends BaseTestCase {
assertFalse(ordersFromRaw.isEmpty());
}
@Test
public void testTableAlias_with_rootTypeMappedNotMapped() {
ResetBasicData.reset();
String rs = "select o.id, o.status " +
"from o_order o order by o.id asc";
RawSql rawSql = RawSqlBuilder.parse(rs)
.create();
List<Order> ordersFromRaw = Ebean.find(Order.class)
.setRawSql(rawSql)
.findList();
for (Order order : ordersFromRaw) {
assertThat(order.getId()).isNotNull();
assertThat(order.getStatus()).isNotNull();
}
}
@Test
public void testTableAlias_with_rootTypeMappedToNullPath() {
ResetBasicData.reset();
String rs = "select o.id, o.status " +
"from o_order o order by o.id asc";
RawSql rawSql = RawSqlBuilder.parse(rs)
.tableAliasMapping("o", null)
.create();
List<Order> ordersFromRaw = Ebean.find(Order.class)
.setRawSql(rawSql)
.findList();
for (Order order : ordersFromRaw) {
assertThat(order.getId()).isNotNull();
assertThat(order.getStatus()).isNotNull();
}
}
@Test
public void testWithMultipleManys() {