Author: tomdz Date: Thu Sep 13 23:26:00 2007 New Revision: 575556 URL: http://svn.apache.org/viewvc?rev=575556&view=rev Log: Added onUpdate tests
Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java db/ddlutils/trunk/src/test/org/apache/ddlutils/io/RoundtripTestBase.java db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestConstraints.java Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java?rev=575556&r1=575555&r2=575556&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/Platform.java Thu Sep 13 23:26:00 2007 @@ -841,6 +841,27 @@ public void update(Connection connection, Database model, DynaBean dynaBean) throws DatabaseOperationException; /** + * Updates the row identified by the given <code>oldDynaBean</code> in the database with the + * values in <code>newDynaBean</code>. + * + * @param model The database model to use + * @param oldDynaBean The bean identifying the row (which means the primary key fields need to be specified) + * @param newDynaBean The bean containing the new data + */ + public void update(Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException; + + /** + * Updates the row identified by the given <code>oldDynaBean</code> in the database with the + * values in <code>newDynaBean</code>. + * + * @param connection The database connection + * @param model The database model to use + * @param oldDynaBean The bean identifying the row (which means the primary key fields need to be specified) + * @param newDynaBean The bean containing the new data + */ + public void update(Connection connection, Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException; + + /** * Returns the sql for deleting the given bean from the database. * * @param model The database model to use Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java?rev=575556&r1=575555&r2=575556&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java Thu Sep 13 23:26:00 2007 @@ -1618,6 +1618,87 @@ /** * [EMAIL PROTECTED] */ + public void update(Connection connection, Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException + { + SqlDynaClass dynaClass = model.getDynaClassFor(oldDynaBean); + SqlDynaProperty[] primaryKeys = dynaClass.getPrimaryKeyProperties(); + + if (!dynaClass.getTable().equals(model.getDynaClassFor(newDynaBean))) + { + throw new DatabaseOperationException("The old and new dyna beans need to be for the same table"); + } + if (primaryKeys.length == 0) + { + _log.info("Cannot update instances of type " + dynaClass + " because it has no primary keys"); + return; + } + + SqlDynaProperty[] properties = dynaClass.getSqlDynaProperties(); + String sql = createUpdateSql(model, dynaClass, primaryKeys, properties, null); + PreparedStatement statement = null; + + if (_log.isDebugEnabled()) + { + _log.debug("About to execute SQL: " + sql); + } + try + { + beforeUpdate(connection, dynaClass.getTable()); + + statement = connection.prepareStatement(sql); + + int sqlIndex = 1; + + for (int idx = 0; idx < properties.length; idx++) + { + setObject(statement, sqlIndex++, newDynaBean, properties[idx]); + } + for (int idx = 0; idx < primaryKeys.length; idx++) + { + setObject(statement, sqlIndex++, oldDynaBean, primaryKeys[idx]); + } + + int count = statement.executeUpdate(); + + afterUpdate(connection, dynaClass.getTable()); + + if (count != 1) + { + _log.warn("Attempted to insert a single row " + newDynaBean + + " into table " + dynaClass.getTableName() + + " but changed " + count + " row(s)"); + } + } + catch (SQLException ex) + { + throw new DatabaseOperationException("Error while updating in the database", ex); + } + finally + { + closeStatement(statement); + } + } + + /** + * [EMAIL PROTECTED] + */ + public void update(Database model, DynaBean oldDynaBean, DynaBean newDynaBean) throws DatabaseOperationException + { + Connection connection = borrowConnection(); + + try + { + update(connection, model, oldDynaBean, newDynaBean); + } + finally + { + returnConnection(connection); + } + } + + /** + * [EMAIL PROTECTED] + */ public void update(Connection connection, Database model, DynaBean dynaBean) throws DatabaseOperationException { SqlDynaClass dynaClass = model.getDynaClassFor(dynaBean); Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java?rev=575556&r1=575555&r2=575556&view=diff ============================================================================== --- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java (original) +++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/SqlBuilder.java Thu Sep 13 23:26:00 2007 @@ -1526,6 +1526,25 @@ */ public String getUpdateSql(Table table, Map columnValues, boolean genPlaceholders) { + return getUpdateSql(table, columnValues, columnValues, genPlaceholders); + } + + /** + * Creates the SQL for updating an object in the specified table. + * If values are given then a concrete update statement is created, otherwise an + * update statement usable in a prepared statement is build. + * + * @param table The table + * @param oldColumnValues Contains the column values to identify the row to update + * @param columnValues Contains the values for the columns to update, and should also + * contain the primary key values to identify the object to update + * in case <code>genPlaceholders</code> is <code>false</code> + * @param genPlaceholders Whether to generate value placeholders for a + * prepared statement (both for the pk values and the object values) + * @return The update sql + */ + public String getUpdateSql(Table table, Map oldColumnValues, Map newColumnValues, boolean genPlaceholders) + { StringBuffer buffer = new StringBuffer("UPDATE "); boolean addSep = false; @@ -1536,7 +1555,7 @@ { Column column = table.getColumn(idx); - if (!column.isPrimaryKey() && columnValues.containsKey(column.getName())) + if (!column.isPrimaryKey() && newColumnValues.containsKey(column.getName())) { if (addSep) { @@ -1550,7 +1569,7 @@ } else { - buffer.append(getValueAsString(column, columnValues.get(column.getName()))); + buffer.append(getValueAsString(column, newColumnValues.get(column.getName()))); } addSep = true; } @@ -1561,7 +1580,7 @@ { Column column = table.getColumn(idx); - if (column.isPrimaryKey() && columnValues.containsKey(column.getName())) + if (column.isPrimaryKey() && oldColumnValues.containsKey(column.getName())) { if (addSep) { @@ -1575,7 +1594,7 @@ } else { - buffer.append(getValueAsString(column, columnValues.get(column.getName()))); + buffer.append(getValueAsString(column, oldColumnValues.get(column.getName()))); } addSep = true; } Modified: db/ddlutils/trunk/src/test/org/apache/ddlutils/io/RoundtripTestBase.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/test/org/apache/ddlutils/io/RoundtripTestBase.java?rev=575556&r1=575555&r2=575556&view=diff ============================================================================== --- db/ddlutils/trunk/src/test/org/apache/ddlutils/io/RoundtripTestBase.java (original) +++ db/ddlutils/trunk/src/test/org/apache/ddlutils/io/RoundtripTestBase.java Thu Sep 13 23:26:00 2007 @@ -151,6 +151,26 @@ getPlatform().insert(getModel(), bean); } + /** + * Updates the row in the designated table. + * + * @param tableName The name of the table (case insensitive) + * @param oldBean The bean representing the current row + * @param columnValues The values for the columns in order of definition + */ + protected void updateRow(String tableName, DynaBean oldBean, Object[] columnValues) + { + Table table = getModel().findTable(tableName); + DynaBean bean = getModel().createDynaBeanFor(table); + + for (int idx = 0; (idx < table.getColumnCount()) && (idx < columnValues.length); idx++) + { + Column column = table.getColumn(idx); + + bean.set(column.getName(), columnValues[idx]); + } + getPlatform().update(getModel(), oldBean, bean); + } /** * Deletes the specified row from the table. Modified: db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestConstraints.java URL: http://svn.apache.org/viewvc/db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestConstraints.java?rev=575556&r1=575555&r2=575556&view=diff ============================================================================== --- db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestConstraints.java (original) +++ db/ddlutils/trunk/src/test/org/apache/ddlutils/io/TestConstraints.java Thu Sep 13 23:26:00 2007 @@ -21,7 +21,9 @@ import java.util.List; +import org.apache.commons.beanutils.DynaBean; import org.apache.commons.lang.StringUtils; +import org.apache.ddlutils.DdlUtilsException; import org.apache.ddlutils.model.Database; import org.apache.ddlutils.platform.sybase.SybasePlatform; @@ -463,6 +465,26 @@ "</database>"; performConstraintsTest(modelXml, true); + + insertRow("roundtrip_1", new Object[] { new Integer(1) }); + insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) }); + + List beansTable1 = getRows("roundtrip_1"); + List beansTable2 = getRows("roundtrip_2"); + + assertEquals(1, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(1), beansTable1.get(0), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(1), beansTable2.get(0), "avalue"); + + try + { + deleteRow("roundtrip_1", new Object[] { new Integer(1) }); + fail(); + } + catch (DdlUtilsException ex) + {} } /** @@ -598,6 +620,193 @@ assertEquals(1, beansTable2.size()); assertEquals(new Integer(5), beansTable2.get(0), "pk"); assertEquals(new Integer(0), beansTable2.get(0), "avalue"); + } + } + + /** + * Tests two tables with a foreign key with a restrict onUpdate action. + */ + public void testForeignKeyWithOnUpdateRestrict() + { + final String modelXml = + "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+ + "<database name='roundtriptest'>\n"+ + " <table name='roundtrip_1'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " </table>\n"+ + " <table name='roundtrip_2'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " <column name='avalue' type='INTEGER' required='true'/>\n"+ + " <foreign-key foreignTable='roundtrip_1' onUpdate='restrict'>\n"+ + " <reference local='avalue' foreign='pk'/>\n"+ + " </foreign-key>\n"+ + " </table>\n"+ + "</database>"; + + performConstraintsTest(modelXml, true); + + insertRow("roundtrip_1", new Object[] { new Integer(1) }); + insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) }); + + List beansTable1 = getRows("roundtrip_1"); + List beansTable2 = getRows("roundtrip_2"); + + assertEquals(1, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(1), beansTable1.get(0), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(1), beansTable2.get(0), "avalue"); + + try + { + updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(5) }); + fail(); + } + catch (DdlUtilsException ex) + {} + } + + /** + * Tests two tables with a foreign key with a cascade onUpdate action. + */ + public void testForeignKeyWithOnUpdateCascade() + { + final String modelXml = + "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+ + "<database name='roundtriptest'>\n"+ + " <table name='roundtrip_1'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " </table>\n"+ + " <table name='roundtrip_2'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " <column name='avalue' type='INTEGER' required='true'/>\n"+ + " <foreign-key foreignTable='roundtrip_1' onUpdate='cascade'>\n"+ + " <reference local='avalue' foreign='pk'/>\n"+ + " </foreign-key>\n"+ + " </table>\n"+ + "</database>"; + + performConstraintsTest(modelXml, true); + + insertRow("roundtrip_1", new Object[] { new Integer(1) }); + insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) }); + + List beansTable1 = getRows("roundtrip_1"); + List beansTable2 = getRows("roundtrip_2"); + + assertEquals(1, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(1), beansTable1.get(0), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(1), beansTable2.get(0), "avalue"); + + updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(2) }); + + beansTable1 = getRows("roundtrip_1"); + beansTable2 = getRows("roundtrip_2"); + + assertEquals(1, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(2), beansTable1.get(0), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(2), beansTable2.get(0), "avalue"); + } + + /** + * Tests two tables with a foreign key with a set-null onUpdate action. + */ + public void testForeignKeyWithOnUpdateSetNull() + { + final String modelXml = + "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+ + "<database name='roundtriptest'>\n"+ + " <table name='roundtrip_1'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " </table>\n"+ + " <table name='roundtrip_2'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " <column name='avalue' type='INTEGER' required='false'/>\n"+ + " <foreign-key foreignTable='roundtrip_1' onUpdate='setnull'>\n"+ + " <reference local='avalue' foreign='pk'/>\n"+ + " </foreign-key>\n"+ + " </table>\n"+ + "</database>"; + + performConstraintsTest(modelXml, true); + + insertRow("roundtrip_1", new Object[] { new Integer(1) }); + insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) }); + + List beansTable1 = getRows("roundtrip_1"); + List beansTable2 = getRows("roundtrip_2"); + + assertEquals(1, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(1), beansTable1.get(0), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(1), beansTable2.get(0), "avalue"); + + updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(2) }); + + beansTable1 = getRows("roundtrip_1"); + beansTable2 = getRows("roundtrip_2"); + + assertEquals(1, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(2), beansTable1.get(0), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals((Object)null, beansTable2.get(0), "avalue"); + } + + /** + * Tests two tables with a foreign key with a det-default onUpdate action. + */ + public void testForeignKeyWithOnUpdateSetDefault() + { + if (getPlatformInfo().isSetDefaultActionSupported()) + { + final String modelXml = + "<?xml version='1.0' encoding='ISO-8859-1'?>\n"+ + "<database name='roundtriptest'>\n"+ + " <table name='roundtrip_1'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " </table>\n"+ + " <table name='roundtrip_2'>\n"+ + " <column name='pk' type='INTEGER' primaryKey='true' required='true'/>\n"+ + " <column name='avalue' type='INTEGER' required='false' default='2'/>\n"+ + " <foreign-key foreignTable='roundtrip_1' onUpdate='setdefault'>\n"+ + " <reference local='avalue' foreign='pk'/>\n"+ + " </foreign-key>\n"+ + " </table>\n"+ + "</database>"; + + performConstraintsTest(modelXml, true); + + insertRow("roundtrip_1", new Object[] { new Integer(1) }); + insertRow("roundtrip_1", new Object[] { new Integer(2) }); + insertRow("roundtrip_2", new Object[] { new Integer(5), new Integer(1) }); + + List beansTable1 = getRows("roundtrip_1"); + List beansTable2 = getRows("roundtrip_2"); + + assertEquals(2, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(1), beansTable1.get(0), "pk"); + assertEquals(new Integer(2), beansTable1.get(1), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(1), beansTable2.get(0), "avalue"); + + updateRow("roundtrip_1", (DynaBean)beansTable1.get(0), new Object[] { new Integer(0) }); + + beansTable1 = getRows("roundtrip_1"); + beansTable2 = getRows("roundtrip_2"); + + assertEquals(2, beansTable1.size()); + assertEquals(1, beansTable2.size()); + assertEquals(new Integer(0), beansTable1.get(0), "pk"); + assertEquals(new Integer(2), beansTable1.get(1), "pk"); + assertEquals(new Integer(5), beansTable2.get(0), "pk"); + assertEquals(new Integer(2), beansTable2.get(0), "avalue"); } } }