You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by jo...@apache.org on 2012/06/15 18:58:29 UTC
svn commit: r1350693 [2/2] - in /cayenne/sandbox: ./ cayenne-migrations/
cayenne-migrations/.settings/ cayenne-migrations/src/
cayenne-migrations/src/main/ cayenne-migrations/src/main/java/
cayenne-migrations/src/main/java/org/ cayenne-migrations/src/m...
Added: cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTable.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTable.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTable.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTable.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,285 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.sql.Types;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbEntity;
+import org.apache.cayenne.merge.MergerFactory;
+import org.apache.cayenne.merge.MergerToken;
+
+/**
+ * Represents a table in the database and provides operations for changing the schema.
+ *
+ * Internally this holds a DbEntity and uses it along with a MergerFactory to queue up
+ * MergerTokens to perform the schema changes.
+ *
+ * @author john
+ *
+ */
+public abstract class MigrationTable {
+
+ private MigrationDatabase database;
+ private DbEntity entity;
+ private Map<String, MigrationColumn> columns = new HashMap<String, MigrationColumn>();
+
+ MigrationTable(MigrationDatabase database, String tableName) {
+ this.database = database;
+
+ this.entity = new DbEntity(tableName);
+ entity.setDataMap(database.getDataMap());
+ database.getDataMap().addDbEntity(entity);
+ }
+
+ MigrationDatabase getDatabase() {
+ return database;
+ }
+
+ MergerFactory factory() {
+ return database.factory();
+ }
+
+ DbEntity getEntity() {
+ return entity;
+ }
+
+ Map<String, MigrationColumn> getColumns() {
+ return columns;
+ }
+
+ abstract boolean isNew();
+
+ /**
+ * Adds a column to a table; works for both new and existing tables.
+ * @param columnName
+ * @param jdbcType
+ * @return
+ */
+ public MigrationColumnNew addColumn(String columnName, int jdbcType) {
+ return addColumn(columnName, jdbcType, false, null);
+ }
+ public MigrationColumnNew addColumn(String columnName, int jdbcType, boolean isMandatory, Object defaultValue) {
+ return new MigrationColumnNew(this, columnName, jdbcType, -1, -1, -1, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addColumn(String columnName, int jdbcType, int maxLength) {
+ return addColumn(columnName, jdbcType, maxLength, false, null);
+ }
+ public MigrationColumnNew addColumn(String columnName, int jdbcType, int maxLength, boolean isMandatory, Object defaultValue) {
+ return new MigrationColumnNew(this, columnName, jdbcType, maxLength, -1, -1, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addColumn(String columnName, int jdbcType, int precision, int scale) {
+ return addColumn(columnName, jdbcType, precision, scale, false, null);
+ }
+ public MigrationColumnNew addColumn(String columnName, int jdbcType, int precision, int scale, boolean isMandatory, Object defaultValue) {
+ return new MigrationColumnNew(this, columnName, jdbcType, -1, precision, scale, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addArrayColumn(String columnName) {
+ return addArrayColumn(columnName, false);
+ }
+ public MigrationColumnNew addArrayColumn(String columnName, boolean isMandatory) {
+ return addColumn(columnName, Types.ARRAY, isMandatory, null);
+ }
+
+ public MigrationColumnNew addBigIntColumn(String columnName) {
+ return addBigIntColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addBigIntColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.BIGINT, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addBinaryColumn(String columnName) {
+ return addBinaryColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addBinaryColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.BINARY, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addBitColumn(String columnName) {
+ return addBitColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addBitColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.BIT, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addBlobColumn(String columnName) {
+ return addBlobColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addBlobColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.BLOB, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addCharColumn(String columnName, int maxLength) {
+ return addCharColumn(columnName, maxLength, false, null);
+ }
+ public MigrationColumnNew addCharColumn(String columnName, int maxLength, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.CHAR, maxLength, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addBooleanColumn(String columnName) {
+ return addBooleanColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addBooleanColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.BOOLEAN, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addClobColumn(String columnName) {
+ return addClobColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addClobColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.CLOB, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addDateColumn(String columnName) {
+ return addDateColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addDateColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.DATE, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addDecimalColumn(String columnName, int precision, int scale) {
+ return addDecimalColumn(columnName, precision, scale, false, null);
+ }
+ public MigrationColumnNew addDecimalColumn(String columnName, int precision, int scale, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.DECIMAL, precision, scale, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addDoubleColumn(String columnName) {
+ return addDoubleColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addDoubleColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.DOUBLE, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addFloatColumn(String columnName) {
+ return addFloatColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addFloatColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.FLOAT, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addIntegerColumn(String columnName) {
+ return addIntegerColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addIntegerColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.INTEGER, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addLongVarBinaryColumn(String columnName) {
+ return addLongVarBinaryColumn(columnName, false);
+ }
+ public MigrationColumnNew addLongVarBinaryColumn(String columnName, boolean isMandatory) {
+ return addColumn(columnName, Types.LONGVARBINARY, isMandatory, null);
+ }
+
+ public MigrationColumnNew addLongVarCharColumn(String columnName) {
+ return addLongVarCharColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addLongVarCharColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.LONGVARCHAR, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addNumericColumn(String columnName, int precision, int scale) {
+ return addNumericColumn(columnName, precision, scale, false, null);
+ }
+ public MigrationColumnNew addNumericColumn(String columnName, int precision, int scale, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.NUMERIC, precision, scale, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addRealColumn(String columnName) {
+ return addRealColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addRealColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.REAL, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addSmallIntColumn(String columnName) {
+ return addSmallIntColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addSmallIntColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.SMALLINT, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addTimeColumn(String columnName) {
+ return addTimeColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addTimeColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.TIME, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addTimestampColumn(String columnName) {
+ return addTimestampColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addTimestampColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.TIMESTAMP, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addTinyIntColumn(String columnName) {
+ return addTinyIntColumn(columnName, false, null);
+ }
+ public MigrationColumnNew addTinyIntColumn(String columnName, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.TINYINT, isMandatory, defaultValue);
+ }
+
+ public MigrationColumnNew addVarBinaryColumn(String columnName, int maxLength) {
+ return addVarBinaryColumn(columnName, maxLength, false);
+ }
+ public MigrationColumnNew addVarBinaryColumn(String columnName, int maxLength, boolean isMandatory) {
+ return addColumn(columnName, Types.VARBINARY, maxLength, isMandatory, null);
+ }
+
+ public MigrationColumnNew addVarcharColumn(String columnName, int maxLength) {
+ return addVarcharColumn(columnName, maxLength, false, null);
+ }
+ public MigrationColumnNew addVarcharColumn(String columnName, int maxLength, boolean isMandatory, Object defaultValue) {
+ return addColumn(columnName, Types.VARCHAR, maxLength, isMandatory, defaultValue);
+ }
+
+ /**
+ * Adds a column to the list of primary keys for this table; works for both new and existing tables.
+ * @param columnName
+ */
+ public void addPrimaryKey(String columnName) {
+ ((DbAttribute)entity.getAttribute(columnName)).setPrimaryKey(true);
+ if (!isNew()) {
+ MigrationColumn column = columns.get(columnName);
+ MergerToken op = factory().createSetPrimaryKeyToDb(getEntity(), Collections.EMPTY_LIST, Collections.singletonList(column.getAttribute()), null);
+ getDatabase().addOperation(op);
+ }
+ }
+
+ /**
+ * Adds a new foreign key constraint; works for both new and existing tables.
+ * @param sourceColumnName
+ * @param destinationTable
+ * @param destinationColumnName
+ */
+ public void addForeignKey(String sourceColumnName, String destinationTable, String destinationColumnName) {
+ MigrationRelationship relationship = new MigrationRelationship(this, sourceColumnName, destinationTable, destinationColumnName);
+ MergerToken op = factory().createAddRelationshipToDb(getEntity(), relationship.getRelationship());
+ getDatabase().addOperation(op);
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableExisting.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableExisting.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableExisting.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableExisting.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,83 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.merge.MergerToken;
+
+/**
+ * Represents an existing table in the database and provides operations for changing the schema.
+ *
+ * Internally this holds a DbEntity and uses it along with a MergerFactory to queue up
+ * MergerTokens to perform the schema changes.
+ *
+ * @author john
+ *
+ */
+public class MigrationTableExisting extends MigrationTable {
+
+ MigrationTableExisting(MigrationDatabase database, String tableName) {
+ super(database, tableName);
+ }
+
+ @Override
+ boolean isNew() {
+ return false;
+ }
+
+ /**
+ * Returns an existing column that can be changed.
+ * @param columnName
+ * @return
+ */
+ public MigrationColumnExisting alterColumn(String columnName) {
+ MigrationColumn result;
+ if (getColumns().get(columnName) != null) {
+ result = getColumns().get(columnName);
+ if (result.isNew()) {
+ throw new IllegalArgumentException(columnName + " is a new column, it cannot be altered.");
+ }
+ } else {
+ result = new MigrationColumnExisting(this, columnName);
+ }
+
+ return (MigrationColumnExisting) result;
+ }
+
+ /**
+ * Drops an existing column.
+ */
+ public void dropColumn(String columnName) {
+ DbAttribute attribute = alterColumn(columnName).getAttribute();
+ getDatabase().addOperation(factory().createDropColumnToDb(getEntity(), attribute));
+ }
+
+ /**
+ * Removes an existing foreign key constraint.
+ * @param sourceColumnName
+ * @param destinationTable
+ * @param destinationColumnName
+ */
+ public void dropForeignKey(String sourceColumnName, String destinationTable, String destinationColumnName) {
+ MigrationRelationship relationship = new MigrationRelationship(this, sourceColumnName, destinationTable, destinationColumnName);
+ MergerToken op = factory().createDropRelationshipToDb(getEntity(), relationship.getRelationship());
+ getDatabase().addOperation(op);
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableNew.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableNew.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableNew.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/MigrationTableNew.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,49 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import org.apache.cayenne.merge.MergerToken;
+
+/**
+ * Represents a new table in the database.
+ *
+ * Internally this holds a DbEntity and uses it along with a MergerFactory to queue up
+ * MergerTokens to perform the schema changes.
+ *
+ * @author john
+ *
+ */
+public class MigrationTableNew extends MigrationTable {
+
+ MigrationTableNew(MigrationDatabase database, String tableName) {
+ super(database, tableName);
+ create();
+ }
+
+ @Override
+ boolean isNew() {
+ return true;
+ }
+
+ private void create() {
+ MergerToken op = factory().createCreateTableToDb(getEntity());
+ getDatabase().addOperation(op);
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/Migrator.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/Migrator.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/Migrator.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/Migrator.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,256 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.List;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.log.JdbcEventLogger;
+import org.apache.cayenne.map.DataMap;
+import org.apache.cayenne.merge.AbstractToDbToken;
+import org.apache.cayenne.merge.MergerToken;
+import org.apache.commons.lang.StringUtils;
+
+/**
+ * The Migrator discovers and executes Migration subclasses in order to migrate
+ * a database schema to the latest version.
+ *
+ * @author john
+ *
+ */
+public class Migrator {
+
+ //private static final Logger log = Logger.getLogger(Migrator.class);
+
+ private final DataNode node;
+ private final String migrationsPackage;
+ private Connection connection;
+
+ /**
+ *
+ * @param node the node that the schema migrations should be applied to
+ * @param migrationsPackage the package that your migration subclasses reside in
+ */
+ public Migrator(DataNode node, String migrationsPackage) {
+ this.node = node;
+ this.migrationsPackage = migrationsPackage;
+ }
+
+ /**
+ * The name of the table that holds the version and lock information for the Migrator to use.
+ * @return
+ */
+ protected String migrationTableName() {
+ return "dbupdater";
+ }
+
+ void createInternalMigrationSchema() throws SQLException {
+ executeSqlWithUpdateCount("CREATE TABLE " + migrationTableName() + "(dataMap VARCHAR(50) NOT NULL, version INTEGER DEFAULT -1 NOT NULL, locked SMALLINT DEFAULT 0 NOT NULL, PRIMARY KEY(dataMap))");
+ getConnection().commit();
+ }
+
+ int currentDbVersion(DataMap map) throws SQLException {
+ String sql = String.format("SELECT version FROM %s WHERE dataMap = '%s'", migrationTableName(), map.getName());
+ return executeSqlReturnInt(sql).intValue();
+ }
+
+ void setDbVersion(DataMap map, int version) throws SQLException {
+ int count = executeSqlWithUpdateCount(String.format("UPDATE %s SET version = %d WHERE version = %d AND dataMap = '%s'", migrationTableName(), version, version-1, map.getName()));
+ if (count == 0) {
+ throw new RuntimeException("Unable to update database version for dataMap: " + map.getName());
+ }
+ }
+
+ boolean lock(DataMap map) throws SQLException {
+ String sql = String.format("UPDATE %s SET locked = 1 WHERE locked=0 and dataMap='%s'", migrationTableName(), map.getName());
+ int count = 0;
+ try {
+ try {
+ count = executeSqlWithUpdateCount(sql);
+ if (count > 0) {
+ return true; // got the lock
+ }
+ } catch (Exception e) {
+ createInternalMigrationSchema();
+ }
+
+ sql = String.format("SELECT locked FROM %s WHERE dataMap='%s'", migrationTableName(), map.getName());
+ Integer locked = executeSqlReturnInt(sql);
+ if (locked != null) {
+ return false; // row exists and is already locked
+ } else {
+ // row doesn't exist
+ sql = String.format("INSERT INTO %s(dataMap, locked) VALUES ('%s', 1)", migrationTableName(), map.getName());
+ executeSqlWithUpdateCount(sql);
+ return true;
+ }
+ } finally {
+ getConnection().commit();
+ }
+ }
+
+ void unlock(DataMap map) throws SQLException {
+ int count = executeSqlWithUpdateCount(String.format("UPDATE %s SET locked = 0 WHERE locked = 1 AND dataMap = '%s'", migrationTableName(), map.getName()));
+ if (count == 0) {
+ throw new IllegalStateException("Unable to remove migration lock.");
+ }
+ getConnection().commit();
+ }
+
+ Migration createMigrationClassForVersion(DataMap map, int version) {
+ String className = migrationsPackage + "." + StringUtils.capitalize(map.getName()) + version;
+
+ Class<?> clazz;
+ try {
+ clazz = Class.forName(className);
+ Migration instance = (Migration) clazz.getConstructor(DataNode.class).newInstance(node);
+ return instance;
+ } catch (Exception e) {
+ //log.debug("Migration class not found: " + className + "; stopping at version " + (version-1) + ".");
+ return null;
+ }
+ }
+
+ /**
+ * Discovers and executes the Migrations necessary to update the database schema to the latest version.
+ *
+ * @throws SQLException
+ */
+ public void migrateToLatest() throws SQLException {
+ synchronized (node) {
+ try {
+ getConnection();
+
+ for (DataMap map : node.getDataMaps()) {
+
+ while (!lock(map)) {
+ //log.debug("Waiting to obtain migration lock for node: " + node.getName());
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ return;
+ }
+ }
+
+ try {
+ int version = currentDbVersion(map)+1;
+
+ Migration migration;
+ while ((migration = createMigrationClassForVersion(map, version)) != null) {
+ //log.info(String.format("Updating %s to version %d", map.getName(), version));
+ migration.run();
+ try {
+ executeOperations(migration.getDatabase().getOperations());
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to migrate database to version " + version + ": " + e.getMessage(), e);
+ }
+ setDbVersion(map, version);
+ getConnection().commit();
+ version++;
+ }
+ } finally {
+ unlock(map);
+ }
+ }
+
+ } finally {
+ if (getConnection() != null) {
+ try {
+ getConnection().close();
+ } catch (SQLException e) {}
+ }
+ }
+ }
+ }
+
+ void executeOperations(List<MergerToken> operations) throws SQLException {
+ for (MergerToken token : operations) {
+ AbstractToDbToken dbToken = (AbstractToDbToken)token;
+ executeSqlWithUpdateCount(dbToken.createSql(node.getAdapter()));
+ }
+ }
+
+ void executeSqlWithUpdateCount(List<String> sqlStatements) throws SQLException {
+ for (String sql : sqlStatements) {
+ executeSqlWithUpdateCount(sql);
+ }
+ }
+
+ int executeSqlWithUpdateCount(String sql) throws SQLException {
+ Statement st = null;
+ JdbcEventLogger logger = node.getJdbcEventLogger();
+ try {
+ logger.log(sql);
+ st = getConnection().createStatement();
+ try {
+ st.execute(sql);
+ } catch (SQLException e) {
+ getConnection().rollback();
+ throw new RuntimeException("SQL statement failed \"" + sql + "\": " + e.getMessage(), e);
+ }
+ return st.getUpdateCount();
+ } finally {
+ closeStatement(st);
+ }
+ }
+
+ Integer executeSqlReturnInt(String sql) throws SQLException {
+ Statement st = null;
+ JdbcEventLogger logger = node.getJdbcEventLogger();
+ try {
+ logger.log(sql);
+ st = getConnection().createStatement();
+ try {
+ st.execute(sql);
+ ResultSet rs = st.getResultSet();
+ if (rs != null && rs.next()) {
+ return rs.getInt(1);
+ } else {
+ return null;
+ }
+ } catch (SQLException e) {
+ getConnection().rollback();
+ throw new RuntimeException("SQL statement failed \"" + sql + "\": " + e.getMessage(), e);
+ }
+ } finally {
+ closeStatement(st);
+ }
+ }
+
+ private void closeStatement(Statement st) {
+ if (st != null) {
+ try {
+ st.close();
+ } catch (SQLException e) {}
+ }
+ }
+
+ Connection getConnection() throws SQLException {
+ if (connection == null) {
+ connection = node.getDataSource().getConnection();
+ getConnection().setAutoCommit(false);
+ }
+ return connection;
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/SqlFileMigration.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/SqlFileMigration.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/SqlFileMigration.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/SqlFileMigration.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,86 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import org.apache.cayenne.access.DataNode;
+
+/**
+ * <p>A migration that relies on an SQL file for it's operations.</p>
+ *
+ * The SQL filename follows these naming conventions:<br>
+ * 1) It is located in the same package as the Migration class it accompanies.<br>
+ * 2) It is named the same as the Migration class is accompanies with a ".sql" extension.<br>
+ * Optionally the class name may be followed by a dash ("-") and the database type it uses to refer to a database-specific file for cases where you want support multiple DB implementations.<br>
+ * The database type is derived by taking from the JdbcAdapter class being used and removing the "Adapter" suffix.<br>
+ *
+ * <p>So for a Migration class named Tutorial0 the generic (universal) sql file would be named 'Tutorial0.sql'<br>
+ * For a postgresql-specific migration the sql file would be named 'Tutorial0-Postgres.sql'</p>
+ *
+ * @author john
+ *
+ */
+public class SqlFileMigration extends Migration {
+
+ /**
+ *
+ * @param node the node that you want to apply the migration on
+ */
+ public SqlFileMigration(DataNode node) {
+ super(node);
+ }
+
+ /**
+ * Executes the sql script given by 'sqlFilename()'.
+ */
+ @Override
+ public void upgrade(MigrationDatabase db) {
+ executeSqlScript(sqlFilename());
+ }
+
+ /**
+ * Returns the filename for the sql script file for this migration, looking first for a database-specific file, then for a generic one.
+ * @return
+ */
+ public String sqlFilename() {
+ if (getClass().getResource(databaseSpecificSqlFilename()) != null) {
+ return databaseSpecificSqlFilename();
+ } else {
+ return genericSqlFilename();
+ }
+ }
+
+ /**
+ * Returns the filename for a database-specific sql script file with migration commands.
+ * @return
+ */
+ protected String databaseSpecificSqlFilename() {
+ String databaseType = getDataNode().getAdapter().getClass().getSimpleName();
+ databaseType = databaseType.replace("Adapter", "");
+ return getClass().getSimpleName() + "-" + databaseType + ".sql";
+ }
+
+ /**
+ * Returns the filename for a generic (not database specific) sql script file with migration commands.
+ * @return
+ */
+ protected String genericSqlFilename() {
+ return getClass().getSimpleName() + ".sql";
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/package.html
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/package.html?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/package.html (added)
+++ cayenne/sandbox/cayenne-migrations/src/main/java/org/apache/cayenne/migration/package.html Fri Jun 15 16:58:25 2012
@@ -0,0 +1,30 @@
+<html>
+<body>
+
+<p>Provides functionality to create and modify database schema / metadata so that it can be evolved over time
+in a recreatable and deterministic way. This is done by versioning the database schema.
+This API gives you database independence for your schema definition since all the SQL is generated by the DbAdapter.</p>
+
+<p>There is also the ability to include raw SQL statements from a file. These files can be defined for each database
+type in order to preserve database independence.</p>
+
+<p>Getting Started:</p>
+<ul>
+ <li>Run org.apache.cayenne.migration.MigrationGenerator to generate the initial Migration from your Cayenne project file (model).
+ This class has a main method that takes two arguments:
+ 1) the name or path to your cayenne project file (domain) and
+ 2) the output directory.
+ It will create a java class with all the calls necessary to create your tables and foreign key constraints, etc.
+ This java class needs to be moved into your project after being generated.</li>
+ <li>At application startup time create a org.apache.cayenne.migration.Migrator object and call migrateToLatest(). For example:</li>
+</ul>
+<pre>
+try {
+ new Migrator(domain.getDataNode("production"), MyDataMap0.class.getPackage().getName()).migrateToLatest();
+} catch (SQLException e) {
+ throw new RuntimeException("Unable to migrate database to current version: " + e.getMessage(), e);
+}
+</pre>
+
+</body>
+</html>
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/merge/ArbitrarySqlToDbTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/merge/ArbitrarySqlToDbTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/merge/ArbitrarySqlToDbTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/merge/ArbitrarySqlToDbTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,55 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.merge;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.map.DbEntity;
+
+public class ArbitrarySqlToDbTest extends TestCase {
+
+ private ArbitrarySqlToDb subject;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ subject = new ArbitrarySqlToDb("UPDATE x SET y=1");
+ }
+
+ public void testCreateSql() {
+ List<String> statements = subject.createSql(null);
+ assertEquals(1, statements.size());
+ assertEquals("UPDATE x SET y=1", statements.get(0));
+ }
+
+ public void testGetTokenValue() {
+ assertEquals("UPDATE x SET y=1", subject.getTokenValue());
+ }
+
+ public void testCompareTo() {
+ CreateTableToDb createTableToken = new CreateTableToDb(new DbEntity("test"));
+ assertTrue(subject.compareTo(createTableToken) > 0);
+
+ ArbitrarySqlToDb arbitrarySqlToken = new ArbitrarySqlToDb("UPDATE z SET y=1");
+ assertEquals(0, subject.compareTo(arbitrarySqlToken));
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnExistingTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnExistingTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnExistingTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnExistingTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,132 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.sql.Types;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.merge.SetAllowNullToDb;
+import org.apache.cayenne.merge.SetColumnTypeToDb;
+import org.apache.cayenne.merge.SetNotNullToDb;
+import org.apache.cayenne.merge.SetValueForNullToDb;
+
+public class MigrationColumnExistingTest extends TestCase {
+
+ private DataNode node;
+ private MigrationDatabase db;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+
+ db = new MigrationDatabase(node);
+ }
+
+ public void testIsNew() {
+ MigrationTableExisting table = db.alterTable("table");
+ MigrationColumn column = table.alterColumn("column");
+ assertFalse(column.isNew());
+ }
+
+ public void testAddNotNullConstraint() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").addNotNullConstraint();
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetNotNullToDb);
+
+ SetNotNullToDb operation = (SetNotNullToDb) table.getDatabase().getOperations().get(0);
+ assertEquals("column", operation.getColumn().getName());
+ assertEquals("table", operation.getColumn().getEntity().getName());
+ }
+
+ public void testDropNotNullConstraint() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").dropNotNullConstraint();
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetAllowNullToDb);
+
+ SetAllowNullToDb operation = (SetAllowNullToDb) table.getDatabase().getOperations().get(0);
+ assertEquals("column", operation.getColumn().getName());
+ assertEquals("table", operation.getColumn().getEntity().getName());
+ }
+
+ public void testSetDataType() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").setDataType(Types.BIGINT);
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetColumnTypeToDb);
+
+ SetColumnTypeToDb operation = (SetColumnTypeToDb)table.getDatabase().getOperations().get(0);
+ assertEquals(Types.BIGINT, operation.getColumnNew().getType());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetColumnTypeToDb);
+ }
+
+ public void testSetDataTypeWithMaxLength() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").setDataType(Types.VARCHAR, 256);
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetColumnTypeToDb);
+
+ SetColumnTypeToDb operation = (SetColumnTypeToDb)table.getDatabase().getOperations().get(0);
+ assertEquals(Types.VARCHAR, operation.getColumnNew().getType());
+ assertEquals(256, operation.getColumnNew().getMaxLength());
+ }
+
+ public void testSetDataTypeWithPrecisionAndScale() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").setDataType(Types.DECIMAL, 38, 4);
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetColumnTypeToDb);
+
+ SetColumnTypeToDb operation = (SetColumnTypeToDb)table.getDatabase().getOperations().get(0);
+ assertEquals(Types.DECIMAL, operation.getColumnNew().getType());
+ assertEquals(38, operation.getColumnNew().getAttributePrecision());
+ assertEquals(4, operation.getColumnNew().getScale());
+ }
+
+ public void testSetDefaultValue() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").setDefault(1);
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof SetValueForNullToDb);
+
+ SetValueForNullToDb operation = (SetValueForNullToDb) table.getDatabase().getOperations().get(0);
+ assertEquals("column", operation.getColumn().getName());
+ assertEquals("table", operation.getColumn().getEntity().getName());
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnNewTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnNewTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnNewTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationColumnNewTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,107 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.sql.Types;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.merge.AddColumnToDb;
+import org.apache.cayenne.merge.CreateTableToDb;
+import org.apache.cayenne.merge.SetValueForNullToDb;
+
+public class MigrationColumnNewTest extends TestCase {
+
+ private DataNode node;
+ private MigrationDatabase db;
+ private MigrationColumnNew subject;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+
+ db = new MigrationDatabase(node);
+ }
+
+ public void testAddColumnToNewTableNoDefault() {
+ MigrationTable table = db.createTable("table");
+ subject = new MigrationColumnNew(table, "column", Types.INTEGER, 0, 0, 0, false, null);
+
+ assertEquals(1, subject.getTable().getDatabase().getOperations().size());
+ assertTrue(subject.getTable().getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ }
+
+ public void testAddColumnToNewTableWithDefault() {
+ MigrationTable table = db.createTable("table");
+ subject = new MigrationColumnNew(table, "column", Types.INTEGER, 0, 0, 0, true, 1);
+
+ assertEquals(2, subject.getTable().getDatabase().getOperations().size());
+ assertTrue(subject.getTable().getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ assertTrue(subject.getTable().getDatabase().getOperations().get(1) instanceof SetValueForNullToDb);
+
+// CreateTableToDb op = (CreateTableToDb) subject.getTable().getDatabase().getOperations().get(0);
+// List<String> statements = op.createSql(node.getAdapter());
+// for (String statement : statements) {
+// if (statement.toUpperCase().startsWith("CREATE TABLE")) {
+// assertTrue(statement.contains(" DEFAULT "));
+// }
+// }
+ }
+
+ public void testAddColumnToExistingTableNoDefault() {
+ MigrationTable table = db.alterTable("table");
+ subject = new MigrationColumnNew(table, "column", Types.INTEGER, 0, 0, 0, false, null);
+
+ assertEquals(1, subject.getTable().getDatabase().getOperations().size());
+ assertTrue(subject.getTable().getDatabase().getOperations().get(0) instanceof AddColumnToDb);
+ }
+
+ public void testAddColumnToExistingTableWithDefault() {
+ MigrationTable table = db.alterTable("table");
+ subject = new MigrationColumnNew(table, "column", Types.INTEGER, 0, 0, 0, true, 1);
+
+ assertEquals(2, subject.getTable().getDatabase().getOperations().size());
+ assertTrue(subject.getTable().getDatabase().getOperations().get(0) instanceof AddColumnToDb);
+ assertTrue(subject.getTable().getDatabase().getOperations().get(1) instanceof SetValueForNullToDb);
+
+// AddColumnToDb op = (AddColumnToDb) subject.getTable().getDatabase().getOperations().get(0);
+// List<String> statements = op.createSql(node.getAdapter());
+// for (String statement : statements) {
+// assertTrue(statement.contains(" DEFAULT "));
+// }
+ }
+
+ public void testIsNew() {
+ MigrationTable table = db.alterTable("table");
+ subject = new MigrationColumnNew(table, "column", Types.INTEGER, 0, 0, 0, false, null);
+ assertTrue(subject.isNew());
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationDatabaseTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationDatabaseTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationDatabaseTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationDatabaseTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,107 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.merge.ArbitrarySqlToDb;
+import org.apache.cayenne.merge.CreateTableToDb;
+import org.apache.cayenne.merge.DropTableToDb;
+
+public class MigrationDatabaseTest extends TestCase {
+
+ private DataNode node;
+ private MigrationDatabase db;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+
+ db = new MigrationDatabase(node);
+ }
+
+ public void testAddOperation() {
+ assertEquals(0, db.getOperations().size());
+ db.addOperation(new ArbitrarySqlToDb("UPDATE x SET y=1"));
+ assertEquals(1, db.getOperations().size());
+ }
+
+ public void testCreateTable() {
+ db.createTable("table");
+ assertEquals(1, db.getOperations().size());
+ assertTrue(db.getOperations().get(0) instanceof CreateTableToDb);
+
+ CreateTableToDb operation = (CreateTableToDb) db.getOperations().get(0);
+ assertEquals("table", operation.getEntity().getName());
+ }
+
+ public void testAlterTable() {
+ MigrationTableExisting table = db.alterTable("table");
+ MigrationTableExisting table2 = db.alterTable("table");
+ assertTrue(table == table2);
+ }
+
+ public void testCantAlterNewTable() {
+ db.createTable("table");
+ try {
+ db.alterTable("table");
+ fail("Shouldn't be able to alter a new table.");
+ } catch (Exception e) {}
+ }
+
+ public void testCantCreateAnExistingTable() {
+ db.alterTable("table");
+ try {
+ db.createTable("table");
+ fail("Shouldn't be able to create an existing table.");
+ } catch (Exception e) {}
+ }
+
+ public void testDropTable() {
+ db.dropTable("table");
+ assertEquals(1, db.getOperations().size());
+ assertTrue(db.getOperations().get(0) instanceof DropTableToDb);
+
+ DropTableToDb operation = (DropTableToDb) db.getOperations().get(0);
+ assertEquals("table", operation.getEntity().getName());
+ }
+
+ public void testExecute() {
+ db.execute("UPDATE x SET y=1");
+
+ assertEquals(1, db.getOperations().size());
+ assertTrue(db.getOperations().get(0) instanceof ArbitrarySqlToDb);
+
+ ArbitrarySqlToDb operation = (ArbitrarySqlToDb) db.getOperations().get(0);
+ assertEquals("UPDATE x SET y=1", operation.getTokenValue());
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableExistingTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableExistingTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableExistingTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableExistingTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,165 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.sql.Types;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.merge.AddColumnToDb;
+import org.apache.cayenne.merge.AddRelationshipToDb;
+import org.apache.cayenne.merge.DropColumnToDb;
+import org.apache.cayenne.merge.DropRelationshipToDb;
+import org.apache.cayenne.merge.SetPrimaryKeyToDb;
+import org.apache.cayenne.merge.SetValueForNullToDb;
+
+public class MigrationTableExistingTest extends TestCase {
+
+ private DataNode node;
+ private MigrationDatabase db;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+
+ db = new MigrationDatabase(node);
+ }
+
+ public void testIsNew() {
+ MigrationTableExisting table = db.alterTable("table");
+ assertFalse(table.isNew());
+ }
+
+ public void testMigrationTableExisting() {
+ MigrationTableExisting table = db.alterTable("table");
+ assertEquals(0, table.getDatabase().getOperations().size());
+ }
+
+ public void testDropColumn() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.dropColumn("column");
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof DropColumnToDb);
+ }
+
+ public void testAddColumn() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.addColumn("column", Types.INTEGER);
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof AddColumnToDb);
+
+ AddColumnToDb operation = (AddColumnToDb) table.getDatabase().getOperations().get(0);
+ assertEquals("column", operation.getColumn().getName());
+ assertEquals(Types.INTEGER, operation.getColumn().getType());
+ assertEquals("table", operation.getColumn().getEntity().getName());
+ assertFalse(operation.getColumn().isMandatory());
+ }
+
+ public void testAddColumnWithDefault() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.addColumn("column", Types.INTEGER, true, 1);
+ assertEquals(2, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof AddColumnToDb);
+ assertTrue(table.getDatabase().getOperations().get(1) instanceof SetValueForNullToDb);
+
+ AddColumnToDb operation = (AddColumnToDb) table.getDatabase().getOperations().get(0);
+ assertEquals("column", operation.getColumn().getName());
+ assertEquals(Types.INTEGER, operation.getColumn().getType());
+ assertEquals("table", operation.getColumn().getEntity().getName());
+ assertTrue(operation.getColumn().isMandatory());
+ }
+
+ public void testAddPrimaryKey() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.addIntegerColumn("pk");
+ table.addPrimaryKey("pk");
+ assertEquals(2, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof AddColumnToDb);
+ assertTrue(table.getDatabase().getOperations().get(1) instanceof SetPrimaryKeyToDb);
+
+ DbAttribute pk = (DbAttribute) table.getEntity().getAttribute("pk");
+ assertTrue(pk.isPrimaryKey());
+ }
+
+ public void testAddForeignKey() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.addForeignKey("fk", "table2", "pk");
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof AddRelationshipToDb);
+
+ AddRelationshipToDb operation = (AddRelationshipToDb) table.getDatabase().getOperations().get(0);
+ DbRelationship relationship = operation.getRelationship();
+ assertEquals("table2", relationship.getTargetEntityName());
+ assertEquals("fk", relationship.getJoins().get(0).getSource().getName());
+ assertEquals("pk", relationship.getJoins().get(0).getTarget().getName());
+ }
+
+ public void testDropForeignKey() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.dropForeignKey("fk", "table2", "pk");
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof DropRelationshipToDb);
+ }
+
+ public void testAlterColumn() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column").addNotNullConstraint();
+
+ // ensure alterColumn can be called multiple times without error
+ table.alterColumn("column").setDefault(1);
+
+ assertEquals(1, table.getEntity().getAttributes().size());
+ assertEquals(2, table.getDatabase().getOperations().size());
+ }
+
+ public void testCantAlterNewColumn() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.addIntegerColumn("column");
+ try {
+ table.alterColumn("column");
+ fail("New columns should not be allowed to altered.");
+ } catch (Exception e) {
+ }
+ }
+
+ public void testCantCreateAnExistingColumn() {
+ MigrationTableExisting table = db.alterTable("table");
+ table.alterColumn("column");
+ try {
+ table.addIntegerColumn("column");
+ fail("Existing columns should not be allowed to created.");
+ } catch (Exception e) {
+ }
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableNewTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableNewTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableNewTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTableNewTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,114 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.sql.Types;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.map.DbAttribute;
+import org.apache.cayenne.map.DbRelationship;
+import org.apache.cayenne.merge.AddRelationshipToDb;
+import org.apache.cayenne.merge.CreateTableToDb;
+import org.apache.cayenne.merge.SetValueForNullToDb;
+
+public class MigrationTableNewTest extends TestCase {
+
+ private DataNode node;
+ private MigrationDatabase db;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+
+ db = new MigrationDatabase(node);
+ }
+
+ public void testMigrationTableNew() {
+ MigrationTableNew table = db.createTable("table");
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ }
+
+ public void testIsNew() {
+ MigrationTableNew table = db.createTable("table");
+ assertTrue(table.isNew());
+ }
+
+ public void testAddColumn() {
+ MigrationTableNew table = db.createTable("table");
+ table.addColumn("column", Types.INTEGER);
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ }
+
+ public void testAddColumnWithDefault() {
+ MigrationTableNew table = db.createTable("table");
+ table.addColumn("column", Types.INTEGER, true, 1);
+ assertEquals(2, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ assertTrue(table.getDatabase().getOperations().get(1) instanceof SetValueForNullToDb);
+
+// CreateTableToDb op = (CreateTableToDb) table.getDatabase().getOperations().get(0);
+// List<String> statements = op.createSql(node.getAdapter());
+// for (String statement : statements) {
+// if (statement.toUpperCase().startsWith("CREATE TABLE")) {
+// assertTrue(statement.contains(" DEFAULT "));
+// }
+// }
+ }
+
+ public void testAddPrimaryKey() {
+ MigrationTableNew table = db.createTable("table");
+ table.addIntegerColumn("pk");
+ table.addPrimaryKey("pk");
+
+ assertEquals(1, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ DbAttribute pk = (DbAttribute) table.getEntity().getAttribute("pk");
+ assertTrue(pk.isPrimaryKey());
+ }
+
+ public void testAddForeignKey() {
+ MigrationTableNew table = db.createTable("table");
+ table.addForeignKey("fk", "table2", "pk");
+
+ assertEquals(2, table.getDatabase().getOperations().size());
+ assertTrue(table.getDatabase().getOperations().get(0) instanceof CreateTableToDb);
+ assertTrue(table.getDatabase().getOperations().get(1) instanceof AddRelationshipToDb);
+
+ AddRelationshipToDb operation = (AddRelationshipToDb) table.getDatabase().getOperations().get(1);
+ DbRelationship relationship = operation.getRelationship();
+ assertEquals("table2", relationship.getTargetEntityName());
+ assertEquals("fk", relationship.getJoins().get(0).getSource().getName());
+ assertEquals("pk", relationship.getJoins().get(0).getTarget().getName());
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigrationTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,86 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.merge.ArbitrarySqlToDb;
+
+public class MigrationTest extends TestCase {
+
+ private DataNode node;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+ }
+
+ private static class MyMigration extends Migration {
+ public MyMigration(DataNode node) {
+ super(node);
+ }
+ @Override
+ public void upgrade(MigrationDatabase db) {}
+ }
+
+ public void testExecuteSqlStatement() {
+ MyMigration migration = new MyMigration(node);
+ migration.executeSqlStatement("UPDATE x SET y=1");
+
+ assertEquals(1, migration.getDatabase().getOperations().size());
+ assertTrue(migration.getDatabase().getOperations().get(0) instanceof ArbitrarySqlToDb);
+
+ ArbitrarySqlToDb operation = (ArbitrarySqlToDb) migration.getDatabase().getOperations().get(0);
+ assertEquals("UPDATE x SET y=1", operation.getTokenValue());
+ }
+
+ public void testLoadTextResource() {
+ try {
+ String sql = Migration.loadTextResource("testMigrationScript.sql", getClass());
+ assertEquals("UPDATE x SET y=1;", sql);
+ } catch (IOException e) {
+ fail(e.getMessage());
+ }
+ }
+
+ public void testExecuteSqlScript() {
+ MyMigration migration = new MyMigration(node);
+ migration.executeSqlScript("testMigrationScript.sql");
+
+ assertEquals(1, migration.getDatabase().getOperations().size());
+ assertTrue(migration.getDatabase().getOperations().get(0) instanceof ArbitrarySqlToDb);
+
+ ArbitrarySqlToDb operation = (ArbitrarySqlToDb) migration.getDatabase().getOperations().get(0);
+ assertEquals("UPDATE x SET y=1;", operation.getTokenValue());
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigratorTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigratorTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigratorTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MigratorTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,163 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.map.DataMap;
+
+// TODO: implement tests for Migrator - not sure how to connect to a real database
+public class MigratorTest extends TestCase {
+
+ private DataNode node;
+// private MockConnection connection;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+
+ DataMap map = new DataMap("MyMap");
+ node.addDataMap(map);
+
+// connection = new MockConnection();
+//
+// MockDataSource dataSource = new MockDataSource();
+// dataSource.setupConnection(connection);
+// node.setDataSource(dataSource);
+ }
+
+ public void testSomething() {
+ }
+
+//
+// public void testCreateMigrationClassForVersion() {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = new DataMap("MyMap");
+//
+// Migration migration0 = migrator.createMigrationClassForVersion(map, 0);
+// assertNotNull(migration0);
+// assertNotNull(migration0 instanceof MyMap0);
+// }
+//
+// public void testExecuteSqlWithUpdateCount() {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// try {
+// migrator.executeSqlWithUpdateCount("UPDATE x SET y=1");
+// } catch (SQLException e) {
+// fail(e.getMessage());
+// }
+// }
+//
+// public void testExecuteSqlWithUpdateCountList() {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// try {
+// migrator.executeSqlWithUpdateCount(Collections.singletonList("UPDATE x SET y=1"));
+// } catch (SQLException e) {
+// fail(e.getMessage());
+// }
+// }
+//
+// public void testExecuteSqlReturnInt() {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// try {
+// migrator.executeSqlReturnInt("SELECT y FROM x");
+// } catch (SQLException e) {
+// fail(e.getMessage());
+// }
+// }
+//
+// public void testExecuteOperations() {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// try {
+// MigrationDatabase db = new MigrationDatabase(node);
+// MigrationTable table = db.createTable("MyTable");
+// table.addIntegerColumn("pk");
+// table.addPrimaryKey("pk");
+// migrator.executeOperations(db.getOperations());
+// } catch (SQLException e) {
+// fail(e.getMessage());
+// }
+// }
+//
+// public void testCreateInternalMigrationSchema() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// migrator.createInternalMigrationSchema();
+// }
+//
+// public void testCurrentDbVersion() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = node.getDataMaps().iterator().next();
+// migrator.currentDbVersion(map);
+// }
+//
+// public void testSetDbVersion() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = node.getDataMaps().iterator().next();
+// migrator.setDbVersion(map, 0);
+// }
+//
+// public void testLock() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = node.getDataMaps().iterator().next();
+// migrator.lock(map);
+// }
+//
+// public void testLockTwiceFails() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = node.getDataMaps().iterator().next();
+// assertTrue(migrator.lock(map));
+// assertFalse(migrator.lock(map));
+// }
+//
+// public void testUnlock() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = node.getDataMaps().iterator().next();
+// migrator.lock(map);
+// migrator.unlock(map);
+// }
+//
+// public void testUnlockTwiceFails() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// DataMap map = node.getDataMaps().iterator().next();
+// migrator.lock(map);
+// migrator.unlock(map);
+// try {
+// migrator.unlock(map);
+// fail("Unlocking twice should fail");
+// } catch (Exception e) {}
+// }
+//
+// public void testMigrateToLatest() throws SQLException {
+// Migrator migrator = new Migrator(node, getClass().getPackage().getName());
+// migrator.migrateToLatest();
+// }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MyMap0.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MyMap0.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MyMap0.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/MyMap0.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,34 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import org.apache.cayenne.access.DataNode;
+
+
+class MyMap0 extends Migration {
+
+ public MyMap0(DataNode node) {
+ super(node);
+ }
+
+ @Override
+ public void upgrade(MigrationDatabase db) {
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/SqlFileMigrationTest.java
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/SqlFileMigrationTest.java?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/SqlFileMigrationTest.java (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/java/org/apache/cayenne/migration/SqlFileMigrationTest.java Fri Jun 15 16:58:25 2012
@@ -0,0 +1,87 @@
+/*****************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ ****************************************************************/
+package org.apache.cayenne.migration;
+
+import java.util.Collections;
+
+import junit.framework.TestCase;
+
+import org.apache.cayenne.access.DataNode;
+import org.apache.cayenne.configuration.DefaultRuntimeProperties;
+import org.apache.cayenne.configuration.RuntimeProperties;
+import org.apache.cayenne.dba.postgres.PostgresAdapter;
+import org.apache.cayenne.merge.ArbitrarySqlToDb;
+
+public class SqlFileMigrationTest extends TestCase {
+
+ private DataNode node;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ node = new DataNode("node");
+
+ RuntimeProperties props = new DefaultRuntimeProperties(Collections.EMPTY_MAP);
+ PostgresAdapter adapter = new PostgresAdapter(props, Collections.EMPTY_LIST, Collections.EMPTY_LIST, Collections.EMPTY_LIST);
+ node.setAdapter(adapter);
+ }
+
+ private static class Node0 extends SqlFileMigration {
+ public Node0(DataNode node) {
+ super(node);
+ }
+ }
+
+ private static class Node1 extends SqlFileMigration {
+ public Node1(DataNode node) {
+ super(node);
+ }
+ }
+
+ public void testDatabaseSpecificSqlFilename() {
+ Node0 migration = new Node0(node);
+ assertEquals("Node0-Postgres.sql", migration.databaseSpecificSqlFilename());
+ }
+
+ public void testGenericSqlFilename() {
+ Node0 migration = new Node0(node);
+ assertEquals("Node0.sql", migration.genericSqlFilename());
+ }
+
+ public void testSqlFilename() {
+ Node0 migration0 = new Node0(node);
+ assertEquals("Node0.sql", migration0.sqlFilename());
+
+ Node1 migration1 = new Node1(node);
+ assertEquals("Node1-Postgres.sql", migration1.sqlFilename());
+ }
+
+ public void testUpgrade() {
+ Node0 migration = new Node0(node);
+ migration.upgrade(migration.getDatabase());
+
+ assertEquals(1, migration.getDatabase().getOperations().size());
+ assertTrue(migration.getDatabase().getOperations().get(0) instanceof ArbitrarySqlToDb);
+
+ ArbitrarySqlToDb operation = (ArbitrarySqlToDb) migration.getDatabase().getOperations().get(0);
+ assertEquals("UPDATE x SET y=1;", operation.getTokenValue());
+ }
+
+}
Added: cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node0.sql
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node0.sql?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node0.sql (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node0.sql Fri Jun 15 16:58:25 2012
@@ -0,0 +1 @@
+UPDATE x SET y=1;
\ No newline at end of file
Added: cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node1-Postgres.sql
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node1-Postgres.sql?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node1-Postgres.sql (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/Node1-Postgres.sql Fri Jun 15 16:58:25 2012
@@ -0,0 +1 @@
+UPDATE x SET y=2;
\ No newline at end of file
Added: cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/testMigrationScript.sql
URL: http://svn.apache.org/viewvc/cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/testMigrationScript.sql?rev=1350693&view=auto
==============================================================================
--- cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/testMigrationScript.sql (added)
+++ cayenne/sandbox/cayenne-migrations/src/test/resources/org/apache/cayenne/migration/testMigrationScript.sql Fri Jun 15 16:58:25 2012
@@ -0,0 +1 @@
+UPDATE x SET y=1;
\ No newline at end of file