diff --git a/src/main/java/org/apache/ibatis/migration/Change.java b/src/main/java/org/apache/ibatis/migration/Change.java index d218e7e0..e78e3f3d 100644 --- a/src/main/java/org/apache/ibatis/migration/Change.java +++ b/src/main/java/org/apache/ibatis/migration/Change.java @@ -71,7 +71,12 @@ public void setFilename(String filename) { @Override public String toString() { - return id + " " + (appliedTimestamp == null ? " ...pending... " : appliedTimestamp) + " " + description; + return id + " " + (isPending() ? " ...pending... " : appliedTimestamp) + " " + description; + } + + public boolean isPending() + { + return appliedTimestamp == null; } @Override diff --git a/src/main/java/org/apache/ibatis/migration/commands/ScriptCommand.java b/src/main/java/org/apache/ibatis/migration/commands/ScriptCommand.java index 4baeb554..2f7fbac9 100644 --- a/src/main/java/org/apache/ibatis/migration/commands/ScriptCommand.java +++ b/src/main/java/org/apache/ibatis/migration/commands/ScriptCommand.java @@ -26,6 +26,7 @@ import org.apache.ibatis.migration.Change; import org.apache.ibatis.migration.MigrationException; import org.apache.ibatis.migration.operations.DatabaseOperation; +import org.apache.ibatis.migration.operations.StatusOperation; import org.apache.ibatis.migration.options.SelectedOptions; public final class ScriptCommand extends BaseCommand { @@ -41,23 +42,44 @@ public void execute(String... sparams) { throw new MigrationException("The script command requires a range of versions from v1 - v2."); } StringTokenizer parser = new StringTokenizer(sparams[0]); - if (parser.countTokens() != 2) { + int tokenCount = parser.countTokens(); + boolean scriptPending = false; + boolean scriptPendingUndo = false; + + String firstToken = parser.nextToken(); + + if(tokenCount == 1 && firstToken.equals("pending")){ + scriptPending = true; + } else if(tokenCount == 1 && firstToken.equals("pending_undo")) { + scriptPendingUndo = true; + } + + else if (!scriptPending&& !scriptPendingUndo && tokenCount != 2) { throw new MigrationException("The script command requires a range of versions from v1 - v2."); } - BigDecimal v1 = new BigDecimal(parser.nextToken()); - BigDecimal v2 = new BigDecimal(parser.nextToken()); - int comparison = v1.compareTo(v2); - if (comparison == 0) { - throw new MigrationException("The script command requires two different versions. Use 0 to include the first version."); + + BigDecimal v1 = (scriptPending || scriptPendingUndo) ? null : new BigDecimal(firstToken); + BigDecimal v2 = (scriptPending || scriptPendingUndo) ? null :new BigDecimal(parser.nextToken()); + + boolean undo; + undo = scriptPendingUndo; + if(!scriptPending && !scriptPendingUndo) { + int comparison = v1.compareTo(v2); + if (comparison == 0) { + throw new MigrationException("The script command requires two different versions. Use 0 to include the first version."); + } + undo = comparison > 0; } - boolean undo = comparison > 0; - List migrations = getMigrationLoader().getMigrations(); + + List migrations = (scriptPending || scriptPendingUndo) ? + new StatusOperation().operate(getConnectionProvider(), getMigrationLoader(), getDatabaseOperationOption(), null).getCurrentStatus() : + getMigrationLoader().getMigrations(); Collections.sort(migrations); if (undo) { Collections.reverse(migrations); } for (Change change : migrations) { - if (shouldRun(change, v1, v2)) { + if (shouldRun(change, v1, v2, scriptPending || scriptPendingUndo)) { printStream.println("-- " + change.getFilename()); Reader migrationReader = getMigrationLoader().getScriptReader(change, undo); char[] cbuf = new char[1024]; @@ -91,12 +113,17 @@ private String generateVersionDelete(Change change) { return "DELETE FROM " + changelogTable() + " WHERE ID = " + change.getId() + getDelimiter(); } - private boolean shouldRun(Change change, BigDecimal v1, BigDecimal v2) { - BigDecimal id = change.getId(); - if (v1.compareTo(v2) > 0) { - return (id.compareTo(v2) > 0 && id.compareTo(v1) <= 0); - } else { - return (id.compareTo(v1) > 0 && id.compareTo(v2) <= 0); + private boolean shouldRun(Change change, BigDecimal v1, BigDecimal v2, boolean pendingOnly) { + if(!pendingOnly) { + BigDecimal id = change.getId(); + if (v1.compareTo(v2) > 0) { + return (id.compareTo(v2) > 0 && id.compareTo(v1) <= 0); + } else { + return (id.compareTo(v1) > 0 && id.compareTo(v2) <= 0); + } + } + else { + return change.isPending(); } } diff --git a/src/test/java/org/apache/ibatis/migration/MigratorTest.java b/src/test/java/org/apache/ibatis/migration/MigratorTest.java index fbb0b25c..36f4fb70 100644 --- a/src/test/java/org/apache/ibatis/migration/MigratorTest.java +++ b/src/test/java/org/apache/ibatis/migration/MigratorTest.java @@ -31,6 +31,7 @@ import java.net.URL; import java.security.Permission; import java.sql.Connection; +import java.sql.DriverManager; import java.sql.SQLException; import java.util.Map; import java.util.Properties; @@ -86,10 +87,28 @@ public void checkExit(int status) { @AfterClass public static void teardown() { + + System.setOut(out); System.setSecurityManager(null); } + private void testDoPendingScriptCommand(File f) throws Exception + { + + safeMigratorMain(args("--path=" + f.getAbsolutePath(), "script", "pending")); + assertTrue(buffer.toString().contains("INSERT")); + assertTrue(buffer.toString().contains("CHANGELOG")); + assertFalse(buffer.toString().contains("-- @UNDO")); + buffer.clear(); + + safeMigratorMain(args("--path=" + f.getAbsolutePath(), "script", "pending_undo")); + assertTrue(buffer.toString().contains("DELETE")); + assertTrue(buffer.toString().contains("CHANGELOG")); + assertTrue(buffer.toString().contains("-- @UNDO")); + buffer.clear(); + } + @Test public void shouldRunThroughFullMigrationUseCaseInOneTestToEnsureOrder() throws Throwable { try { @@ -107,6 +126,9 @@ public void shouldRunThroughFullMigrationUseCaseInOneTestToEnsureOrder() throws testStatusContainsNoPendingMigrations(f); testDownCommandGiven2Steps(f); testStatusContainsPendingMigrations(f); + + testDoPendingScriptCommand(f); + testVersionCommand(f); testStatusContainsNoPendingMigrations(f); testDownCommand(f);