Skip to content

Commit

Permalink
Implement migrations subsystem
Browse files Browse the repository at this point in the history
  • Loading branch information
voidpointer0x00 committed Apr 12, 2023
1 parent 65ea38e commit 25ea05c
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import voidpointer.spigot.framework.localemodule.annotation.AutowiredLocale;
import voidpointer.spigot.voidwhitelist.config.OrmliteConfig;
import voidpointer.spigot.voidwhitelist.storage.WhitelistService;
import voidpointer.spigot.voidwhitelist.storage.db.migration.MigrationModel;
import voidpointer.spigot.voidwhitelist.storage.db.migration.SchemaMigrator;
import voidpointer.spigot.voidwhitelist.task.DatabaseSyncTask;

import java.net.ConnectException;
Expand All @@ -21,20 +23,23 @@
import static voidpointer.spigot.voidwhitelist.storage.WhitelistService.ConnectionResult.FAIL;
import static voidpointer.spigot.voidwhitelist.storage.WhitelistService.ConnectionResult.SUCCESS;

final class OrmliteDatabase {
public final class OrmliteDatabase {
@AutowiredLocale private static LocaleLog log;

private final Plugin plugin;
private final OrmliteConfig ormliteConfig;
private final SchemaMigrator schemaMigrator;
private DatabaseSyncTask syncTask;

@Getter private ConnectionSource connectionSource;
@Getter private Dao<WhitelistableModel, UUID> whitelistDao;
@Getter private Dao<AutoWhitelistNumberModel, UUID> autoWhitelistDao;
@Getter private Dao<MigrationModel, String> migrationDao;

public OrmliteDatabase(final Plugin plugin) {
this.plugin = plugin;
ormliteConfig = new OrmliteConfig(plugin);
schemaMigrator = new SchemaMigrator(this);
Logger.setGlobalLogLevel(Level.OFF); // disable ORMLite logging
}

Expand All @@ -45,6 +50,7 @@ public WhitelistService.ConnectionResult connect() {
log.warn("Connection failed.");
return FAIL;
}
schemaMigrator.runUnfinishedMigrations();
scheduleSync();
log.info("Connection established.");
return SUCCESS;
Expand Down Expand Up @@ -85,16 +91,19 @@ private boolean createDataAccessObjects() {
getRootConnectionExceptionOrElse(sqlException, sqlException).getMessage());
whitelistDao = null;
autoWhitelistDao = null;
migrationDao = null;
return false;
}
}

private void createDataAccessObjects0() throws SQLException {
TableUtils.createTableIfNotExists(connectionSource, WhitelistableModel.class);
TableUtils.createTableIfNotExists(connectionSource, AutoWhitelistNumberModel.class);
TableUtils.createTableIfNotExists(connectionSource, MigrationModel.class);

whitelistDao = createDao(connectionSource, WhitelistableModel.class);
autoWhitelistDao = createDao(connectionSource, AutoWhitelistNumberModel.class);
migrationDao = createDao(connectionSource, MigrationModel.class);
}

private void scheduleSync() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package voidpointer.spigot.voidwhitelist.storage.db.migration;

import voidpointer.spigot.voidwhitelist.storage.db.OrmliteDatabase;

import java.sql.SQLException;

final class AutoWhitelistSchemaMigration implements SchemaMigration {
public static final String NAME = "auto_whitelist/whitelistable_rename";
private static final String RENAME_COLUMNS = "ALTER TABLE whitelist RENAME COLUMN uniqueId TO unique_id" +
", RENAME COLUMN expiresAt TO expires_at";

@Override public String name() {
return NAME;
}

@Override public void perform(final OrmliteDatabase database) throws SQLException {
database.getWhitelistDao().executeRaw(RENAME_COLUMNS);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package voidpointer.spigot.voidwhitelist.storage.db.migration;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
@AllArgsConstructor
@DatabaseTable(tableName="migrations")
public final class MigrationModel {
@DatabaseField(id=true)
private String name;
@DatabaseField(columnName="is_finished")
private boolean isFinished;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package voidpointer.spigot.voidwhitelist.storage.db.migration;

import lombok.RequiredArgsConstructor;
import voidpointer.spigot.framework.localemodule.LocaleLog;
import voidpointer.spigot.framework.localemodule.annotation.AutowiredLocale;
import voidpointer.spigot.voidwhitelist.storage.db.OrmliteDatabase;

import java.sql.SQLException;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@RequiredArgsConstructor
final class OrmliteMigrationService {
@AutowiredLocale private static LocaleLog log;
private final OrmliteDatabase database;

public CompletableFuture<Optional<Set<String>>> findAllFinished() {
return CompletableFuture.supplyAsync(() -> {
try {
return Optional.of(findAllFinished0());
} catch (final SQLException sqlException) {
log.warn("Unable to get finished migrations list: {0}", sqlException.getMessage());
return Optional.empty();
}
});
}

void setFinished(final String migrationName) throws SQLException {
database.getMigrationDao().createOrUpdate(new MigrationModel(migrationName, true));
}

private Set<String> findAllFinished0() throws SQLException {
return database.getMigrationDao().queryForMatching(new MigrationModel(null, true)).stream()
.map(MigrationModel::getName).collect(Collectors.toSet());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package voidpointer.spigot.voidwhitelist.storage.db.migration;

import voidpointer.spigot.voidwhitelist.storage.db.OrmliteDatabase;

import java.sql.SQLException;

interface SchemaMigration {
String name();

void perform(final OrmliteDatabase database) throws SQLException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package voidpointer.spigot.voidwhitelist.storage.db.migration;

import java.util.LinkedList;
import java.util.Queue;

final class SchemaMigrationRepository {
public static Queue<SchemaMigration> migrations() {
final Queue<SchemaMigration> migrations = new LinkedList<>();
migrations.add(new AutoWhitelistSchemaMigration());
return migrations;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package voidpointer.spigot.voidwhitelist.storage.db.migration;

import com.j256.ormlite.misc.TransactionManager;
import voidpointer.spigot.framework.localemodule.LocaleLog;
import voidpointer.spigot.framework.localemodule.annotation.AutowiredLocale;
import voidpointer.spigot.voidwhitelist.storage.db.OrmliteDatabase;

import java.sql.SQLException;
import java.util.Queue;

public final class SchemaMigrator {
@AutowiredLocale private static LocaleLog log;
private final OrmliteDatabase database;
private final OrmliteMigrationService migrationService;

public SchemaMigrator(final OrmliteDatabase database) {
this.database = database;
this.migrationService = new OrmliteMigrationService(database);
}

public void runUnfinishedMigrations() {
migrationService.findAllFinished().join().ifPresent(finishedMigrations -> {
final Queue<SchemaMigration> migrations = SchemaMigrationRepository.migrations();
while (!migrations.isEmpty()) {
final SchemaMigration migration = migrations.poll();
if (finishedMigrations.contains(migration.name()))
continue;
if (!performMigration(migration))
break;
}
});
}

private boolean performMigration(final SchemaMigration migration) {
try {
log.info("Performing {0} migration", migration.name());
final long start = System.currentTimeMillis();
TransactionManager.callInTransaction(database.getConnectionSource(), () -> {
migration.perform(database);
migrationService.setFinished(migration.name());
return null;
});
log.info("{0} finished in {1} ms.", migration.name(), System.currentTimeMillis() - start);
return true;
} catch (final SQLException sqlException) {
log.severe("Unable to perform migration {0}: {1}", migration.name(), sqlException.getMessage());
return false;
}
}
}

0 comments on commit 25ea05c

Please sign in to comment.