using MySqlConnector; using System; namespace SharpChat.EventStorage { public partial class MariaDBEventStorage { private void DoMigration(string name, Action action) { bool done = (long?)RunQueryValue( "SELECT COUNT(*) FROM `sqc_migrations` WHERE `migration_name` = @name", new MySqlParameter("name", name) ) > 0; if(!done) { Logger.Write($"Running migration '{name}'..."); action(); RunMigrationCommand( "INSERT INTO `sqc_migrations` (`migration_name`) VALUES (@name)", new MySqlParameter("name", name) ); } } public void RunMigrations() { RunMigrationCommand( "CREATE TABLE IF NOT EXISTS `sqc_migrations` (" + "`migration_name` VARCHAR(255) NOT NULL," + "`migration_completed` TIMESTAMP NOT NULL DEFAULT current_timestamp()," + "UNIQUE INDEX `migration_name` (`migration_name`)," + "INDEX `migration_completed` (`migration_completed`)" + ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;" ); DoMigration("create_events_table", CreateEventsTable); DoMigration("allow_null_target", AllowNullTarget); DoMigration("update_event_type_names", UpdateEventTypeNames); DoMigration("deprecate_event_flags", DeprecateEventFlags); DoMigration("update_collations_and_use_json_type", UpdateCollationsAndUseJsonType); } private void UpdateCollationsAndUseJsonType() { RunMigrationCommand("UPDATE sqc_events SET event_target = LOWER(event_target)"); RunMigrationCommand("UPDATE sqc_events SET event_sender_nick = NULL WHERE event_sender_nick = ''"); RunMigrationCommand( "ALTER TABLE `sqc_events` COLLATE='utf8mb4_unicode_520_ci'," + " CHANGE COLUMN `event_type` `event_type` VARCHAR(255) NOT NULL COLLATE 'ascii_general_ci' AFTER `event_id`," + " CHANGE COLUMN `event_created` `event_created` TIMESTAMP NOT NULL DEFAULT current_timestamp() AFTER `event_type`," + " CHANGE COLUMN `event_deleted` `event_deleted` TIMESTAMP NULL DEFAULT NULL AFTER `event_created`," + " CHANGE COLUMN `event_target` `event_channel` VARCHAR(255) NULL DEFAULT NULL COLLATE 'ascii_general_ci' AFTER `event_deleted`," + " CHANGE COLUMN `event_sender_name` `event_sender_name` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_520_ci' AFTER `event_sender`," + " CHANGE COLUMN `event_sender_nick` `event_sender_nick` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8mb4_unicode_520_ci' AFTER `event_sender_rank`," + " CHANGE COLUMN `event_data` `event_data` JSON NOT NULL DEFAULT '{}' AFTER `event_sender_perms`," + " DROP INDEX `event_target`, ADD INDEX `event_channel` (`event_channel`)" ); } private void DeprecateEventFlags() { // StoredEventFlags.Action is just a field in the data object RunMigrationCommand(@"UPDATE sqc_events SET event_data = JSON_MERGE_PATCH(event_data, JSON_OBJECT('action', true)) WHERE event_flags & 1"); // StoredEventFlags.Broadcast can be implied by just having a NULL as the channel name RunMigrationCommand(@"UPDATE sqc_events SET event_target = NULL WHERE event_flags & 2"); // StoredEventFlags.Log was never meaningfully used by anything and basically just meant "not-msg:add" // StoredEventFlags.Private was also never meaningfully used, can be determined by checking if the channel name starts with @ RunMigrationCommand(@"ALTER TABLE sqc_events DROP COLUMN event_flags"); } private void UpdateEventTypeNames() { RunMigrationCommand(@"UPDATE sqc_events SET event_type = ""msg:add"" WHERE event_type = ""SharpChat.Events.ChatMessage"""); RunMigrationCommand(@"UPDATE sqc_events SET event_type = ""user:connect"" WHERE event_type = ""SharpChat.Events.UserConnectEvent"""); RunMigrationCommand(@"UPDATE sqc_events SET event_type = ""user:disconnect"" WHERE event_type = ""SharpChat.Events.UserDisconnectEvent"""); RunMigrationCommand(@"UPDATE sqc_events SET event_type = ""chan:join"" WHERE event_type = ""SharpChat.Events.UserChannelJoinEvent"""); RunMigrationCommand(@"UPDATE sqc_events SET event_type = ""chan:leave"" WHERE event_type = ""SharpChat.Events.UserChannelLeaveEvent"""); } private void AllowNullTarget() { RunMigrationCommand( "ALTER TABLE `sqc_events`" + " CHANGE COLUMN `event_target` `event_target` VARBINARY(255) NULL AFTER `event_type`;" ); } private void CreateEventsTable() { RunMigrationCommand( "CREATE TABLE `sqc_events` (" + "`event_id` BIGINT(20) NOT NULL," + "`event_sender` BIGINT(20) UNSIGNED NULL DEFAULT NULL," + "`event_sender_name` VARCHAR(255) NULL DEFAULT NULL," + "`event_sender_colour` INT(11) NULL DEFAULT NULL," + "`event_sender_rank` INT(11) NULL DEFAULT NULL," + "`event_sender_nick` VARCHAR(255) NULL DEFAULT NULL," + "`event_sender_perms` INT(11) NULL DEFAULT NULL," + "`event_created` TIMESTAMP NOT NULL DEFAULT current_timestamp()," + "`event_deleted` TIMESTAMP NULL DEFAULT NULL," + "`event_type` VARBINARY(255) NOT NULL," + "`event_target` VARBINARY(255) NOT NULL," + "`event_flags` TINYINT(3) UNSIGNED NOT NULL," + "`event_data` BLOB NULL DEFAULT NULL," + "PRIMARY KEY (`event_id`)," + "INDEX `event_target` (`event_target`)," + "INDEX `event_type` (`event_type`)," + "INDEX `event_sender` (`event_sender`)," + "INDEX `event_datetime` (`event_created`)," + "INDEX `event_deleted` (`event_deleted`)" + ") COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;" ); } } }