From 5a2c4cdb7ba6830ec53e1ffd49f21b4e730339f7 Mon Sep 17 00:00:00 2001 From: getBoolean <19920697+getBoolean@users.noreply.github.com> Date: Sun, 31 May 2026 00:20:07 -0500 Subject: [PATCH] Remove room index option for winners --- data/migrations/0014_narrow_wind_dancer.sql | 3 + data/migrations/meta/0014_snapshot.json | 3041 +++++++++++++++++++ data/migrations/meta/_journal.json | 7 + src/commands/commands/events.command.ts | 63 +- src/db/schema.ts | 3 +- src/db/store.ts | 7 +- src/options/options.loader.ts | 2 - src/options/options/room-index.option.ts | 7 - src/utils/winner.logic.test.ts | 57 +- src/utils/winner.logic.ts | 47 +- src/utils/winner.utils.ts | 29 +- 11 files changed, 3092 insertions(+), 174 deletions(-) create mode 100644 data/migrations/0014_narrow_wind_dancer.sql create mode 100644 data/migrations/meta/0014_snapshot.json delete mode 100644 src/options/options/room-index.option.ts diff --git a/data/migrations/0014_narrow_wind_dancer.sql b/data/migrations/0014_narrow_wind_dancer.sql new file mode 100644 index 0000000..07d46c3 --- /dev/null +++ b/data/migrations/0014_narrow_wind_dancer.sql @@ -0,0 +1,3 @@ +DROP INDEX `event_winner_event_id_room_index_user_id_unique`;--> statement-breakpoint +CREATE UNIQUE INDEX `event_winner_event_id_user_id_unique` ON `event_winner` (`event_id`,`user_id`);--> statement-breakpoint +ALTER TABLE `event_winner` DROP COLUMN `room_index`; \ No newline at end of file diff --git a/data/migrations/meta/0014_snapshot.json b/data/migrations/meta/0014_snapshot.json new file mode 100644 index 0000000..de37794 --- /dev/null +++ b/data/migrations/meta/0014_snapshot.json @@ -0,0 +1,3041 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "5688b198-1d01-4eb7-b878-e61c3cf888a7", + "prevId": "afe1d2ce-4d72-45aa-b4f3-0a5aceeead86", + "tables": { + "admin": { + "name": "admin", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "admin_guild_id_index": { + "name": "admin_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "admin_guild_id_subject_id_unique": { + "name": "admin_guild_id_subject_id_unique", + "columns": [ + "guild_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "admin_guild_id_guild_guild_id_fk": { + "name": "admin_guild_id_guild_guild_id_fk", + "tableFrom": "admin", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "archived_member": { + "name": "archived_member", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position_time": { + "name": "position_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "join_time": { + "name": "join_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "archived_time": { + "name": "archived_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "archived_member_queue_id_user_id_unique": { + "name": "archived_member_queue_id_user_id_unique", + "columns": [ + "queue_id", + "user_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "blacklisted": { + "name": "blacklisted", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "blacklisted_guild_id_index": { + "name": "blacklisted_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "blacklisted_queue_id_subject_id_unique": { + "name": "blacklisted_queue_id_subject_id_unique", + "columns": [ + "queue_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "blacklisted_guild_id_guild_guild_id_fk": { + "name": "blacklisted_guild_id_guild_guild_id_fk", + "tableFrom": "blacklisted", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "blacklisted_queue_id_queue_id_fk": { + "name": "blacklisted_queue_id_queue_id_fk", + "tableFrom": "blacklisted", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "display": { + "name": "display", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "display_channel_id": { + "name": "display_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_message_id": { + "name": "last_message_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "display_guild_id_index": { + "name": "display_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "display_queue_id_display_channel_id_unique": { + "name": "display_queue_id_display_channel_id_unique", + "columns": [ + "queue_id", + "display_channel_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "display_guild_id_guild_guild_id_fk": { + "name": "display_guild_id_guild_guild_id_fk", + "tableFrom": "display", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "display_queue_id_queue_id_fk": { + "name": "display_queue_id_queue_id_fk", + "tableFrom": "display", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_blacklisted": { + "name": "event_blacklisted", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_blacklisted_guild_id_index": { + "name": "event_blacklisted_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_blacklisted_event_id_index": { + "name": "event_blacklisted_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_blacklisted_event_id_subject_id_unique": { + "name": "event_blacklisted_event_id_subject_id_unique", + "columns": [ + "event_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_blacklisted_guild_id_guild_guild_id_fk": { + "name": "event_blacklisted_guild_id_guild_guild_id_fk", + "tableFrom": "event_blacklisted", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_blacklisted_event_id_event_id_fk": { + "name": "event_blacklisted_event_id_event_id_fk", + "tableFrom": "event_blacklisted", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_default": { + "name": "event_default", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_role": { + "name": "queue_role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "autopull_toggle": { + "name": "autopull_toggle", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "badge_toggle": { + "name": "badge_toggle", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_update_type": { + "name": "display_update_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "dm_on_pull_toggle": { + "name": "dm_on_pull_toggle", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "buttons_toggles": { + "name": "buttons_toggles", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "header": { + "name": "header", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "inline_toggle": { + "name": "inline_toggle", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lock_toggle": { + "name": "lock_toggle", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "member_display_type": { + "name": "member_display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pull_batch_size": { + "name": "pull_batch_size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pull_message": { + "name": "pull_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pull_message_display_type": { + "name": "pull_message_display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pull_message_channel_id": { + "name": "pull_message_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rejoin_cooldown_period": { + "name": "rejoin_cooldown_period", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rejoin_grace_period": { + "name": "rejoin_grace_period", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "require_message_to_join": { + "name": "require_message_to_join", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role_in_queue_id": { + "name": "role_in_queue_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role_on_pull_id": { + "name": "role_on_pull_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_display_type": { + "name": "time_display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "voice_destination_channel_id": { + "name": "voice_destination_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "voice_only_toggle": { + "name": "voice_only_toggle", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_default_guild_id_index": { + "name": "event_default_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_default_event_id_queue_role_unique": { + "name": "event_default_event_id_queue_role_unique", + "columns": [ + "event_id", + "queue_role" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_default_guild_id_guild_guild_id_fk": { + "name": "event_default_guild_id_guild_guild_id_fk", + "tableFrom": "event_default", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_default_event_id_event_id_fk": { + "name": "event_default_event_id_event_id_fk", + "tableFrom": "event_default", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_occurrence_room_ping": { + "name": "event_occurrence_room_ping", + "columns": { + "occurrence_id": { + "name": "occurrence_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_queue_id": { + "name": "event_queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "handled_at": { + "name": "handled_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "event_occurrence_room_ping_occurrence_id_index": { + "name": "event_occurrence_room_ping_occurrence_id_index", + "columns": [ + "occurrence_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "event_occurrence_room_ping_occurrence_id_event_occurrence_id_fk": { + "name": "event_occurrence_room_ping_occurrence_id_event_occurrence_id_fk", + "tableFrom": "event_occurrence_room_ping", + "tableTo": "event_occurrence", + "columnsFrom": [ + "occurrence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_occurrence_room_ping_event_queue_id_event_queue_id_fk": { + "name": "event_occurrence_room_ping_event_queue_id_event_queue_id_fk", + "tableFrom": "event_occurrence_room_ping", + "tableTo": "event_queue", + "columnsFrom": [ + "event_queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_occurrence_room_ping_occurrence_id_event_queue_id_pk": { + "columns": [ + "occurrence_id", + "event_queue_id" + ], + "name": "event_occurrence_room_ping_occurrence_id_event_queue_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_occurrence_room_pull": { + "name": "event_occurrence_room_pull", + "columns": { + "occurrence_id": { + "name": "occurrence_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_queue_id": { + "name": "event_queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "handled_at": { + "name": "handled_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "event_occurrence_room_pull_occurrence_id_index": { + "name": "event_occurrence_room_pull_occurrence_id_index", + "columns": [ + "occurrence_id" + ], + "isUnique": false + } + }, + "foreignKeys": { + "event_occurrence_room_pull_occurrence_id_event_occurrence_id_fk": { + "name": "event_occurrence_room_pull_occurrence_id_event_occurrence_id_fk", + "tableFrom": "event_occurrence_room_pull", + "tableTo": "event_occurrence", + "columnsFrom": [ + "occurrence_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_occurrence_room_pull_event_queue_id_event_queue_id_fk": { + "name": "event_occurrence_room_pull_event_queue_id_event_queue_id_fk", + "tableFrom": "event_occurrence_room_pull", + "tableTo": "event_queue", + "columnsFrom": [ + "event_queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "event_occurrence_room_pull_occurrence_id_event_queue_id_pk": { + "columns": [ + "occurrence_id", + "event_queue_id" + ], + "name": "event_occurrence_room_pull_occurrence_id_event_queue_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_occurrence": { + "name": "event_occurrence", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "start_time": { + "name": "start_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "open_handled_at": { + "name": "open_handled_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "lock_handled_at": { + "name": "lock_handled_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "discord_event_id": { + "name": "discord_event_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_occurrence_guild_id_index": { + "name": "event_occurrence_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_occurrence_event_id_index": { + "name": "event_occurrence_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_occurrence_event_id_start_time_unique": { + "name": "event_occurrence_event_id_start_time_unique", + "columns": [ + "event_id", + "start_time" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_occurrence_guild_id_guild_guild_id_fk": { + "name": "event_occurrence_guild_id_guild_guild_id_fk", + "tableFrom": "event_occurrence", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_occurrence_event_id_event_id_fk": { + "name": "event_occurrence_event_id_event_id_fk", + "tableFrom": "event_occurrence", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_prioritized": { + "name": "event_prioritized", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "priority_order": { + "name": "priority_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 5 + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_prioritized_guild_id_index": { + "name": "event_prioritized_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_prioritized_event_id_index": { + "name": "event_prioritized_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_prioritized_event_id_subject_id_unique": { + "name": "event_prioritized_event_id_subject_id_unique", + "columns": [ + "event_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_prioritized_guild_id_guild_guild_id_fk": { + "name": "event_prioritized_guild_id_guild_guild_id_fk", + "tableFrom": "event_prioritized", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_prioritized_event_id_event_id_fk": { + "name": "event_prioritized_event_id_event_id_fk", + "tableFrom": "event_prioritized", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_queue": { + "name": "event_queue", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_role": { + "name": "queue_role", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_index": { + "name": "queue_index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ping_channel_id": { + "name": "ping_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "auto_created_role_id": { + "name": "auto_created_role_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_queue_guild_id_index": { + "name": "event_queue_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_queue_event_id_index": { + "name": "event_queue_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_queue_event_id_queue_role_queue_index_unique": { + "name": "event_queue_event_id_queue_role_queue_index_unique", + "columns": [ + "event_id", + "queue_role", + "queue_index" + ], + "isUnique": true + }, + "event_queue_queue_id_unique": { + "name": "event_queue_queue_id_unique", + "columns": [ + "queue_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_queue_guild_id_guild_guild_id_fk": { + "name": "event_queue_guild_id_guild_guild_id_fk", + "tableFrom": "event_queue", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_queue_event_id_event_id_fk": { + "name": "event_queue_event_id_event_id_fk", + "tableFrom": "event_queue", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_queue_queue_id_queue_id_fk": { + "name": "event_queue_queue_id_queue_id_fk", + "tableFrom": "event_queue", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_room_channel": { + "name": "event_room_channel", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "room_index": { + "name": "room_index", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "channel_id": { + "name": "channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "event_room_channel_guild_id_index": { + "name": "event_room_channel_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_room_channel_event_id_index": { + "name": "event_room_channel_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_room_channel_event_id_room_index_suffix_unique": { + "name": "event_room_channel_event_id_room_index_suffix_unique", + "columns": [ + "event_id", + "room_index", + "suffix" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_room_channel_guild_id_guild_guild_id_fk": { + "name": "event_room_channel_guild_id_guild_guild_id_fk", + "tableFrom": "event_room_channel", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_room_channel_event_id_event_id_fk": { + "name": "event_room_channel_event_id_event_id_fk", + "tableFrom": "event_room_channel", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_room_channel_template": { + "name": "event_room_channel_template", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "suffix": { + "name": "suffix", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slowmode_seconds": { + "name": "slowmode_seconds", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_room_channel_template_guild_id_index": { + "name": "event_room_channel_template_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_room_channel_template_event_id_index": { + "name": "event_room_channel_template_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_room_channel_template_event_id_suffix_unique": { + "name": "event_room_channel_template_event_id_suffix_unique", + "columns": [ + "event_id", + "suffix" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_room_channel_template_guild_id_guild_guild_id_fk": { + "name": "event_room_channel_template_guild_id_guild_guild_id_fk", + "tableFrom": "event_room_channel_template", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_room_channel_template_event_id_event_id_fk": { + "name": "event_room_channel_template_event_id_event_id_fk", + "tableFrom": "event_room_channel_template", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event": { + "name": "event", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "room_count": { + "name": "room_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "room_queues_channel_id": { + "name": "room_queues_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "sub_queues_channel_id": { + "name": "sub_queues_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "room_length_ms": { + "name": "room_length_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "room_scheduling": { + "name": "room_scheduling", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'parallel'" + }, + "create_offset_ms": { + "name": "create_offset_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 86400000 + }, + "lock_offset_ms": { + "name": "lock_offset_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "cleanup_offset_ms": { + "name": "cleanup_offset_ms", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 3600000 + }, + "announcement_channel_id": { + "name": "announcement_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "announcement_message": { + "name": "announcement_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "room_ping_message": { + "name": "room_ping_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_rooms_per_user": { + "name": "max_rooms_per_user", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "max_subs_per_user": { + "name": "max_subs_per_user", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "parent_sub_mutually_exclusive": { + "name": "parent_sub_mutually_exclusive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "room_category_id": { + "name": "room_category_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role_in_room_queue": { + "name": "role_in_room_queue", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "role_on_room_pull": { + "name": "role_on_room_pull", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "role_in_sub_queue": { + "name": "role_in_sub_queue", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "role_on_sub_pull": { + "name": "role_on_sub_pull", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "auto_pull_subs_at_room_start_toggle": { + "name": "auto_pull_subs_at_room_start_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "shuffle_subs_before_auto_pull_toggle": { + "name": "shuffle_subs_before_auto_pull_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "sub_auto_pull_mode": { + "name": "sub_auto_pull_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'drain'" + }, + "create_discord_event": { + "name": "create_discord_event", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "discord_event_description": { + "name": "discord_event_description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "winner_role_id": { + "name": "winner_role_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_guild_id_index": { + "name": "event_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_name_guild_id_unique": { + "name": "event_name_guild_id_unique", + "columns": [ + "name", + "guild_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_guild_id_guild_guild_id_fk": { + "name": "event_guild_id_guild_guild_id_fk", + "tableFrom": "event", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_whitelisted": { + "name": "event_whitelisted", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "event_whitelisted_guild_id_index": { + "name": "event_whitelisted_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_whitelisted_event_id_index": { + "name": "event_whitelisted_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_whitelisted_event_id_subject_id_unique": { + "name": "event_whitelisted_event_id_subject_id_unique", + "columns": [ + "event_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_whitelisted_guild_id_guild_guild_id_fk": { + "name": "event_whitelisted_guild_id_guild_guild_id_fk", + "tableFrom": "event_whitelisted", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_whitelisted_event_id_event_id_fk": { + "name": "event_whitelisted_event_id_event_id_fk", + "tableFrom": "event_whitelisted", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "event_winner": { + "name": "event_winner", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "event_id": { + "name": "event_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "role_id": { + "name": "role_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "declared_at": { + "name": "declared_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "event_winner_guild_id_index": { + "name": "event_winner_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "event_winner_event_id_index": { + "name": "event_winner_event_id_index", + "columns": [ + "event_id" + ], + "isUnique": false + }, + "event_winner_event_id_user_id_unique": { + "name": "event_winner_event_id_user_id_unique", + "columns": [ + "event_id", + "user_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "event_winner_guild_id_guild_guild_id_fk": { + "name": "event_winner_guild_id_guild_guild_id_fk", + "tableFrom": "event_winner", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "event_winner_event_id_event_id_fk": { + "name": "event_winner_event_id_event_id_fk", + "tableFrom": "event_winner", + "tableTo": "event", + "columnsFrom": [ + "event_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "guild_blacklisted": { + "name": "guild_blacklisted", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "guild_blacklisted_guild_id_index": { + "name": "guild_blacklisted_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "guild_blacklisted_guild_id_subject_id_unique": { + "name": "guild_blacklisted_guild_id_subject_id_unique", + "columns": [ + "guild_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "guild_blacklisted_guild_id_guild_guild_id_fk": { + "name": "guild_blacklisted_guild_id_guild_guild_id_fk", + "tableFrom": "guild_blacklisted", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "guild_prioritized": { + "name": "guild_prioritized", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "priority_order": { + "name": "priority_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 5 + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "guild_prioritized_guild_id_index": { + "name": "guild_prioritized_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "guild_prioritized_guild_id_subject_id_unique": { + "name": "guild_prioritized_guild_id_subject_id_unique", + "columns": [ + "guild_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "guild_prioritized_guild_id_guild_guild_id_fk": { + "name": "guild_prioritized_guild_id_guild_guild_id_fk", + "tableFrom": "guild_prioritized", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "guild": { + "name": "guild", + "columns": { + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "log_channel_id": { + "name": "log_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "log_scope": { + "name": "log_scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "joinTime": { + "name": "joinTime", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "last_updated_time": { + "name": "last_updated_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "messages_received": { + "name": "messages_received", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "commands_received": { + "name": "commands_received", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "buttons_received": { + "name": "buttons_received", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "queues_added": { + "name": "queues_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "voices_added": { + "name": "voices_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "displays_added": { + "name": "displays_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "members_added": { + "name": "members_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "schedules_added": { + "name": "schedules_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "whitelisted_added": { + "name": "whitelisted_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "blacklisted_added": { + "name": "blacklisted_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "prioritized_added": { + "name": "prioritized_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "admins_added": { + "name": "admins_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "archived_members_added": { + "name": "archived_members_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "events_added": { + "name": "events_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "guild_whitelisted": { + "name": "guild_whitelisted", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "guild_whitelisted_guild_id_index": { + "name": "guild_whitelisted_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "guild_whitelisted_guild_id_subject_id_unique": { + "name": "guild_whitelisted_guild_id_subject_id_unique", + "columns": [ + "guild_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "guild_whitelisted_guild_id_guild_guild_id_fk": { + "name": "guild_whitelisted_guild_id_guild_guild_id_fk", + "tableFrom": "guild_whitelisted", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "member": { + "name": "member", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "position_time": { + "name": "position_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "join_time": { + "name": "join_time", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "priority_order": { + "name": "priority_order", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "member_guild_id_index": { + "name": "member_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "member_priority_order_index": { + "name": "member_priority_order_index", + "columns": [ + "priority_order" + ], + "isUnique": false + }, + "member_position_time_index": { + "name": "member_position_time_index", + "columns": [ + "position_time" + ], + "isUnique": false + }, + "member_queue_id_user_id_unique": { + "name": "member_queue_id_user_id_unique", + "columns": [ + "queue_id", + "user_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "member_guild_id_guild_guild_id_fk": { + "name": "member_guild_id_guild_guild_id_fk", + "tableFrom": "member", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_queue_id_queue_id_fk": { + "name": "member_queue_id_queue_id_fk", + "tableFrom": "member", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "patch_note": { + "name": "patch_note", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "file_name": { + "name": "file_name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "prioritized": { + "name": "prioritized", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "priority_order": { + "name": "priority_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 5 + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "prioritized_guild_id_index": { + "name": "prioritized_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "prioritized_queue_id_subject_id_unique": { + "name": "prioritized_queue_id_subject_id_unique", + "columns": [ + "queue_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "prioritized_guild_id_guild_guild_id_fk": { + "name": "prioritized_guild_id_guild_guild_id_fk", + "tableFrom": "prioritized", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "prioritized_queue_id_queue_id_fk": { + "name": "prioritized_queue_id_queue_id_fk", + "tableFrom": "prioritized", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "queue": { + "name": "queue", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "autopull_toggle": { + "name": "autopull_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "badge_toggle": { + "name": "badge_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Random'" + }, + "display_update_type": { + "name": "display_update_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'edit'" + }, + "dm_on_pull_toggle": { + "name": "dm_on_pull_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "buttons_toggles": { + "name": "buttons_toggles", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'all'" + }, + "header": { + "name": "header", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "inline_toggle": { + "name": "inline_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "lock_toggle": { + "name": "lock_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "member_display_type": { + "name": "member_display_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'mention'" + }, + "pull_batch_size": { + "name": "pull_batch_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "pull_message": { + "name": "pull_message", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "pull_message_display_type": { + "name": "pull_message_display_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'private'" + }, + "pull_message_channel_id": { + "name": "pull_message_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "rejoin_cooldown_period": { + "name": "rejoin_cooldown_period", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "rejoin_grace_period": { + "name": "rejoin_grace_period", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "require_message_to_join": { + "name": "require_message_to_join", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "role_in_queue_id": { + "name": "role_in_queue_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role_on_pull_id": { + "name": "role_on_pull_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "time_display_type": { + "name": "time_display_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'off'" + }, + "voice_destination_channel_id": { + "name": "voice_destination_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "voice_only_toggle": { + "name": "voice_only_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + } + }, + "indexes": { + "queue_guild_id_index": { + "name": "queue_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "queue_name_guild_id_unique": { + "name": "queue_name_guild_id_unique", + "columns": [ + "name", + "guild_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "queue_guild_id_guild_guild_id_fk": { + "name": "queue_guild_id_guild_guild_id_fk", + "tableFrom": "queue", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "schedule": { + "name": "schedule", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "command": { + "name": "command", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "cron": { + "name": "cron", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'america/chicago'" + }, + "message_channel_id": { + "name": "message_channel_id", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "schedule_guild_id_index": { + "name": "schedule_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "schedule_queue_id_command_cron_timezone_unique": { + "name": "schedule_queue_id_command_cron_timezone_unique", + "columns": [ + "queue_id", + "command", + "cron", + "timezone" + ], + "isUnique": true + } + }, + "foreignKeys": { + "schedule_guild_id_guild_guild_id_fk": { + "name": "schedule_guild_id_guild_guild_id_fk", + "tableFrom": "schedule", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "schedule_queue_id_queue_id_fk": { + "name": "schedule_queue_id_queue_id_fk", + "tableFrom": "schedule", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "voice": { + "name": "voice", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_channel_id": { + "name": "source_channel_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "join_sync_toggle": { + "name": "join_sync_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "leave_sync_toggle": { + "name": "leave_sync_toggle", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + } + }, + "indexes": { + "voice_guild_id_index": { + "name": "voice_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "voice_queue_id_source_channel_id_unique": { + "name": "voice_queue_id_source_channel_id_unique", + "columns": [ + "queue_id", + "source_channel_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "voice_guild_id_guild_guild_id_fk": { + "name": "voice_guild_id_guild_guild_id_fk", + "tableFrom": "voice", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "voice_queue_id_queue_id_fk": { + "name": "voice_queue_id_queue_id_fk", + "tableFrom": "voice", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "whitelisted": { + "name": "whitelisted", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "guild_id": { + "name": "guild_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "queue_id": { + "name": "queue_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "subject_id": { + "name": "subject_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "is_role": { + "name": "is_role", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "whitelisted_guild_id_index": { + "name": "whitelisted_guild_id_index", + "columns": [ + "guild_id" + ], + "isUnique": false + }, + "whitelisted_queue_id_subject_id_unique": { + "name": "whitelisted_queue_id_subject_id_unique", + "columns": [ + "queue_id", + "subject_id" + ], + "isUnique": true + } + }, + "foreignKeys": { + "whitelisted_guild_id_guild_guild_id_fk": { + "name": "whitelisted_guild_id_guild_guild_id_fk", + "tableFrom": "whitelisted", + "tableTo": "guild", + "columnsFrom": [ + "guild_id" + ], + "columnsTo": [ + "guild_id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "whitelisted_queue_id_queue_id_fk": { + "name": "whitelisted_queue_id_queue_id_fk", + "tableFrom": "whitelisted", + "tableTo": "queue", + "columnsFrom": [ + "queue_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +} \ No newline at end of file diff --git a/data/migrations/meta/_journal.json b/data/migrations/meta/_journal.json index a8405f2..4d1c94d 100644 --- a/data/migrations/meta/_journal.json +++ b/data/migrations/meta/_journal.json @@ -99,6 +99,13 @@ "when": 1780196657727, "tag": "0013_mature_steve_rogers", "breakpoints": true + }, + { + "idx": 14, + "version": "6", + "when": 1780204452392, + "tag": "0014_narrow_wind_dancer", + "breakpoints": true } ] } \ No newline at end of file diff --git a/src/commands/commands/events.command.ts b/src/commands/commands/events.command.ts index d2b1d2d..cc3d8b3 100644 --- a/src/commands/commands/events.command.ts +++ b/src/commands/commands/events.command.ts @@ -47,7 +47,6 @@ import { RoleOnRoomPullOption } from "../../options/options/role-on-room-pull.op import { RoleOnSubPullOption } from "../../options/options/role-on-sub-pull.option.ts"; import { RoomCategoryOption } from "../../options/options/room-category.option.ts"; import { RoomCountOption } from "../../options/options/room-count.option.ts"; -import { RoomIndexOption } from "../../options/options/room-index.option.ts"; import { RoomLengthMinutesOption } from "../../options/options/room-length-minutes.option.ts"; import { RoomPingMessageOption } from "../../options/options/room-ping-message.option.ts"; import { RoomQueuesChannelOption } from "../../options/options/room-queues-channel.option.ts"; @@ -69,14 +68,13 @@ import { AdminCommand } from "../../types/command.types.ts"; import { Color, EventQueueRole, type RoomScheduling, type SubAutoPullMode } from "../../types/db.types.ts"; import type { SlashInteraction } from "../../types/interaction.types.ts"; import { DateUtils } from "../../utils/date.utils.ts"; -import { CustomError, EventNotFoundWarning, RoomIndexNotFoundWarning, WinnerRoleNotSetWarning } from "../../utils/error.utils.ts"; +import { CustomError, EventNotFoundWarning, WinnerRoleNotSetWarning } from "../../utils/error.utils.ts"; import { EventUtils } from "../../utils/event.utils.ts"; import { EventChannelUtils } from "../../utils/event-channel.utils.ts"; import { EventSyncLock } from "../../utils/event-sync-lock.utils.ts"; import { SelectMenuTransactor } from "../../utils/message-utils/select-menu-transactor.ts"; import { toCollection } from "../../utils/misc.utils.ts"; import { commandMention, describeTable, eventMention, queuesMention } from "../../utils/string.utils.ts"; -import { groupWinnersByRoom } from "../../utils/winner.logic.ts"; import { WinnerUtils } from "../../utils/winner.utils.ts"; const HOURS_TO_MS = 3_600_000n; @@ -258,21 +256,21 @@ export class EventsCommand extends AdminCommand { .addSubcommand(subcommand => { subcommand .setName("declare-winners") - .setDescription("Grant the winner role to a room's winner(s)"); + .setDescription("Grant the winner role to the event's winner(s)"); Object.values(EventsCommand.DECLARE_WINNERS_OPTIONS).forEach(option => option.addToCommand(subcommand)); return subcommand; }) .addSubcommand(subcommand => { subcommand .setName("winners") - .setDescription("List declared winners per room"); + .setDescription("List declared winners"); Object.values(EventsCommand.WINNERS_OPTIONS).forEach(option => option.addToCommand(subcommand)); return subcommand; }) .addSubcommand(subcommand => { subcommand .setName("clear-winners") - .setDescription("Revoke winner role(s) for a room or the whole event"); + .setDescription("Revoke the winner role for the event"); Object.values(EventsCommand.CLEAR_WINNERS_OPTIONS).forEach(option => option.addToCommand(subcommand)); return subcommand; }) @@ -457,7 +455,7 @@ export class EventsCommand extends AdminCommand { subAutoPullMode: new SubAutoPullModeOption({ description: "Auto-pull mode" }), createDiscordEvent: new CreateDiscordEventToggleOption({ description: "Create Discord scheduled event per occurrence" }), discordEventDescription: new DiscordEventDescriptionOption({ description: "Use {event_name}, {start_time}, {start_time_relative}, {room_queues_channel}, {sub_queues_channel}" }), - winnerRole: new WinnerRoleOption({ description: "Role granted to declared room winners" }), + winnerRole: new WinnerRoleOption({ description: "Role granted to declared winners" }), }; static async events_set(inter: SlashInteraction) { @@ -1087,12 +1085,11 @@ export class EventsCommand extends AdminCommand { static readonly DECLARE_WINNERS_OPTIONS = { event: new EventOption({ required: true, description: "Target event" }), - roomIndex: new RoomIndexOption({ required: true, description: "Room number (1..room count)" }), - winner1: new UserOption({ required: true, id: "winner_1", description: "A room winner" }), - winner2: new UserOption({ id: "winner_2", description: "A room winner" }), - winner3: new UserOption({ id: "winner_3", description: "A room winner" }), - winner4: new UserOption({ id: "winner_4", description: "A room winner" }), - winner5: new UserOption({ id: "winner_5", description: "A room winner" }), + winner1: new UserOption({ required: true, id: "winner_1", description: "A winner" }), + winner2: new UserOption({ id: "winner_2", description: "A winner" }), + winner3: new UserOption({ id: "winner_3", description: "A winner" }), + winner4: new UserOption({ id: "winner_4", description: "A winner" }), + winner5: new UserOption({ id: "winner_5", description: "A winner" }), }; static async events_declare_winners(inter: SlashInteraction) { @@ -1101,10 +1098,6 @@ export class EventsCommand extends AdminCommand { if (!event.winnerRoleId) { throw new WinnerRoleNotSetWarning(); } - const roomIndex = EventsCommand.DECLARE_WINNERS_OPTIONS.roomIndex.get(inter); - if (roomIndex < 1 || BigInt(roomIndex) > event.roomCount) { - throw new RoomIndexNotFoundWarning(Number(event.roomCount)); - } const userIds = new Set(compact([ EventsCommand.DECLARE_WINNERS_OPTIONS.winner1.get(inter), @@ -1114,16 +1107,16 @@ export class EventsCommand extends AdminCommand { EventsCommand.DECLARE_WINNERS_OPTIONS.winner5.get(inter), ]).map(user => user.id)); - const added = await WinnerUtils.declareRoomWinners(inter.store, event, BigInt(roomIndex), userIds); + const added = await WinnerUtils.declareWinners(inter.store, event, userIds); if (added.length === 0) { - await inter.respond(`No new winners added to room ${roomIndex} of ${eventMention(event)} — all selected users already win that room.`, true); + await inter.respond(`No new winners added to ${eventMention(event)} — all selected users are already winners.`, true); return; } const mentions = added.map(userMention).join(", "); await inter.respond( - `Granted ${roleMention(event.winnerRoleId)} to ${mentions} as winner(s) of room ${roomIndex} in ${eventMention(event)}.`, + `Granted ${roleMention(event.winnerRoleId)} to ${mentions} as winner(s) of ${eventMention(event)}.`, true, ); } @@ -1140,22 +1133,20 @@ export class EventsCommand extends AdminCommand { await inter.deferReply(); const event = await EventsCommand.WINNERS_OPTIONS.event.get(inter); - const grouped = groupWinnersByRoom(Queries.selectManyEventWinners({ guildId: inter.guildId, eventId: event.id })); + const rows = Queries.selectManyEventWinners({ guildId: inter.guildId, eventId: event.id }); const roleLine = `Winner role: ${event.winnerRoleId ? roleMention(event.winnerRoleId) : "not set"}`; - if (grouped.size === 0) { + if (rows.length === 0) { await inter.respond(`No winners declared yet for ${eventMention(event)}.\n${roleLine}`); return; } - const roomLines = [...grouped.entries()].map(([roomIndex, userIds]) => - `Room ${roomIndex}: ${userIds.map(userMention).join(", ")}` - ); + const winnerList = rows.map(r => userMention(r.userId)).join(", "); const embed = new EmbedBuilder() .setTitle(`Winners — ${event.name}`) .setColor(Color.Gold) - .setDescription(`${roomLines.join("\n")}\n\n${roleLine}`); + .setDescription(`${winnerList}\n\n${roleLine}`); await inter.respond({ embeds: [embed] }); } @@ -1166,26 +1157,16 @@ export class EventsCommand extends AdminCommand { static readonly CLEAR_WINNERS_OPTIONS = { event: new EventOption({ required: true, description: "Target event" }), - roomIndex: new RoomIndexOption({ description: "Room number to clear (omit = all rooms)" }), }; static async events_clear_winners(inter: SlashInteraction) { await inter.deferReply(); const event = await EventsCommand.CLEAR_WINNERS_OPTIONS.event.get(inter); - const roomIndex = EventsCommand.CLEAR_WINNERS_OPTIONS.roomIndex.get(inter); - if (roomIndex != null && (roomIndex < 1 || BigInt(roomIndex) > event.roomCount)) { - throw new RoomIndexNotFoundWarning(Number(event.roomCount)); - } - const removals = await WinnerUtils.clearEventWinners( - inter.store, - event, - roomIndex != null ? BigInt(roomIndex) : undefined, - ); + const removals = await WinnerUtils.clearEventWinners(inter.store, event); - const scope = roomIndex != null ? `room ${roomIndex}` : "all rooms"; await inter.respond( - `Cleared winners for ${scope} of ${eventMention(event)}. Revoked the role from ${removals.length} member(s).`, + `Cleared winners for ${eventMention(event)}. Revoked the role from ${removals.length} member(s).`, true, ); } @@ -1221,10 +1202,10 @@ export class EventsCommand extends AdminCommand { "- `role_on_room_pull` (default `false`) — assign the role when a user is pulled from the room queue\n" + "- `role_in_sub_queue` (default `false`) — assign the role while a user is in the sub queue\n" + "- `role_on_sub_pull` (default `false`) — assign the role when a user is pulled from the sub queue\n\n" + - "**Declaring winners** — crown a room's winner(s) with one shared role that auto-revokes when the event's next occurrence opens:\n" + + "**Declaring winners** — crown the event's winner(s) with one shared role that auto-revokes when the event's next occurrence opens:\n" + `- Configure the role once via \`winner_role\` on ${commandMention("events", "set")}.\n` + - `- ${commandMention("events", "declare-winners")} (\`room_index\`, \`winner_1\`..\`winner_5\`) grants it — additive, ties allowed; call again for >5 winners.\n` + - `- ${commandMention("events", "winners")} lists winners per room; ${commandMention("events", "clear-winners")} (optional \`room_index\`) revokes early.\n` + + `- ${commandMention("events", "declare-winners")} (\`winner_1\`..\`winner_5\`) grants it — additive, ties allowed; call again for >5 winners.\n` + + `- ${commandMention("events", "winners")} lists current winners; ${commandMention("events", "clear-winners")} revokes early.\n` + "- With multiple occurrences scheduled, the **earliest** one to open revokes the role.\n\n" + "**Auto-pull subs at room start:**\n" + "- `auto_pull_subs_at_room_start_toggle` (default `false`) — at each room's start, lock paired sub and pull subs into the room. Forces room lock at exact `start_time` (ignores `lock_offset`).\n" + diff --git a/src/db/schema.ts b/src/db/schema.ts index a3a9445..3a6a5cc 100644 --- a/src/db/schema.ts +++ b/src/db/schema.ts @@ -281,13 +281,12 @@ export const EVENT_WINNER_TABLE = sqliteTable("event_winner", ({ guildId: text("guild_id").$type().notNull().references(() => GUILD_TABLE.guildId, { onDelete: "cascade" }), eventId: integer("event_id").$type().notNull().references(() => EVENT_TABLE.id, { onDelete: "cascade" }), - roomIndex: integer("room_index").$type().notNull(), userId: text("user_id").$type().notNull(), roleId: text("role_id").$type().notNull(), declaredAt: integer("declared_at").$type().notNull().$defaultFn(() => BigInt(Date.now())), }), (table) => ({ - unq: unique().on(table.eventId, table.roomIndex, table.userId), + unq: unique().on(table.eventId, table.userId), guildIdIndex: index("event_winner_guild_id_index").on(table.guildId), eventIdIndex: index("event_winner_event_id_index").on(table.eventId), })); diff --git a/src/db/store.ts b/src/db/store.ts index 61bdc17..1af71f2 100644 --- a/src/db/store.ts +++ b/src/db/store.ts @@ -630,7 +630,7 @@ export class Store { .returning().get(); } - // idempotent additive declare: (eventId, roomIndex, userId) conflict is a no-op + // idempotent additive declare: (eventId, userId) conflict is a no-op insertEventWinner(row: NewEventWinner): DbEventWinner { return db .insert(EVENT_WINNER_TABLE) @@ -1212,14 +1212,11 @@ export class Store { .returning().all(); } - deleteManyEventWinners(by: { eventId: bigint, roomIndex?: bigint }) { + deleteManyEventWinners(by: { eventId: bigint }) { const conds = [ eq(EVENT_WINNER_TABLE.guildId, this.guild.id), eq(EVENT_WINNER_TABLE.eventId, by.eventId), ]; - if (by.roomIndex !== undefined) { - conds.push(eq(EVENT_WINNER_TABLE.roomIndex, by.roomIndex)); - } return db .delete(EVENT_WINNER_TABLE) .where(and(...conds)) diff --git a/src/options/options.loader.ts b/src/options/options.loader.ts index 16c5da1..efcbfe1 100644 --- a/src/options/options.loader.ts +++ b/src/options/options.loader.ts @@ -69,7 +69,6 @@ import { RoleOnRoomPullOption } from "./options/role-on-room-pull.option.ts"; import { RoleOnSubPullOption } from "./options/role-on-sub-pull.option.ts"; import { RoomCategoryOption } from "./options/room-category.option.ts"; import { RoomCountOption } from "./options/room-count.option.ts"; -import { RoomIndexOption } from "./options/room-index.option.ts"; import { RoomLengthMinutesOption } from "./options/room-length-minutes.option.ts"; import { RoomPingMessageOption } from "./options/room-ping-message.option.ts"; import { RoomQueuesChannelOption } from "./options/room-queues-channel.option.ts"; @@ -162,7 +161,6 @@ export const OPTIONS = new Collection([ [RoleOnSubPullOption.ID, new RoleOnSubPullOption()], [RoomCategoryOption.ID, new RoomCategoryOption()], [RoomCountOption.ID, new RoomCountOption()], - [RoomIndexOption.ID, new RoomIndexOption()], [RoomLengthMinutesOption.ID, new RoomLengthMinutesOption()], [RoomPingMessageOption.ID, new RoomPingMessageOption()], [RoomQueuesChannelOption.ID, new RoomQueuesChannelOption()], diff --git a/src/options/options/room-index.option.ts b/src/options/options/room-index.option.ts deleted file mode 100644 index e7789c0..0000000 --- a/src/options/options/room-index.option.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { IntegerOption } from "../base-option.ts"; - -export class RoomIndexOption extends IntegerOption { - static readonly ID = "room_index"; - id = RoomIndexOption.ID; - minValue = 1; -} diff --git a/src/utils/winner.logic.test.ts b/src/utils/winner.logic.test.ts index b5a1e3f..00fed84 100644 --- a/src/utils/winner.logic.test.ts +++ b/src/utils/winner.logic.test.ts @@ -1,20 +1,6 @@ import { describe, expect, it } from "vitest"; -import type { DbEventWinner } from "../db/schema.ts"; -import { computeRoleRemovals, computeWinnersToAdd, groupWinnersByRoom } from "./winner.logic.ts"; - -function winnerRow(overrides: Partial): DbEventWinner { - return { - id: 1n, - guildId: "g", - eventId: 1n, - roomIndex: 1n, - userId: "u", - roleId: "r", - declaredAt: 0n, - ...overrides, - }; -} +import { computeWinnersToAdd } from "./winner.logic.ts"; describe("computeWinnersToAdd", () => { it("dedupes repeated requested users", () => { @@ -29,44 +15,3 @@ describe("computeWinnersToAdd", () => { expect(computeWinnersToAdd(new Set(["a"]), new Set(["a", "b", "c"]))).toEqual(["b", "c"]); }); }); - -describe("computeRoleRemovals", () => { - it("does not remove a user who still has a remaining row (multi-room win)", () => { - const deleted = [{ userId: "a", roleId: "r" }]; - const remaining = [{ userId: "a" }]; - expect(computeRoleRemovals(deleted, remaining)).toEqual([]); - }); - - it("removes a user whose only row was deleted, carrying the snapshotted roleId", () => { - const deleted = [{ userId: "b", roleId: "role-123" }]; - expect(computeRoleRemovals(deleted, [])).toEqual([{ userId: "b", roleId: "role-123" }]); - }); - - it("removes everyone exactly once on whole-event delete even when duplicated across rooms", () => { - const deleted = [ - { userId: "a", roleId: "r" }, - { userId: "a", roleId: "r" }, - { userId: "b", roleId: "r" }, - ]; - expect(computeRoleRemovals(deleted, [])).toEqual([ - { userId: "a", roleId: "r" }, - { userId: "b", roleId: "r" }, - ]); - }); -}); - -describe("groupWinnersByRoom", () => { - it("groups winners by room ordered ascending, preserving multiple winners per room", () => { - const rows = [ - winnerRow({ id: 1n, roomIndex: 2n, userId: "x" }), - winnerRow({ id: 2n, roomIndex: 1n, userId: "z" }), - winnerRow({ id: 3n, roomIndex: 2n, userId: "y" }), - ]; - - const grouped = groupWinnersByRoom(rows); - - expect([...grouped.keys()]).toEqual([1n, 2n]); - expect(grouped.get(1n)).toEqual(["z"]); - expect(grouped.get(2n)).toEqual(["x", "y"]); - }); -}); diff --git a/src/utils/winner.logic.ts b/src/utils/winner.logic.ts index 6ad529f..d2234c7 100644 --- a/src/utils/winner.logic.ts +++ b/src/utils/winner.logic.ts @@ -1,5 +1,3 @@ -import type { DbEventWinner } from "../db/schema.ts"; - /** * Pure decision functions for the event-winner feature. * @@ -8,47 +6,8 @@ import type { DbEventWinner } from "../db/schema.ts"; */ /** - * Additive union, deduped: the requested userIds that are not already winners of the room. - */ -export function computeWinnersToAdd(existingRoomUserIds: Set, requested: Set): string[] { - return [...requested].filter(userId => !existingRoomUserIds.has(userId)); -} - -/** - * Given the winner rows being deleted and the rows that remain for the event, return the - * (userId, roleId) pairs whose role must be removed — i.e. users with NO remaining row. - * - * Encodes the multi-room-win safety rule: a user who still holds a winning row elsewhere keeps - * the role. Deduped by (userId, roleId) so a user duplicated across rooms is removed exactly once. - */ -export function computeRoleRemovals( - deleted: { userId: string, roleId: string }[], - remaining: { userId: string }[], -): { userId: string, roleId: string }[] { - const remainingUserIds = new Set(remaining.map(row => row.userId)); - const seen = new Set(); - const removals: { userId: string, roleId: string }[] = []; - for (const { userId, roleId } of deleted) { - if (remainingUserIds.has(userId)) continue; - const key = `${userId}:${roleId}`; - if (seen.has(key)) continue; - seen.add(key); - removals.push({ userId, roleId }); - } - return removals; -} - -/** - * For the list command: rows -> ordered map of roomIndex -> userIds (rooms ascending, - * within-room order preserved). + * Additive union, deduped: the requested userIds that are not already winners of the event. */ -export function groupWinnersByRoom(rows: DbEventWinner[]): Map { - const grouped = new Map(); - const ordered = [...rows].sort((a, b) => Number(a.roomIndex) - Number(b.roomIndex)); - for (const row of ordered) { - const userIds = grouped.get(row.roomIndex) ?? []; - userIds.push(row.userId); - grouped.set(row.roomIndex, userIds); - } - return grouped; +export function computeWinnersToAdd(existingUserIds: Set, requested: Set): string[] { + return [...requested].filter(userId => !existingUserIds.has(userId)); } diff --git a/src/utils/winner.utils.ts b/src/utils/winner.utils.ts index 9ebdccb..6a2ebbc 100644 --- a/src/utils/winner.utils.ts +++ b/src/utils/winner.utils.ts @@ -4,7 +4,7 @@ import { Queries } from "../db/queries.ts"; import type { DbEvent } from "../db/schema.ts"; import type { Store } from "../db/store.ts"; import { MemberUtils } from "./member.utils.ts"; -import { computeRoleRemovals, computeWinnersToAdd } from "./winner.logic.ts"; +import { computeWinnersToAdd } from "./winner.logic.ts"; /** * `WinnerUtils` orchestrates the event-winner Store/Queries writes and the Discord role @@ -27,24 +27,22 @@ export namespace WinnerUtils { } /** - * Additive declaration: grants the event's winner role to the requested users for `roomIndex`, - * skipping any who already win that room. Returns the userIds newly added. + * Additive declaration: grants the event's winner role to the requested users, skipping any who + * are already winners of the event. Returns the userIds newly added. */ - export async function declareRoomWinners( + export async function declareWinners( store: Store, event: DbEvent, - roomIndex: bigint, requested: Set, ): Promise { const rows = Queries.selectManyEventWinners({ guildId: store.guild.id, eventId: event.id }); - const existingForRoom = new Set(rows.filter(row => row.roomIndex === roomIndex).map(row => row.userId)); - const toAdd = computeWinnersToAdd(existingForRoom, requested); + const existing = new Set(rows.map(row => row.userId)); + const toAdd = computeWinnersToAdd(existing, requested); for (const userId of toAdd) { store.insertEventWinner({ guildId: store.guild.id, eventId: event.id, - roomIndex, userId, roleId: event.winnerRoleId, }); @@ -55,22 +53,19 @@ export namespace WinnerUtils { } /** - * Clears winner rows for the whole event (or a single `roomIndex`), revoking the role only - * from users who no longer hold any winning row. Uses each row's snapshotted `roleId`, so it - * works even if `event.winnerRoleId` was later changed or cleared. Returns the role removals. + * Clears all of the event's winner rows, revoking the role from each winner. Uses each row's + * snapshotted `roleId`, so it works even if `event.winnerRoleId` was later changed or cleared. + * With one row per winner there is nothing to dedup. Returns the role removals. */ export async function clearEventWinners( store: Store, event: DbEvent, - roomIndex?: bigint, ): Promise<{ userId: string, roleId: string }[]> { - const rows = Queries.selectManyEventWinners({ guildId: store.guild.id, eventId: event.id }); - const deleted = roomIndex != null ? rows.filter(row => row.roomIndex === roomIndex) : rows; - const remaining = roomIndex != null ? rows.filter(row => row.roomIndex !== roomIndex) : []; + const deleted = Queries.selectManyEventWinners({ guildId: store.guild.id, eventId: event.id }); - store.deleteManyEventWinners(roomIndex != null ? { eventId: event.id, roomIndex } : { eventId: event.id }); + store.deleteManyEventWinners({ eventId: event.id }); - const removals = computeRoleRemovals(deleted, remaining); + const removals = deleted.map(row => ({ userId: row.userId, roleId: row.roleId })); for (const { userId, roleId } of removals) { await applyRole(store, userId, roleId, "remove"); }