Skip to content

Commit

Permalink
Add hooks for script command
Browse files Browse the repository at this point in the history
  • Loading branch information
harawata committed Dec 7, 2021
1 parent faefef8 commit 79c122f
Show file tree
Hide file tree
Showing 13 changed files with 565 additions and 17 deletions.
32 changes: 31 additions & 1 deletion src/main/java/org/apache/ibatis/migration/Environment.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,11 @@ private enum SETTING_KEY {
hook_after_each_down,
hook_after_down,
hook_before_new,
hook_after_new
hook_after_new,
hook_before_script,
hook_before_each_script,
hook_after_each_script,
hook_after_script
}

private static final List<String> SETTING_KEYS;
Expand Down Expand Up @@ -95,6 +99,11 @@ private enum SETTING_KEY {
private final String hookBeforeNew;
private final String hookAfterNew;

private final String hookBeforeScript;
private final String hookBeforeEachScript;
private final String hookAfterEachScript;
private final String hookAfterScript;

/**
* Prefix used to lookup environment variable or system property.
*/
Expand Down Expand Up @@ -135,6 +144,11 @@ public Environment(File file) {
this.hookBeforeNew = readProperty(prop, SETTING_KEY.hook_before_new.name());
this.hookAfterNew = readProperty(prop, SETTING_KEY.hook_after_new.name());

this.hookBeforeScript = readProperty(prop, SETTING_KEY.hook_before_script.name());
this.hookBeforeEachScript = readProperty(prop, SETTING_KEY.hook_before_each_script.name());
this.hookAfterEachScript = readProperty(prop, SETTING_KEY.hook_after_each_script.name());
this.hookAfterScript = readProperty(prop, SETTING_KEY.hook_after_script.name());

// User defined variables.
prop.entrySet().stream().filter(e -> !SETTING_KEYS.contains(e.getKey()))
.forEach(e -> variables.put(e.getKey(), parser.replace((String) e.getValue())));
Expand Down Expand Up @@ -273,6 +287,22 @@ public String getHookAfterNew() {
return hookAfterNew;
}

public String getHookBeforeScript() {
return hookBeforeScript;
}

public String getHookBeforeEachScript() {
return hookBeforeEachScript;
}

public String getHookAfterEachScript() {
return hookAfterEachScript;
}

public String getHookAfterScript() {
return hookAfterScript;
}

public Properties getVariables() {
return variables;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.apache.ibatis.migration.Change;
import org.apache.ibatis.migration.MigrationException;
import org.apache.ibatis.migration.hook.MigrationHook;
import org.apache.ibatis.migration.hook.ScriptHookContext;
import org.apache.ibatis.migration.operations.DatabaseOperation;
import org.apache.ibatis.migration.operations.StatusOperation;
import org.apache.ibatis.migration.options.SelectedOptions;
Expand Down Expand Up @@ -70,23 +74,37 @@ public void execute(String... sparams) {
undo = comparison > 0;
}

Map<String, Object> hookBindings = new HashMap<>();
MigrationHook hook = createScriptHook();
List<Change> migrations = (scriptPending || scriptPendingUndo) ? new StatusOperation()
.operate(getConnectionProvider(), getMigrationLoader(), getDatabaseOperationOption(), null).getCurrentStatus()
: getMigrationLoader().getMigrations();
Collections.sort(migrations);
if (undo) {
Collections.reverse(migrations);
}
int count = 0;
for (int i = 0; i < migrations.size(); i++) {
Change change = migrations.get(i);
if (shouldRun(change, v1, v2, scriptPending || scriptPendingUndo)) {
if (count == 0 && hook != null) {
hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(null, undo));
hook.before(hookBindings);
printStream.println();
}
if (hook != null) {
hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(change.clone(), undo));
hook.beforeEach(hookBindings);
printStream.println();
}
printStream.println("-- " + change.getFilename());
Reader migrationReader = getMigrationLoader().getScriptReader(change, undo);
char[] cbuf = new char[1024];
int l;
while ((l = migrationReader.read(cbuf)) > -1) {
printStream.print(l == cbuf.length ? cbuf : Arrays.copyOf(cbuf, l));
}
count++;
printStream.println();
printStream.println();
if (!undo) {
Expand All @@ -95,8 +113,18 @@ public void execute(String... sparams) {
printStream.println(generateVersionDelete(change));
}
printStream.println();
if (hook != null) {
hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(change.clone(), undo));
hook.afterEach(hookBindings);
printStream.println();
}
}
}
if (count > 0 && hook != null) {
hookBindings.put(MigrationHook.HOOK_CONTEXT, new ScriptHookContext(null, undo));
hook.after(hookBindings);
printStream.println();
}
} catch (IOException e) {
throw new MigrationException("Error generating script. Cause: " + e, e);
}
Expand Down Expand Up @@ -135,4 +163,14 @@ private String getDelimiter() {
return delimiter.toString();
}

