diff --git a/src/main/java/io/ebean/EbeanServer.java b/src/main/java/io/ebean/EbeanServer.java
index aad3eb6d9..face93fa3 100644
--- a/src/main/java/io/ebean/EbeanServer.java
+++ b/src/main/java/io/ebean/EbeanServer.java
@@ -1442,6 +1442,13 @@ public interface EbeanServer {
*/
JsonContext json();
+ /**
+ * Return a ScriptRunner for running SQL or DDL scripts.
+ *
+ * Intended to use mostly in testing to run seed SQL scripts or truncate table scripts etc.
+ */
+ ScriptRunner script();
+
/**
* Return the Document store.
*/
diff --git a/src/main/java/io/ebean/ScriptRunner.java b/src/main/java/io/ebean/ScriptRunner.java
new file mode 100644
index 000000000..b9130d57b
--- /dev/null
+++ b/src/main/java/io/ebean/ScriptRunner.java
@@ -0,0 +1,65 @@
+package io.ebean;
+
+import java.net.URL;
+import java.util.Map;
+
+/**
+ * Runs DDL and SQL scripts.
+ *
+ * Typically these are scripts used for testing such as seed SQL scripts or truncate SQL scripts.
+ *
+ * Scripts are executed in their own transaction and committed on successful completion.
+ *
+ * Example of simple use
+ * {@code
+ *
+ * EbeanServer server = Ebean.getDefaultServer();
+ * server.script().run("/scripts/test-script.sql");
+ *
+ * }
+ *
+ *
+ * Example using place holders in the script
+ * {@code
+ *
+ * Map placeholders = new HashMap<>();
+ * placeholders.put("tableName", "e_basic");
+ *
+ * EbeanServer server = Ebean.getDefaultServer();
+ * server.script().run("/scripts/test-script.sql");
+ *
+ * }
+ */
+public interface ScriptRunner {
+
+ /**
+ * Run a script given the resource path (that should start with "/").
+ */
+ void run(String path);
+
+ /**
+ * Run a script given the resource path (that should start with "/") and place holders.
+ *
+ * {@code
+ *
+ * Map placeholders = new HashMap<>();
+ * placeholders.put("tableName", "e_basic");
+ *
+ * EbeanServer server = Ebean.getDefaultServer();
+ * server.script().run("/scripts/test-script.sql");
+ *
+ * }
+ */
+ void run(String path, Map placeholderMap);
+
+ /**
+ * Run a DDL or SQL script given the resource.
+ */
+ void run(URL resource);
+
+ /**
+ * Run a DDL or SQL script given the resource and place holders.
+ */
+ void run(URL resource, Map placeholderMap);
+
+}
diff --git a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
index 8230bc65b..fa0b662cf 100644
--- a/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
+++ b/src/main/java/io/ebeaninternal/dbmigration/DdlGenerator.java
@@ -348,7 +348,6 @@ public class DdlGenerator {
buf.append(s).append("\n");
}
return buf.toString();
-
}
}
diff --git a/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java b/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java
new file mode 100644
index 000000000..cefe9f22a
--- /dev/null
+++ b/src/main/java/io/ebeaninternal/server/core/DScriptRunner.java
@@ -0,0 +1,116 @@
+package io.ebeaninternal.server.core;
+
+import io.ebean.ScriptRunner;
+import io.ebean.migration.ddl.DdlRunner;
+import io.ebean.migration.runner.ScriptTransform;
+import io.ebeaninternal.api.SpiEbeanServer;
+
+import javax.persistence.PersistenceException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+import java.io.Reader;
+import java.net.URL;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.Map;
+
+class DScriptRunner implements ScriptRunner {
+
+ private static final String NEWLINE = "\n";
+
+ private final SpiEbeanServer server;
+
+ DScriptRunner(SpiEbeanServer server) {
+ this.server = server;
+ }
+
+ @Override
+ public void run(String path) {
+ run(path, null);
+ }
+
+ @Override
+ public void run(String path, Map placeholderMap) {
+ run(this.getClass().getResource(path), path, placeholderMap);
+ }
+
+ @Override
+ public void run(URL resource) {
+ run(resource, null, null);
+ }
+
+ @Override
+ public void run(URL resource, Map placeholderMap) {
+ run(resource, null, placeholderMap);
+ }
+
+ private void run(URL resource, String scriptName, Map placeholderMap) {
+ if (resource == null) {
+ throw new IllegalArgumentException("resource is null?");
+ }
+ if (scriptName == null) {
+ scriptName = resource.getFile();
+ }
+
+ String content = content(resource);
+ runScript(content, scriptName, placeholderMap);
+ }
+
+ private String content(URL resource) {
+ if (resource == null) {
+ throw new IllegalArgumentException("resource is null?");
+ }
+
+ try (InputStream inputStream = resource.openStream()) {
+ return readContent(new InputStreamReader(inputStream));
+
+ } catch (IOException e) {
+ throw new PersistenceException("Failed to read script content", e);
+ }
+ }
+
+
+ /**
+ * Execute all the DDL statements in the script.
+ */
+ private void runScript(String content, String scriptName, Map placeholderMap) {
+
+ try {
+ if (placeholderMap != null) {
+ content = ScriptTransform.build(null, placeholderMap).transform(content);
+ }
+
+ try (Connection connection = obtainConnection()) {
+ DdlRunner runner = new DdlRunner(false, scriptName);
+ runner.runAll(content, connection);
+ connection.commit();
+ }
+
+ } catch (SQLException e) {
+ throw new PersistenceException("Failed to run script", e);
+ }
+ }
+
+ private Connection obtainConnection() {
+ try {
+ return server.getPluginApi().getDataSource().getConnection();
+ } catch (SQLException e) {
+ throw new PersistenceException("Failed to obtain connection to run script", e);
+ }
+ }
+
+ private String readContent(Reader reader) throws IOException {
+
+ StringBuilder buf = new StringBuilder();
+ try (LineNumberReader lineReader = new LineNumberReader(reader)) {
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ buf.append(line).append(NEWLINE);
+ }
+ return buf.toString();
+ }
+ }
+
+}
diff --git a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
index df991c343..1872c0f5b 100644
--- a/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
+++ b/src/main/java/io/ebeaninternal/server/core/DefaultServer.java
@@ -22,6 +22,7 @@ import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.RowConsumer;
import io.ebean.RowMapper;
+import io.ebean.ScriptRunner;
import io.ebean.SqlQuery;
import io.ebean.SqlRow;
import io.ebean.SqlUpdate;
@@ -185,6 +186,8 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
private final DdlGenerator ddlGenerator;
+ private final ScriptRunner scriptRunner;
+
private final ExpressionFactory expressionFactory;
private final SpiBackgroundExecutor backgroundExecutor;
@@ -291,6 +294,7 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
this.serverPlugins = config.getPlugins();
this.ddlGenerator = new DdlGenerator(this, serverConfig);
+ this.scriptRunner = new DScriptRunner(this);
configureServerPlugins();
@@ -370,6 +374,11 @@ public final class DefaultServer implements SpiServer, SpiEbeanServer {
return databasePlatform;
}
+ @Override
+ public ScriptRunner script() {
+ return scriptRunner;
+ }
+
@Override
public DdlHandler createDdlHandler() {
return PlatformDdlBuilder.create(databasePlatform).createDdlHandler(serverConfig);
diff --git a/src/test/java/io/ebean/EbeanServer_refresh.java b/src/test/java/io/ebean/EbeanServer_refresh.java
index 1c1188ea4..0c3e676a8 100644
--- a/src/test/java/io/ebean/EbeanServer_refresh.java
+++ b/src/test/java/io/ebean/EbeanServer_refresh.java
@@ -1,13 +1,13 @@
package io.ebean;
-import io.ebean.Ebean;
-import io.ebean.EbeanServer;
+import org.junit.Test;
import org.tests.model.basic.EBasic;
import org.tests.model.basic.Order;
import org.tests.model.basic.ResetBasicData;
-import org.junit.Test;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
import static org.junit.Assert.assertEquals;
@@ -16,7 +16,14 @@ public class EbeanServer_refresh {
@Test
public void basic() {
+ Map map = new HashMap<>();
+ map.put("tableName", "e_basic");
+
EbeanServer server = Ebean.getDefaultServer();
+ server.script().run("/scripts/test-script.sql");
+ server.script().run("/scripts/test-script-2.sql", map);
+ server.script().run(this.getClass().getResource("/scripts/test-script.sql"));
+ server.script().run(this.getClass().getResource("/scripts/test-script-2.sql"), map);
EBasic basic = new EBasic("basic refresh");
basic.setStatus(EBasic.Status.NEW);
diff --git a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java
index 2100f8d7c..afa192641 100644
--- a/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java
+++ b/src/test/java/io/ebeaninternal/api/TDSpiEbeanServer.java
@@ -19,6 +19,7 @@ import io.ebean.Query;
import io.ebean.QueryIterator;
import io.ebean.RowConsumer;
import io.ebean.RowMapper;
+import io.ebean.ScriptRunner;
import io.ebean.SqlQuery;
import io.ebean.SqlRow;
import io.ebean.SqlUpdate;
@@ -106,6 +107,11 @@ public class TDSpiEbeanServer implements SpiEbeanServer {
}
+ @Override
+ public ScriptRunner script() {
+ return null;
+ }
+
@Override
public void scopedTransactionEnter(TxScope txScope) {
diff --git a/src/test/resources/scripts/test-script-2.sql b/src/test/resources/scripts/test-script-2.sql
new file mode 100644
index 000000000..977ee0ec4
--- /dev/null
+++ b/src/test/resources/scripts/test-script-2.sql
@@ -0,0 +1,4 @@
+delete from ${tableName};
+
+-- some other comment, tableName is replaced
+select count(*) from ${tableName};
diff --git a/src/test/resources/scripts/test-script.sql b/src/test/resources/scripts/test-script.sql
new file mode 100644
index 000000000..6118a0454
--- /dev/null
+++ b/src/test/resources/scripts/test-script.sql
@@ -0,0 +1,4 @@
+delete from e_basic;
+
+-- some comment, select not useful here
+select count(*) from e_basic;