diff --git a/src/main/java/net/discordjug/javabot/data/h2db/MigrationUtils.java b/src/main/java/net/discordjug/javabot/data/h2db/MigrationUtils.java index e18cdadc4..335643150 100644 --- a/src/main/java/net/discordjug/javabot/data/h2db/MigrationUtils.java +++ b/src/main/java/net/discordjug/javabot/data/h2db/MigrationUtils.java @@ -7,16 +7,32 @@ import java.nio.file.*; import java.util.HashMap; import java.util.Map; +import java.util.Objects; +import lombok.extern.slf4j.Slf4j; import net.discordjug.javabot.data.h2db.commands.MigrationsListSubcommand; /** * Utility class that handles SQL Migrations. */ +@Slf4j public class MigrationUtils { + + private static final Path migrationDirectory; private MigrationUtils() { } + + static { + Path dir; + try { + dir = createMigrationsDirectory(); + } catch (IOException | URISyntaxException e) { + log.error("Cannot create database migration directory", e); + dir = null; + } + migrationDirectory = dir; + } /** * Tries to get the Migrations Directories' Path. @@ -26,6 +42,10 @@ private MigrationUtils() { * @throws IOException If an error occurs. */ public static Path getMigrationsDirectory() throws URISyntaxException, IOException { + return Objects.requireNonNull(migrationDirectory); + } + + private static Path createMigrationsDirectory() throws IOException, URISyntaxException { URL resource = MigrationsListSubcommand.class.getResource("/database/migrations/"); if (resource == null) throw new IOException("Missing resource /migrations/"); URI uri = resource.toURI(); diff --git a/src/main/java/net/discordjug/javabot/data/h2db/commands/ExportTableSubcommand.java b/src/main/java/net/discordjug/javabot/data/h2db/commands/ExportTableSubcommand.java index ab111f902..567f882fe 100644 --- a/src/main/java/net/discordjug/javabot/data/h2db/commands/ExportTableSubcommand.java +++ b/src/main/java/net/discordjug/javabot/data/h2db/commands/ExportTableSubcommand.java @@ -52,7 +52,6 @@ public ExportTableSubcommand(ExecutorService asyncPool, SystemsConfig systemsCon .addChoice("Message Cache", "MESSAGE_CACHE") .addChoice("Question of the Week Accounts", "QOTW_POINTS") .addChoice("Question of the Week Questions", "QOTW_QUESTION") - .addChoice("Reserved Help Channels", "RESERVED_HELP_CHANNELS") .addChoice("Starboard", "STARBOARD") .addChoice("Warns", "WARN") .addChoice("User Preferences", "USER_PREFERENCES"), diff --git a/src/main/java/net/discordjug/javabot/data/h2db/commands/MigrateSubcommand.java b/src/main/java/net/discordjug/javabot/data/h2db/commands/MigrateSubcommand.java index 3a4a28632..623b3457f 100644 --- a/src/main/java/net/discordjug/javabot/data/h2db/commands/MigrateSubcommand.java +++ b/src/main/java/net/discordjug/javabot/data/h2db/commands/MigrateSubcommand.java @@ -93,7 +93,6 @@ public void execute(@NotNull SlashCommandInteractionEvent event) { return; } String sql = Files.readString(migrationFile); - migrationsDir.getFileSystem().close(); String[] statements = sql.split("\\s*;\\s*"); if (statements.length == 0) { Responses.error(event, "The migration `" + migrationName + "` does not contain any statements. Please remove or edit it before running again.").queue(); diff --git a/src/main/resources/database/migrations/02-13-2023_message_cache_links.sql b/src/main/resources/database/migrations/02-13-2023_message_cache_links.sql deleted file mode 100644 index 03c55f07c..000000000 --- a/src/main/resources/database/migrations/02-13-2023_message_cache_links.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE message_cache_attachments ( - message_id BIGINT NOT NULL, - attachment_index INT NOT NULL, - link VARCHAR(255), - PRIMARY KEY(message_id, attachment_index) -) diff --git a/src/main/resources/database/migrations/04-02-2025_bigger_message_links.sql b/src/main/resources/database/migrations/04-02-2025_bigger_message_links.sql deleted file mode 100644 index 69cfcd5c6..000000000 --- a/src/main/resources/database/migrations/04-02-2025_bigger_message_links.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE message_cache_attachments ALTER COLUMN link VARCHAR(511); diff --git a/src/main/resources/database/migrations/07-08-2023_channel_transactions.sql b/src/main/resources/database/migrations/07-08-2023_channel_transactions.sql deleted file mode 100644 index 1c4a41538..000000000 --- a/src/main/resources/database/migrations/07-08-2023_channel_transactions.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE help_transaction ADD COLUMN channel BIGINT DEFAULT -1; \ No newline at end of file diff --git a/src/main/resources/database/migrations/07-19-2026_add_channel_column_to_cache.sql b/src/main/resources/database/migrations/07-19-2026_add_channel_column_to_cache.sql deleted file mode 100644 index 8ac312be8..000000000 --- a/src/main/resources/database/migrations/07-19-2026_add_channel_column_to_cache.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE message_cache ADD COLUMN channel_id BIGINT DEFAULT -1; diff --git a/src/main/resources/database/migrations/08-15-2023_staff_activity.sql b/src/main/resources/database/migrations/08-15-2023_staff_activity.sql deleted file mode 100644 index cdf771235..000000000 --- a/src/main/resources/database/migrations/08-15-2023_staff_activity.sql +++ /dev/null @@ -1,6 +0,0 @@ -CREATE TABLE staff_activity_messages ( - guild_id BIGINT NOT NULL, - user_id BIGINT NOT NULL, - message_id BIGINT NOT NULL, - PRIMARY KEY(guild_id, user_id) -) \ No newline at end of file diff --git a/src/main/resources/database/migrations/09-08-2025_forms.sql b/src/main/resources/database/migrations/09-08-2025_forms.sql deleted file mode 100644 index 3779da643..000000000 --- a/src/main/resources/database/migrations/09-08-2025_forms.sql +++ /dev/null @@ -1,37 +0,0 @@ -CREATE TABLE forms ( - form_id BIGINT NOT NULL AUTO_INCREMENT, - title VARCHAR NOT NULL, - submit_message VARCHAR DEFAULT NULL, - submit_channel BIGINT NOT NULL, - message_id BIGINT DEFAULT NULL, - message_channel BIGINT DEFAULT NULL, - expiration TIMESTAMP DEFAULT NULL, - closed BOOLEAN NOT NULL DEFAULT FALSE, - onetime BOOLEAN NOT NULL DEFAULT FALSE, - PRIMARY KEY (form_id) -); - -CREATE TABLE form_fields ( - id BIGINT NOT NULL AUTO_INCREMENT, - form_id BIGINT NOT NULL, - label VARCHAR NOT NULL, - min INTEGER DEFAULT 0 NOT NULL, - max INTEGER DEFAULT 16 NOT NULL, - placeholder VARCHAR, - "required" BOOLEAN DEFAULT FALSE NOT NULL, - "style" ENUM('SHORT', 'PARAGRAPH') DEFAULT 'SHORT' NOT NULL, - initial VARCHAR DEFAULT NULL, - PRIMARY KEY (id), - FOREIGN KEY (form_id) REFERENCES forms(form_id) ON DELETE CASCADE ON UPDATE RESTRICT -); - -CREATE TABLE form_submissions ( - message_id BIGINT NOT NULL, - user_id BIGINT NOT NULL, - form_id BIGINT NOT NULL, - user_name VARCHAR NOT NULL, - PRIMARY KEY (message_id), - FOREIGN KEY (form_id) REFERENCES FORMS(form_id) ON DELETE CASCADE ON UPDATE RESTRICT -); - -CREATE INDEX FORM_SUBMISSIONS_USER_ID_IDX ON form_submissions (user_id,form_id); diff --git a/src/main/resources/database/migrations/09-15-2024_custom_vcs.sql b/src/main/resources/database/migrations/09-15-2024_custom_vcs.sql deleted file mode 100644 index e08363295..000000000 --- a/src/main/resources/database/migrations/09-15-2024_custom_vcs.sql +++ /dev/null @@ -1,4 +0,0 @@ -CREATE TABLE custom_vc ( - channel_id BIGINT NOT NULL PRIMARY KEY, - owner_id BIGINT NOT NULL -) diff --git a/src/main/resources/database/migrations/11-11-2024_store_qotw_champion.sql b/src/main/resources/database/migrations/11-11-2024_store_qotw_champion.sql deleted file mode 100644 index dc8790520..000000000 --- a/src/main/resources/database/migrations/11-11-2024_store_qotw_champion.sql +++ /dev/null @@ -1,5 +0,0 @@ -CREATE TABLE qotw_champion ( - guild_id BIGINT NOT NULL, - user_id BIGINT NOT NULL, - PRIMARY KEY(guild_id, user_id) -) \ No newline at end of file diff --git a/src/main/resources/database/migrations/12-17-2022_qotw_point_timestamps.sql b/src/main/resources/database/migrations/12-17-2022_qotw_point_timestamps.sql deleted file mode 100644 index de7d073ef..000000000 --- a/src/main/resources/database/migrations/12-17-2022_qotw_point_timestamps.sql +++ /dev/null @@ -1,3 +0,0 @@ -ALTER TABLE qotw_points ADD obtained_at DATE NOT NULL DEFAULT CURRENT_TIMESTAMP(0); -ALTER TABLE qotw_points DROP PRIMARY KEY; -ALTER TABLE qotw_points ADD PRIMARY KEY (user_id, obtained_at); \ No newline at end of file diff --git a/src/main/resources/database/migrations/12-17-2022_remove_channel_reservations.sql b/src/main/resources/database/migrations/12-17-2022_remove_channel_reservations.sql deleted file mode 100644 index bff3b5ef7..000000000 --- a/src/main/resources/database/migrations/12-17-2022_remove_channel_reservations.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE reserved_help_channels; \ No newline at end of file diff --git a/src/main/resources/database/migrations/12-17-2022_remove_help_transaction_message.sql b/src/main/resources/database/migrations/12-17-2022_remove_help_transaction_message.sql deleted file mode 100644 index 0e6d11694..000000000 --- a/src/main/resources/database/migrations/12-17-2022_remove_help_transaction_message.sql +++ /dev/null @@ -1 +0,0 @@ -ALTER TABLE help_transaction DROP COLUMN messagetype; \ No newline at end of file diff --git a/src/main/resources/database/migrations/12-18-2022_qotw_clear_points.sql b/src/main/resources/database/migrations/12-18-2022_qotw_clear_points.sql deleted file mode 100644 index 75b3bd5c5..000000000 --- a/src/main/resources/database/migrations/12-18-2022_qotw_clear_points.sql +++ /dev/null @@ -1 +0,0 @@ -DELETE FROM qotw_points WHERE user_id=374328434677121036; diff --git a/src/main/resources/database/migrations/README.md b/src/main/resources/database/migrations/README.md new file mode 100644 index 000000000..397fa4401 --- /dev/null +++ b/src/main/resources/database/migrations/README.md @@ -0,0 +1,7 @@ +# Creating database migrations + +To create a database migration, first create a migration script containing the change you want to perform. This script should be located in this directory (`src/main/resources/database/migrations`) and use a file name in the format `yyyy-MM-dd_.sql` where `` is a short name/description of the database migration. An example of such a file name would be `1970-01-01_create-the-world.sql`. + +After creating the database script, verify that it works using the `/db-admin migrate ` command. + +Finally, add your change to the `src/main/resources/database/schema.sql` file. diff --git a/src/main/resources/database/schema.sql b/src/main/resources/database/schema.sql index 86de02667..725abcc9f 100644 --- a/src/main/resources/database/schema.sql +++ b/src/main/resources/database/schema.sql @@ -1,13 +1,4 @@ // Help System -CREATE TABLE IF NOT EXISTS reserved_help_channels -( - id BIGINT PRIMARY KEY AUTO_INCREMENT, - channel_id BIGINT NOT NULL UNIQUE, - reserved_at TIMESTAMP(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0), - user_id BIGINT NOT NULL, - timeout INT NOT NULL DEFAULT 60 -); - CREATE TABLE IF NOT EXISTS help_channel_thanks ( id BIGINT PRIMARY KEY AUTO_INCREMENT, @@ -31,7 +22,7 @@ CREATE TABLE IF NOT EXISTS help_transaction recipient BIGINT NOT NULL, created_at TIMESTAMP(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), weight DOUBLE NOT NULL, - messagetype INT NOT NULL DEFAULT 0 + channel BIGINT DEFAULT -1 ); // Question of the Week @@ -95,13 +86,14 @@ CREATE TABLE IF NOT EXISTS message_cache ( message_id BIGINT PRIMARY KEY, author_id BIGINT NOT NULL, - message_content VARCHAR(4000) NOT NULL + message_content VARCHAR(4000) NOT NULL, + channel_id BIGINT DEFAULT -1 ); CREATE TABLE IF NOT EXISTS message_cache_attachments ( message_id BIGINT NOT NULL, attachment_index INT NOT NULL, - link VARCHAR(255), + link VARCHAR(511), PRIMARY KEY(message_id, attachment_index) ); @@ -120,3 +112,56 @@ CREATE TABLE qotw_champion ( user_id BIGINT NOT NULL, PRIMARY KEY(guild_id, user_id) ); + +// staff activity +CREATE TABLE staff_activity_messages ( + guild_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + message_id BIGINT NOT NULL, + PRIMARY KEY(guild_id, user_id) +); + +// custom voice channels +CREATE TABLE custom_vc ( + channel_id BIGINT NOT NULL PRIMARY KEY, + owner_id BIGINT NOT NULL +); + +// forms +CREATE TABLE forms ( + form_id BIGINT NOT NULL AUTO_INCREMENT, + title VARCHAR NOT NULL, + submit_message VARCHAR DEFAULT NULL, + submit_channel BIGINT NOT NULL, + message_id BIGINT DEFAULT NULL, + message_channel BIGINT DEFAULT NULL, + expiration TIMESTAMP DEFAULT NULL, + closed BOOLEAN NOT NULL DEFAULT FALSE, + onetime BOOLEAN NOT NULL DEFAULT FALSE, + PRIMARY KEY (form_id) +); + +CREATE TABLE form_fields ( + id BIGINT NOT NULL AUTO_INCREMENT, + form_id BIGINT NOT NULL, + label VARCHAR NOT NULL, + min INTEGER DEFAULT 0 NOT NULL, + max INTEGER DEFAULT 16 NOT NULL, + placeholder VARCHAR, + "required" BOOLEAN DEFAULT FALSE NOT NULL, + "style" ENUM('SHORT', 'PARAGRAPH') DEFAULT 'SHORT' NOT NULL, + initial VARCHAR DEFAULT NULL, + PRIMARY KEY (id), + FOREIGN KEY (form_id) REFERENCES forms(form_id) ON DELETE CASCADE ON UPDATE RESTRICT +); + +CREATE TABLE form_submissions ( + message_id BIGINT NOT NULL, + user_id BIGINT NOT NULL, + form_id BIGINT NOT NULL, + user_name VARCHAR NOT NULL, + PRIMARY KEY (message_id), + FOREIGN KEY (form_id) REFERENCES FORMS(form_id) ON DELETE CASCADE ON UPDATE RESTRICT +); + +CREATE INDEX FORM_SUBMISSIONS_USER_ID_IDX ON form_submissions (user_id,form_id); diff --git a/src/test/java/net/discordjug/javabot/DatabaseTest.java b/src/test/java/net/discordjug/javabot/DatabaseTest.java new file mode 100644 index 000000000..5ff84d952 --- /dev/null +++ b/src/test/java/net/discordjug/javabot/DatabaseTest.java @@ -0,0 +1,43 @@ +package net.discordjug.javabot; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.SQLException; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import net.discordjug.javabot.data.h2db.DbHelper; +import net.discordjug.javabot.data.h2db.commands.MigrateSubcommand; +import net.dv8tion.jda.api.interactions.commands.Command.Choice; +import org.h2.jdbcx.JdbcDataSource; +import org.junit.jupiter.api.Test; + +public class DatabaseTest { + @Test + void testCreateDatabaseFromSchema() throws SQLException, IOException { + JdbcDataSource ds = new JdbcDataSource(); + ds.setUrl("jdbc:h2:mem:"+UUID.randomUUID().toString()); + DbHelper.initializeSchema(ds); + } + + @Test + void testDatabaseFilesCorrect() throws URISyntaxException, IOException { + Set expectedMigrations; + try (Stream list = Files.list(Path.of("src/main/resources/database/migrations"))) { + expectedMigrations = list + .map(path -> path.getFileName().toString()) + .filter(file -> file.endsWith(".sql")) + .collect(Collectors.toSet()); + } + Set foundMigrations = MigrateSubcommand.getAvailableMigrations().stream() + .map(Choice::getName) + .collect(Collectors.toSet()); + assertEquals(expectedMigrations, foundMigrations); + } +}