private MigrationHook createScriptHook() {
String before = environment().getHookBeforeScript();
String beforeEach = environment().getHookBeforeEachScript();
String afterEach = environment().getHookAfterEachScript();
String after = environment().getHookAfterScript();
if (before == null && beforeEach == null && afterEach == null && after == null) {
return null;
}
return createFileMigrationHook(before, beforeEach, afterEach, after);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright 2010-2021 the original author or authors.
*
* Licensed 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.ibatis.migration.hook;

import org.apache.ibatis.migration.Change;

/**
* Hook context object that is available to <code>before_new</code> and <code>after_new</code> hooks.
*/
public class ScriptHookContext {
private final Change change;
private final boolean undo;

public ScriptHookContext(Change change, boolean undo) {
super();
this.change = change;
this.undo = undo;
}

public Change getChange() {
return change;
}

public boolean isUndo() {
return undo;
}
}
28 changes: 12 additions & 16 deletions src/site/xdoc/hooks.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2010-2018 the original author or authors.
Copyright 2010-2021 the original author or authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -37,17 +37,6 @@

<p>
You can write scripts that are executed before or after up/down operation.<br />
The following hooks are supported.
</p>

<ul>
<li>before up/down : executed before the first migration</li>
<li>before each up/down : executed before each migration</li>
<li>after each up/down : executed after each migration</li>
<li>after up/down : executed after the last migration</li>
</ul>

<p>
Hook scripts can be written in <b>SQL</b> or <b>JSR-223</b> compliannt script languages.
</p>

Expand Down Expand Up @@ -127,10 +116,16 @@ Hello, World!]]></source>
<li>hook_before_each_down</li>
<li>hook_after_each_down</li>
<li>hook_after_down</li>
<li>hook_before_new (since 3.3.5)</li>
<li>hook_after_new (since 3.3.5)</li>
<li>hook_before_new [1] (since 3.3.5)</li>
<li>hook_after_new [1] (since 3.3.5)</li>
<li>hook_before_script [1] (since 3.3.10)</li>
<li>hook_before_each_script [1] (since 3.3.10)</li>
<li>hook_after_each_script [1] (since 3.3.10)</li>
<li>hook_after_script [1] (since 3.3.10)</li>
</ul>

<p>[1] Only JSR-223 script is supported.</p>

<h4>Minimum setting : language and file name</h4>

<p>
Expand Down Expand Up @@ -209,8 +204,9 @@ print(migrationPaths.getHookPath());]]></source>
</p>

<ul>
<li>For hooks except before_new and after_new, it is an instance of <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/HookContext.html" target="_blank">HookContext</a>.</li>
<li>For before_new and after_new hooks, it will be <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/NewHookContext.html" target="_blank">NewHookContext</a>.</li>
<li>For <code>up</code> and <code>down</code> hooks, <code>hookConte</code> is an instance of <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/HookContext.html" target="_blank">HookContext</a>.</li>
<li>For <code>new</code> hooks, <code>hookContext</code> is an instance of <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/NewHookContext.html" target="_blank">NewHookContext</a>.</li>
<li>For <code>script</code> hooks, <code>hookContext</code> is an instance of <a href="/migrations/apidocs/org/apache/ibatis/migration/hook/ScriptHookContext.html" target="_blank">ScriptHookContext</a>.</li>
</ul>

<h4>Accessing <i>Change</i> object (in each hook only)</h4>
Expand Down
Loading

0 comments on commit 79c122f

Please sign in to comment.