mirror of
https://github.com/ebean-orm/ebean.git
synced 2026-11-12 22:41:35 +00:00
#2284 - ENH: ddl-generator - add optional generation of idx_<platform>.migrations file
This commit is contained in:
1 parent
4ba26ee7b7
commit
589ee7a5ea
17 files changed
+293
-9
No files matched your search
@@ -133,6 +133,14 @@ public interface DbMigration {
|
||||
*/
|
||||
void setStrictMode(boolean strictMode);
|
||||
|
||||
/**
|
||||
* Set to include generation of the index migration file.
|
||||
* <p>
|
||||
* When true this generates a {@code idx_<platform>.migrations} file. This can be used by the migration
|
||||
* runner to improve performance of running migrations, especially when no migration changes have occurred.
|
||||
*/
|
||||
void setIncludeIndex(boolean generateIndexFile);
|
||||
|
||||
/**
|
||||
* Set to true to include a generated header comment in the DDL script.
|
||||
*/
|
||||
|
||||
+26
-1
@@ -106,6 +106,7 @@ public class DefaultDbMigration implements DbMigration {
|
||||
private boolean addForeignKeySkipCheck;
|
||||
private int lockTimeoutSeconds;
|
||||
protected boolean includeBuiltInPartitioning = true;
|
||||
protected boolean includeIndex;
|
||||
|
||||
/**
|
||||
* Create for offline migration generation.
|
||||
@@ -182,6 +183,11 @@ public class DefaultDbMigration implements DbMigration {
|
||||
this.generatePendingDrop = generatePendingDrop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIncludeIndex(boolean includeIndex) {
|
||||
this.includeIndex = includeIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIncludeGeneratedFileComment(boolean includeGeneratedFileComment) {
|
||||
this.includeGeneratedFileComment = includeGeneratedFileComment;
|
||||
@@ -273,7 +279,26 @@ public class DefaultDbMigration implements DbMigration {
|
||||
*/
|
||||
@Override
|
||||
public String generateMigration() throws IOException {
|
||||
return generateMigrationFor(false);
|
||||
final String version = generateMigrationFor(false);
|
||||
if (includeIndex) {
|
||||
generateIndex(version);
|
||||
}
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the {@code idx_platform.migrations} file.
|
||||
*/
|
||||
private void generateIndex(String version) throws IOException {
|
||||
final boolean overwrite = version != null;
|
||||
final File topDir = migrationDirectory(false);
|
||||
if (!platforms.isEmpty()) {
|
||||
for (Pair pair : platforms) {
|
||||
new IndexMigration(topDir, pair).generate(overwrite);
|
||||
}
|
||||
} else {
|
||||
new IndexMigration(topDir, databasePlatform).generate(overwrite);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
package io.ebeaninternal.dbmigration;
|
||||
|
||||
import io.ebean.config.dbplatform.DatabasePlatform;
|
||||
import io.ebean.migration.MigrationVersion;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Stack;
|
||||
|
||||
/**
|
||||
* Generate a migration index file.
|
||||
* <p>
|
||||
* This is a file that has all the migrations listed in order with checksum of the file content.
|
||||
*/
|
||||
class IndexMigration {
|
||||
|
||||
private static final String eol = "\n";
|
||||
private final List<Entry> all = new ArrayList<>();
|
||||
private final File topDir;
|
||||
private final DatabasePlatform databasePlatform;
|
||||
private final File indexFile;
|
||||
private final Stack<String> pathStack = new Stack<>();
|
||||
|
||||
IndexMigration(File topDir, DatabasePlatform databasePlatform) {
|
||||
this.topDir = topDir;
|
||||
this.databasePlatform = databasePlatform;
|
||||
this.indexFile = init();
|
||||
}
|
||||
|
||||
IndexMigration(File topDir, DefaultDbMigration.Pair pair) {
|
||||
this.topDir = new File(topDir, pair.prefix);
|
||||
this.databasePlatform = pair.platform;
|
||||
this.indexFile = init();
|
||||
}
|
||||
|
||||
File init() {
|
||||
pathStack.push("");
|
||||
String name = "idx_" + databasePlatform.getPlatform().base().name().toLowerCase() + ".migrations";
|
||||
return new File(topDir, name);
|
||||
}
|
||||
|
||||
void generate(boolean overwrite) throws IOException {
|
||||
if (!overwrite && indexFile.exists()) {
|
||||
return;
|
||||
}
|
||||
readSqlFiles(topDir);
|
||||
generateIndex();
|
||||
}
|
||||
|
||||
private void generateIndex() throws IOException {
|
||||
Collections.sort(all);
|
||||
FileWriter writer = new FileWriter(indexFile);
|
||||
for (Entry entry : all) {
|
||||
writeChecksumPadded(writer, entry.checksum);
|
||||
writer.write(entry.fileName);
|
||||
writer.write(eol);
|
||||
}
|
||||
writer.write(eol);
|
||||
writer.close();
|
||||
}
|
||||
|
||||
private void writeChecksumPadded(FileWriter writer, int checksum) throws IOException {
|
||||
final String asStr = String.valueOf(checksum);
|
||||
writer.write(asStr);
|
||||
writer.write(',');
|
||||
int max = 15 - asStr.length();
|
||||
for (int i = 0; i < max; i++) {
|
||||
writer.write(' ');
|
||||
}
|
||||
}
|
||||
|
||||
private void readSqlFiles(File dir) {
|
||||
final File[] files = dir.listFiles();
|
||||
if (files != null && files.length > 0) {
|
||||
for (File file : files) {
|
||||
if (file.isDirectory()) {
|
||||
readDirectory(file);
|
||||
}
|
||||
final String lowerName = file.getName().toLowerCase();
|
||||
if (lowerName.endsWith(".sql")) {
|
||||
addEntry(file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void readDirectory(File dir) {
|
||||
final String current = pathStack.peek();
|
||||
pathStack.push(current + dir.getName() + "/");
|
||||
readSqlFiles(dir);
|
||||
pathStack.pop();
|
||||
}
|
||||
|
||||
private void addEntry(File sqlFile) {
|
||||
final String relativePath = pathStack.peek();
|
||||
final String fileName = sqlFile.getName();
|
||||
final String name = fileName.substring(0, fileName.length() - 4);
|
||||
final MigrationVersion version = MigrationVersion.parse(name);
|
||||
final int checksum = MChecksum.calculate(sqlFile);
|
||||
all.add(new Entry(checksum, version, relativePath + fileName));
|
||||
}
|
||||
|
||||
static class Entry implements Comparable<Entry> {
|
||||
|
||||
private final int checksum;
|
||||
private final String fileName;
|
||||
private final MigrationVersion version;
|
||||
|
||||
Entry(int checksum, MigrationVersion version, String fileName) {
|
||||
this.checksum = checksum;
|
||||
this.version = version;
|
||||
this.fileName = fileName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Entry other) {
|
||||
return version.compareTo(other.version);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package io.ebeaninternal.dbmigration;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.zip.CRC32;
|
||||
|
||||
/**
|
||||
* Calculates the checksum for the given file content.
|
||||
*/
|
||||
class MChecksum {
|
||||
|
||||
/**
|
||||
* Returns the checksum of the file. Agnostic of encoding and new line character.
|
||||
*/
|
||||
static int calculate(File file) {
|
||||
try {
|
||||
final CRC32 crc32 = new CRC32();
|
||||
BufferedReader bufferedReader = new BufferedReader(new FileReader(file));
|
||||
String line;
|
||||
while ((line = bufferedReader.readLine()) != null) {
|
||||
final byte[] lineBytes = line.getBytes(StandardCharsets.UTF_8);
|
||||
crc32.update(lineBytes, 0, lineBytes.length);
|
||||
}
|
||||
return (int) crc32.getValue();
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException("Failed to calculate checksum", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user