diff --git a/AGENTS.md b/AGENTS.md index 9e5474571..7a19d6116 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -57,8 +57,9 @@ ## SQL -- database is Sqlite3 used with the Kysely library +- database is Sqlite3, driven by Node's built-in `node:sqlite` through a custom Kysely dialect (`app/db/node-sqlite-dialect.ts`) - database code should only be written in Repository files, see [repositories.md](./docs/dev/repositories.md) for their conventions +- migrations are Kysely migrations in `/migrations`, scaffolded with `pnpm run migrate:new "description"` and applied with `pnpm run migrate up`, see [how-to.md](./docs/dev/how-to.md) - down migrations are not needed, only up migrations - every database id is of type number - if we are working on a branch by default we should add to the migration this branch added instead of creating a brand new one diff --git a/app/db/node-sqlite-dialect.ts b/app/db/node-sqlite-dialect.ts new file mode 100644 index 000000000..4b784f21e --- /dev/null +++ b/app/db/node-sqlite-dialect.ts @@ -0,0 +1,322 @@ +import type { + DatabaseSync, + SQLInputValue, + SQLOutputValue, + StatementSync, +} from "node:sqlite"; +import { + CompiledQuery, + createQueryId, + type DatabaseConnection, + type Dialect, + type Driver, + IdentifierNode, + type Kysely, + type QueryCompiler, + type QueryResult, + RawNode, + SelectQueryNode, + SqliteAdapter, + SqliteIntrospector, + SqliteQueryCompiler, +} from "kysely"; + +/** + * Query kinds whose compiled SQL is stable enough to keep a prepared statement + * around for. Everything else (DDL, raw SQL, `begin`/`commit`) is prepared fresh. + */ +const CACHEABLE_QUERY_KINDS = new Set([ + "SelectQueryNode", + "InsertQueryNode", + "UpdateQueryNode", + "DeleteQueryNode", + "MergeQueryNode", +]); + +/** + * Leading keywords of raw statements that can not change the schema, so the + * column lists the statement cache is holding stay valid across them. Raw DDL + * (`create`, `alter`, `drop`, ...) is not here and clears the cache. + */ +const SCHEMA_PRESERVING_RAW_COMMANDS = new Set([ + "begin", + "commit", + "rollback", + "savepoint", + "release", + "select", + "with", + "insert", + "update", + "delete", + "replace", + "pragma", + "analyze", + "explain", +]); + +const STATEMENT_CACHE_SIZE = 5000; + +export interface NodeSqliteDialectConfig { + database: DatabaseSync; + /** + * Keeps prepared statements around between queries, keyed by their SQL. Saves + * a re-compile per query at the cost of holding onto the compiled programs. + * Off by default because it assumes the schema does not change under the + * connection, which is not true while migrations run. + */ + cacheStatements?: boolean; +} + +/** + * Kysely dialect backed by Node's built-in `node:sqlite` module, replacing the + * `better-sqlite3` native addon that Kysely's own `SqliteDialect` expects. + * + * Rows come back from `node:sqlite` as arrays rather than objects: the objects it + * builds itself are both slower to produce and have a `null` prototype, which is + * not what the rest of the codebase (or Kysely's own dialects) hand out. + */ +export class NodeSqliteDialect implements Dialect { + readonly #config: NodeSqliteDialectConfig; + + constructor(config: NodeSqliteDialectConfig) { + this.#config = config; + } + + createDriver(): Driver { + return new NodeSqliteDriver(this.#config); + } + + createQueryCompiler(): QueryCompiler { + return new SqliteQueryCompiler(); + } + + createAdapter(): SqliteAdapter { + return new SqliteAdapter(); + } + + createIntrospector(db: Kysely): SqliteIntrospector { + return new SqliteIntrospector(db); + } +} + +class NodeSqliteDriver implements Driver { + readonly #config: NodeSqliteDialectConfig; + #connection?: NodeSqliteConnection; + + constructor(config: NodeSqliteDialectConfig) { + this.#config = config; + } + + async init(): Promise { + this.#connection = new NodeSqliteConnection(this.#config); + } + + async acquireConnection(): Promise { + return this.#connection!; + } + + async beginTransaction(connection: DatabaseConnection): Promise { + await connection.executeQuery(CompiledQuery.raw("begin")); + } + + async commitTransaction(connection: DatabaseConnection): Promise { + await connection.executeQuery(CompiledQuery.raw("commit")); + } + + async rollbackTransaction(connection: DatabaseConnection): Promise { + await connection.executeQuery(CompiledQuery.raw("rollback")); + } + + async savepoint( + connection: DatabaseConnection, + savepointName: string, + compileQuery: QueryCompiler["compileQuery"], + ): Promise { + await connection.executeQuery( + compileQuery( + savepointCommand("savepoint", savepointName), + createQueryId(), + ), + ); + } + + async rollbackToSavepoint( + connection: DatabaseConnection, + savepointName: string, + compileQuery: QueryCompiler["compileQuery"], + ): Promise { + await connection.executeQuery( + compileQuery( + savepointCommand("rollback to", savepointName), + createQueryId(), + ), + ); + } + + async releaseSavepoint( + connection: DatabaseConnection, + savepointName: string, + compileQuery: QueryCompiler["compileQuery"], + ): Promise { + await connection.executeQuery( + compileQuery(savepointCommand("release", savepointName), createQueryId()), + ); + } + + async releaseConnection(): Promise { + // the single connection is never handed back to a pool + } + + async destroy(): Promise { + this.#connection?.dispose(); + this.#config.database.close(); + } +} + +interface PreparedStatement { + statement: StatementSync; + /** Empty for statements that return no rows, which is how writes are detected. */ + columnNames: string[]; +} + +class NodeSqliteConnection implements DatabaseConnection { + readonly #database: DatabaseSync; + readonly #cacheStatements: boolean; + readonly #cache = new Map(); + + constructor(config: NodeSqliteDialectConfig) { + this.#database = config.database; + this.#cacheStatements = config.cacheStatements ?? false; + } + + async executeQuery(compiledQuery: CompiledQuery): Promise> { + const prepared = this.#preparedStatementFor(compiledQuery); + const parameters = compiledQuery.parameters as SQLInputValue[]; + + if (prepared.columnNames.length > 0) { + return { rows: readRows(prepared, parameters) }; + } + + const { changes, lastInsertRowid } = prepared.statement.run(...parameters); + + return { + insertId: BigInt(lastInsertRowid), + numAffectedRows: BigInt(changes), + rows: [], + }; + } + + async *streamQuery( + compiledQuery: CompiledQuery, + ): AsyncIterableIterator> { + if (!SelectQueryNode.is(compiledQuery.query)) { + throw new Error( + "Sqlite driver only supports streaming of select queries", + ); + } + + // deliberately uncached: the cursor stays open across yields, so sharing the + // statement with another query would reset it mid-iteration + const prepared = prepare(this.#database, compiledQuery.sql); + const parameters = compiledQuery.parameters as SQLInputValue[]; + + for (const row of prepared.statement.iterate(...parameters)) { + yield { + rows: [ + toRow(prepared.columnNames, row as unknown as SQLOutputValue[]), + ], + }; + } + } + + dispose() { + this.#cache.clear(); + } + + #preparedStatementFor(compiledQuery: CompiledQuery): PreparedStatement { + const { sql, query } = compiledQuery; + + if (!this.#cacheStatements || !CACHEABLE_QUERY_KINDS.has(query.kind)) { + // a schema change invalidates every column list the cache is holding + if (query.kind !== "RawNode" || canChangeSchema(sql)) { + this.#cache.clear(); + } + + return prepare(this.#database, sql); + } + + const cached = this.#cache.get(sql); + if (cached) { + // re-insert so the least recently used entry stays at the front + this.#cache.delete(sql); + this.#cache.set(sql, cached); + return cached; + } + + const prepared = prepare(this.#database, sql); + + if (this.#cache.size >= STATEMENT_CACHE_SIZE) { + this.#cache.delete(this.#cache.keys().next().value!); + } + this.#cache.set(sql, prepared); + + return prepared; + } +} + +function canChangeSchema(sql: string) { + const firstKeyword = sql + .trimStart() + .split(/[\s;(]/, 1)[0] + .toLowerCase(); + + return !SCHEMA_PRESERVING_RAW_COMMANDS.has(firstKeyword); +} + +function prepare(database: DatabaseSync, sql: string): PreparedStatement { + const statement = database.prepare(sql); + statement.setReturnArrays(true); + + return { statement, columnNames: statement.columns().map((it) => it.name) }; +} + +function readRows( + prepared: PreparedStatement, + parameters: SQLInputValue[], +): R[] { + const rawRows = prepared.statement.all( + ...parameters, + ) as unknown as SQLOutputValue[][]; + + if (rawRows.length === 0) return []; + + // `select *` widens when a migration adds a column, leaving a cached statement + // with a stale column list until the next read notices the mismatch + if (rawRows[0].length !== prepared.columnNames.length) { + prepared.columnNames = prepared.statement.columns().map((it) => it.name); + } + + const rows = new Array(rawRows.length); + for (let i = 0; i < rawRows.length; i++) { + rows[i] = toRow(prepared.columnNames, rawRows[i]); + } + + return rows; +} + +function toRow(columnNames: string[], rawRow: SQLOutputValue[]): R { + const row: Record = {}; + for (let i = 0; i < columnNames.length; i++) { + row[columnNames[i]] = rawRow[i]; + } + + return row as R; +} + +function savepointCommand(command: string, savepointName: string) { + return RawNode.createWithChildren([ + RawNode.createWithSql(`${command} `), + IdentifierNode.create(savepointName), + ]); +} diff --git a/app/db/reset.ts b/app/db/reset.ts index e24410665..04e69ca7f 100644 --- a/app/db/reset.ts +++ b/app/db/reset.ts @@ -1,37 +1,18 @@ -import { sql } from "kysely"; import { resetFactories } from "~/db/seed/core/defineFactory"; -import { db } from "~/db/sql"; +import { deleteAllRows } from "~/db/wipe"; import { markDatabaseClean } from "~/db/write-tracker"; /** * Resets all data in the database by deleting all rows from every table, - * except for SQLite system tables and the 'migrations' table. + * except for SQLite system tables and the kysely migration bookkeeping tables + * (`kysely_migration` and `kysely_migration_lock`). * * Tests do not call this — `app/test-setup.ts` runs it after every vitest test that * wrote anything, and the e2e reset fixture before every test. Call it by hand only * to wipe *within* a test. */ export const dbReset = async () => { - // virtual tables and their shadow tables (e.g. UserSearch_data) can not be - // deleted from directly; the fts index stays in sync via the User triggers - const { rows: tables } = await sql<{ name: string }>` - SELECT name FROM sqlite_master - WHERE type='table' - AND name NOT LIKE 'sqlite_%' - AND name NOT LIKE 'migrations' - AND sql NOT LIKE 'CREATE VIRTUAL TABLE%' - AND NOT EXISTS ( - SELECT 1 FROM sqlite_master AS vt - WHERE vt.sql LIKE 'CREATE VIRTUAL TABLE%' - AND sqlite_master.name LIKE vt.name || '_%' - ) - `.execute(db); - - await sql`PRAGMA foreign_keys = OFF`.execute(db); - for (const table of tables) { - await sql`DELETE FROM ${sql.table(table.name)}`.execute(db); - } - await sql`PRAGMA foreign_keys = ON`.execute(db); + await deleteAllRows(); resetFactories(); // last, because the deletes above are themselves writes diff --git a/app/db/seed/index.ts b/app/db/seed/index.ts index 98c346785..2b8d34709 100644 --- a/app/db/seed/index.ts +++ b/app/db/seed/index.ts @@ -1,5 +1,4 @@ -import { sql } from "kysely"; -import { db } from "~/db/sql"; +import { deleteAllRows } from "~/db/wipe"; import { clearAllTournamentDataCache } from "~/features/tournament-bracket/core/Tournament.server"; import { withoutInfoLogs } from "~/utils/logger"; import { resetFactories } from "./core/defineFactory"; @@ -20,7 +19,7 @@ import { seedUsers } from "./dev/users"; import { seedVods } from "./dev/vods"; export async function seed() { - await wipeDB(); + await deleteAllRows(); resetFactories(); const users = await runModule(() => seedUsers()); @@ -55,26 +54,3 @@ function runModule(module: () => Promise) { return withoutInfoLogs(module); } - -async function wipeDB() { - // virtual tables and their shadow tables (e.g. UserSearch_data) can not be - // deleted from directly; the fts index stays in sync via the User triggers - const { rows: tables } = await sql<{ name: string }>` - SELECT name FROM sqlite_master - WHERE type='table' - AND name NOT LIKE 'sqlite_%' - AND name NOT LIKE 'migrations' - AND sql NOT LIKE 'CREATE VIRTUAL TABLE%' - AND NOT EXISTS ( - SELECT 1 FROM sqlite_master AS vt - WHERE vt.sql LIKE 'CREATE VIRTUAL TABLE%' - AND sqlite_master.name LIKE vt.name || '_%' - ) - `.execute(db); - - await sql`PRAGMA foreign_keys = OFF`.execute(db); - for (const table of tables) { - await sql`DELETE FROM ${sql.table(table.name)}`.execute(db); - } - await sql`PRAGMA foreign_keys = ON`.execute(db); -} diff --git a/app/db/sql.ts b/app/db/sql.ts index 2d205d336..d17b261fb 100644 --- a/app/db/sql.ts +++ b/app/db/sql.ts @@ -1,37 +1,42 @@ +import { DatabaseSync } from "node:sqlite"; import { styleText } from "node:util"; import * as Sentry from "@sentry/react-router"; -import Database from "better-sqlite3"; -import { Kysely, type LogEvent, SqliteDialect } from "kysely"; +import { Kysely, type LogEvent } from "kysely"; import { format } from "sql-formatter"; import { Config } from "~/config"; import { ServerConfig } from "~/config.server"; import { logger } from "~/utils/logger"; import { roundToNDecimalPlaces } from "~/utils/number"; import { EmptyValuesNoopPlugin } from "./empty-values-noop-plugin"; +import { NodeSqliteDialect } from "./node-sqlite-dialect"; import { FastParseJSONResultsPlugin } from "./parse-json-results-plugin"; import type { DB } from "./tables"; import { WriteTrackerPlugin } from "./write-tracker"; -const sql = new Database( - ServerConfig.isTest ? migratedEmptyDb() : ServerConfig.dbPath, +const sql = new DatabaseSync( + ServerConfig.isTest ? ":memory:" : ServerConfig.dbPath, ); -sql.pragma("journal_mode = WAL"); +if (ServerConfig.isTest) { + applyMigratedSchema(sql); +} + +sql.exec("PRAGMA journal_mode = WAL"); // The synchronous=NORMAL setting provides the best balance between performance and safety for most applications running in WAL mode. // You lose durability across power lose with synchronous NORMAL in WAL mode, but that is not important for most applications. // Transactions are still atomic, consistent, and isolated, which are the most important characteristics in most use cases. // Source: https://sqlite.org/pragma.html -sql.pragma("synchronous = NORMAL"); -sql.pragma("foreign_keys = ON"); -sql.pragma("busy_timeout = 5000"); +sql.exec("PRAGMA synchronous = NORMAL"); +sql.exec("PRAGMA foreign_keys = ON"); +sql.exec("PRAGMA busy_timeout = 5000"); // 64MB page cache (default is 2MB) -sql.pragma("cache_size = -65536"); +sql.exec("PRAGMA cache_size = -65536"); // lets reads come straight from the OS page cache without read() syscalls // Source: https://sqlite.org/mmap.html -sql.pragma("mmap_size = 3221225472"); +sql.exec("PRAGMA mmap_size = 3221225472"); // see https://sqlite.org/pragma.html#pragma_optimize — recommended for long-lived // connections; pair with a periodic `PRAGMA optimize;` (see OptimizeDatabase routine) -sql.pragma("optimize = 0x10002"); +sql.exec("PRAGMA optimize = 0x10002"); // Strips diacritics so accent-insensitive name searches are possible // (e.g. "cafe" matches "Café"). Combined with LIKE's built-in ASCII @@ -43,8 +48,9 @@ sql.function("unaccent", { deterministic: true }, (value) => ); export const db = new Kysely({ - dialect: new SqliteDialect({ + dialect: new NodeSqliteDialect({ database: sql, + cacheStatements: true, }), log, plugins: [ @@ -54,17 +60,39 @@ export const db = new Kysely({ ], }); -// The test database file is created and migrated by scripts/ensure-test-db.ts -// (vitest globalSetup) before any test worker imports this module. -function migratedEmptyDb() { - const testDb = new Database("db-test.sqlite3", { - readonly: true, - fileMustExist: true, +// Every test worker gets its own in-memory database, built by replaying the +// schema of the migrated (and otherwise empty) file that scripts/ensure-test-db.ts +// creates in vitest's globalSetup. Replaying the DDL rather than copying the file +// is what `node:sqlite` allows: unlike better-sqlite3 it cannot deserialize a +// database into memory. +function applyMigratedSchema(target: DatabaseSync) { + const source = new DatabaseSync("db-test.sqlite3", { + readOnly: true, + timeout: 5000, }); + try { - return testDb.serialize(); + // virtual tables create their own shadow tables (e.g. UserSearch_data), so + // replaying those would fail on a table that already exists + const statements = source + .prepare(` + SELECT sql FROM sqlite_master m + WHERE sql IS NOT NULL + AND name NOT LIKE 'sqlite_%' + AND NOT EXISTS ( + SELECT 1 FROM sqlite_master AS vt + WHERE vt.sql LIKE 'CREATE VIRTUAL TABLE%' + AND m.name LIKE vt.name || '_%' + ) + ORDER BY m.rowid + `) + .all() as Array<{ sql: string }>; + + for (const statement of statements) { + target.exec(statement.sql); + } } finally { - testDb.close(); + source.close(); } } diff --git a/app/db/wipe.ts b/app/db/wipe.ts new file mode 100644 index 000000000..1a45b618a --- /dev/null +++ b/app/db/wipe.ts @@ -0,0 +1,29 @@ +import { sql } from "kysely"; +import { db } from "~/db/sql"; + +/** + * Deletes every row of every table, leaving the schema (and the kysely + * migration bookkeeping tables) in place. + */ +export async function deleteAllRows() { + // virtual tables and their shadow tables (e.g. UserSearch_data) can not be + // deleted from directly; the fts index stays in sync via the User triggers + const { rows: tables } = await sql<{ name: string }>` + SELECT name FROM sqlite_master + WHERE type='table' + AND name NOT LIKE 'sqlite_%' + AND name NOT LIKE 'kysely_migration%' + AND sql NOT LIKE 'CREATE VIRTUAL TABLE%' + AND NOT EXISTS ( + SELECT 1 FROM sqlite_master AS vt + WHERE vt.sql LIKE 'CREATE VIRTUAL TABLE%' + AND sqlite_master.name LIKE vt.name || '_%' + ) + `.execute(db); + + await sql`PRAGMA foreign_keys = OFF`.execute(db); + for (const table of tables) { + await sql`DELETE FROM ${sql.table(table.name)}`.execute(db); + } + await sql`PRAGMA foreign_keys = ON`.execute(db); +} diff --git a/docs/dev/database-schemas.md b/docs/dev/database-schemas.md index 37d84f16e..358c83c2d 100644 --- a/docs/dev/database-schemas.md +++ b/docs/dev/database-schemas.md @@ -66,10 +66,13 @@ Non-obvious columns get a JSDoc comment: what `null` means, what a magic number ## SQLite migration quirks -- SQLite can't add `not null` to an existing column. To tighten one: add `"_new" integer not null default 0`, `update ... set "_new" = coalesce("", 0)`, drop the old column, rename the new one. See `migrations/162-boolean-columns-not-null.js`. +Adding a column, table or index is a `trx.schema` call (see [how-to.md](./how-to.md)). These are the cases where the schema builder runs out and raw `` sql`...` `` is the answer. + +- SQLite can't add `not null` to an existing column. To tighten one: add `"_new" integer not null default 0`, `update ... set "_new" = coalesce("", 0)`, drop the old column, rename the new one. - `drop column` fails if the column is indexed, part of a constraint, or referenced by a trigger, view, generated column or partial index. Check `sqlite_master` first. -- Only when that isn't enough, rebuild the table: `pragma foreign_keys = OFF`, create `X_new`, copy, drop, rename, recreate every index, then `pragma foreign_key_check` inside the transaction. See `migrations/161-tournament-match-nullable-opponents.js`. -- New columns can't be added with a non-constant default, so a `createdAt` added later starts out nullable. Backfill it and rebuild the table in the same migration rather than leaving the nullability behind — see the `TournamentStage` rebuild in `migrations/162-boolean-columns-not-null.js`. +- Only when that isn't enough, rebuild the table: `pragma foreign_keys = OFF`, create `X_new`, copy, drop, rename, recreate every index, then `pragma foreign_key_check` inside the transaction. +- New columns can't be added with a non-constant default, so a `createdAt` added later starts out nullable. Backfill it and rebuild the table in the same migration rather than leaving the nullability behind. +- `pragma foreign_keys` is a no-op inside a transaction, so a rebuild that needs it off has to toggle it outside the `db.transaction()` block. ## After changing the schema diff --git a/docs/dev/how-to.md b/docs/dev/how-to.md index 534cfb346..6b02371cf 100644 --- a/docs/dev/how-to.md +++ b/docs/dev/how-to.md @@ -8,18 +8,58 @@ Run the `pnpm run biome:fix` command. Also you might want to set up Biome as an ## Add a new database migration -1) Add a new file to the migrations folder incrementing the last used number by one e.g. `011-my-cool-feature.js`. Note: there is no script to do this. -2) Take this file as a base and fill it out with your migration: +1) Run `pnpm run migrate:new "my cool feature"`. This creates `migrations/-my-cool-feature.ts` e.g. `migrations/20260803143000-my-cool-feature.ts`. Migrations run in filename order, and the timestamp keeps two branches from claiming the same slot. +2) Fill out the generated file, replacing the `TODO`s. Use the schema builder (`trx.schema`) rather than raw SQL: -```js -export function up(db) { - db.transaction(() => { - // your migrations go here - })(); +```ts +import type { Kysely } from "kysely"; + +/** Gives users somewhere to put their pronouns */ +export async function up(db: Kysely): Promise { + // kysely does not wrap sqlite migrations in a transaction, so do it here + await db.transaction().execute(async (trx) => { + await trx.schema + .alterTable("User") + .addColumn("pronouns", "text") + .execute(); + }); } ``` -Note: No need to implement the "down" migration +New tables need `strict` appended, which the builder has no method for: + +```ts +import { type Kysely, sql } from "kysely"; + +export async function up(db: Kysely): Promise { + await db.transaction().execute(async (trx) => { + await trx.schema + .createTable("UserPronoun") + .addColumn("id", "integer", (col) => col.primaryKey()) + .addColumn("userId", "integer", (col) => + col.notNull().references("User.id").onDelete("cascade"), + ) + .addColumn("createdAt", "integer", (col) => + col.notNull().defaultTo(sql`(strftime('%s', 'now'))`), + ) + // every table in this schema is strict + .modifyEnd(sql`strict`) + .execute(); + + await trx.schema + .createIndex("user_pronoun_user_id") + .on("UserPronoun") + .column("userId") + .execute(); + }); +} +``` + +Notes: +- No need to implement the "down" migration +- Kysely does not wrap migrations in a transaction for SQLite, so wrap it yourself +- Drop to raw `` sql`...` `` only for what the builder can't express: table rebuilds, `pragma foreign_key_check`, FTS5 virtual tables, generated columns. See the [SQLite migration quirks](./database-schemas.md#sqlite-migration-quirks). +- `migrations/20260803000000-initial.ts` is the collapsed history of the 165 migrations that came before it. It only ever runs against an empty database, so leave it alone. 3) Update the typings in `app/db/tables.ts` 4) Run `pnpm run migrate up` to apply your migration (the unit test database `db-test.sqlite3` is created and migrated automatically when unit tests run) diff --git a/knip.ts b/knip.ts index 73573da97..ef1b1aa49 100644 --- a/knip.ts +++ b/knip.ts @@ -6,11 +6,9 @@ const config = { tags: ["-lintignore"], entry: [ "app/features/*/routes/**/*.{ts,tsx}", - "migrations/**/*.js", + "migrations/**/*.ts", "scripts/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}", "public/sw-2.js", - "ley.config.cjs", - "ley-driver.cjs", ], compilers: { css: (text: string, path: string) => { diff --git a/ley-driver.cjs b/ley-driver.cjs deleted file mode 100644 index b2ae2b792..000000000 --- a/ley-driver.cjs +++ /dev/null @@ -1,38 +0,0 @@ -const { load, MigrationError } = require("ley/lib/util"); -const TEXT = require("ley/lib/text"); - -exports.connect = (opts = {}) => { - const { database, ...rest } = opts; - const Database = require("better-sqlite3"); - return new Database(database, rest); -}; - -exports.setup = async (client) => { - client.prepare(TEXT.table.replace("serial", "integer")).run(); - return client.prepare("select name from migrations order by id asc").all(); -}; - -exports.loop = async (client, files, method) => { - const INSERT = client.prepare( - "insert into migrations (name,created_at) values (?,current_timestamp)", - ); - const DELETE = client.prepare("delete from migrations where name = ?"); - - for (const obj of files) { - const file = await load(obj.abs); - if (typeof file[method] === "function") { - await Promise.resolve(file[method](client)).catch((err) => { - throw new MigrationError(err, obj); - }); - } - if (method === "up") { - INSERT.run(obj.name); - } else if (method === "down") { - DELETE.run(obj.name); - } - } -}; - -exports.end = async (client) => { - await client.close(); -}; diff --git a/ley.config.cjs b/ley.config.cjs deleted file mode 100644 index 36752528d..000000000 --- a/ley.config.cjs +++ /dev/null @@ -1,12 +0,0 @@ -const path = require("node:path"); - -try { - process.loadEnvFile(); -} catch { - // .env is optional; in production DB_PATH comes from the host environment -} - -module.exports = { - database: process.env.DB_PATH, - driver: path.join(__dirname, "ley-driver.cjs"), -}; diff --git a/migrations/000-initial.js b/migrations/000-initial.js deleted file mode 100644 index 35420200e..000000000 --- a/migrations/000-initial.js +++ /dev/null @@ -1,154 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "User" ( - "id" integer primary key, - "discordId" text unique not null, - "discordName" text not null, - "discordDiscriminator" text not null, - "discordAvatar" text, - "twitch" text, - "twitter" text, - "youtubeId" text, - "bio" text, - "country" text - ) strict - `, - ).run(); - - db.prepare( - ` - create table "PlusSuggestion" ( - "id" integer primary key, - "text" text not null, - "authorId" integer not null, - "suggestedId" integer not null, - "month" integer not null, - "year" integer not null, - "tier" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("authorId") references "User"("id") on delete cascade, - foreign key ("suggestedId") REFERENCES "User"("id") ON delete cascade, - unique( - "month", - "year", - "suggestedId", - "authorId", - "tier" - ) on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index plus_suggestion_author_id on "PlusSuggestion"("authorId")`, - ).run(); - db.prepare( - `create index plus_suggestion_suggested_id on "PlusSuggestion"("suggestedId")`, - ).run(); - - db.prepare( - ` - create table "PlusVote" ( - "month" integer not null, - "year" integer not null, - "tier" integer not null, - "authorId" integer not null, - "votedId" integer not null, - "score" integer not null, - "validAfter" integer not null, - foreign key ("authorId") references "User"("id") on delete cascade, - foreign key ("votedId") references "User"("id") on delete cascade, - unique("month", "year", "authorId", "votedId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index plus_vote_author_id on "PlusVote"("authorId");`, - ).run(); - db.prepare(`create index plus_vote_voted_id on "PlusVote"("votedId");`).run(); - - db.prepare( - ` - create view "PlusVotingResult" as - select - "votedId", - "tier", - avg("score") as "score", - avg("score") >= 0 as "passedVoting", - "month", - "year", - exists ( - select - 1 - from - "PlusSuggestion" - where - "PlusSuggestion"."month" = "PlusVote"."month" - and "PlusSuggestion"."year" = "PlusVote"."year" - and "PlusSuggestion"."suggestedId" = "PlusVote"."votedId" - AND "PlusSuggestion"."tier" = "PlusVote"."tier" - ) as "wasSuggested" - from - "PlusVote" - group by - "votedId", - "tier", - "month", - "year"; - `, - ).run(); - - db.prepare( - ` - create view "PlusTier" as - select - "votedId" as "userId", - case - when "passedVoting" = 0 - and "wasSuggested" = 1 then null - when "passedVoting" = 1 then "tier" - when "passedVoting" = 0 - and "tier" != 3 then "tier" + 1 - end "tier" - from - "PlusVotingResult" - where - year = ( - select - "year" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - and "month" = ( - select - "month" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - group by - "votedId"; - `, - ).run(); -} - -export function down(db) { - db.prepare(`drop view "PlusVotingResult"`).run(); - db.prepare(`drop view "PlusTier"`).run(); - db.prepare(`drop table "User"`).run(); - db.prepare(`drop table "PlusSuggestion"`).run(); - db.prepare(`drop table "PlusVote"`).run(); -} diff --git a/migrations/001-badges.js b/migrations/001-badges.js deleted file mode 100644 index f5218c94f..000000000 --- a/migrations/001-badges.js +++ /dev/null @@ -1,191 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "Badge" ( - "id" integer primary key, - "code" text not null, - "displayName" text not null - ) strict - `, - ).run(); - - for (const badge of initialBadgesForDb()) { - db.prepare( - `insert into "Badge" ("code", "displayName") values ($code, $displayName)`, - ).run(badge); - } - - db.prepare( - ` - create table "BadgeOwner" ( - "badgeId" integer not null, - "userId" integer not null - ) strict - `, - ).run(); - - db.prepare( - ` - create table "BadgeManager" ( - "badgeId" integer not null, - "userId" integer not null, - unique("badgeId", "userId") on conflict rollback - ) strict - `, - ).run(); -} - -export function down(db) { - db.prepare(`drop table "Badge"`).run(); - db.prepare(`drop table "BadgeOwner"`).run(); - db.prepare(`drop table "BadgeManager"`).run(); -} - -function initialBadgesForDb() { - return [ - { - code: "sundae", - displayName: "4v4 Sundaes", - }, - { - code: "zones", - displayName: "Dapple SZ Speedladder", - }, - { - code: "ebtv", - displayName: "EBTV League", - }, - { - code: "girls", - displayName: "Girls Duo Cup", - }, - { - code: "idtga", - displayName: "It's Dangerous to go Alone", - }, - { - code: "beta_top1", - displayName: "Beta's Events", - }, - { - code: "beta_top2", - displayName: "Launch Day", - }, - { - code: "beta_top3", - displayName: "Launch Day", - }, - { - code: "pair", - displayName: "League Rush (Pair)", - }, - { - code: "quad", - displayName: "League Rush (Quad)", - }, - { - code: "lobster", - displayName: "Lobster Crossfire", - }, - { - code: "monday", - displayName: "Monday Afterparty", - }, - { - code: "pool1", - displayName: "Paddling Pool Weekly", - }, - { - code: "snapshot_gold", - displayName: "Snapshot (Alpha)", - }, - { - code: "snapshot_silver", - displayName: "Snapshot (Beta)", - }, - { - code: "snapshot_bronze", - displayName: "Snapshot (Gamma)", - }, - { - code: "superjump_alpha", - displayName: "Superjump", - }, - { - code: "superjump_beta", - displayName: "Superjump (Beta bracket)", - }, - { - code: "superjump_gamma", - displayName: "Superjump (Gamma bracket)", - }, - { - code: "toni_kensa", - displayName: "Toni Kensa Cup", - }, - { - code: "pool2", - displayName: "Golden Paddling Pool Event", - }, - { - code: "lutipink", - displayName: "LUTI Season 12 (Div X)", - }, - { - code: "lutired", - displayName: "LUTI Season 12 (Div 1)", - }, - { - code: "lutiorange", - displayName: "LUTI Season 12 (Div 2)", - }, - { - code: "lutiyellow", - displayName: "LUTI Season 12 (Div 3)", - }, - { - code: "lutilimegreen", - displayName: "LUTI Season 12 (Div 4)", - }, - { - code: "lutigreen", - displayName: "LUTI Season 12 (Div 5)", - }, - { - code: "lutiblue", - displayName: "LUTI Season 12 (Div 6)", - }, - { - code: "lutipurple", - displayName: "LUTI Season 12 (Div 7)", - }, - { - code: "lutitan", - displayName: "LUTI Season 12 (Div 8)", - }, - { - code: "lutitan", - displayName: "LUTI Season 12 (Div 9)", - }, - { - code: "tidal_tuesdays", - displayName: "Tidal Tuesdays", - }, - { - code: "squid_junction", - displayName: "Squid Junction", - }, - { - code: "triton", - displayName: "Triton-Cup", - }, - { - code: "cake", - displayName: "Yay's SUPER AWESOME Birthday Bash!", - }, - { - code: "20xx", - displayName: "a 20XX Series tournament", - }, - ]; -} diff --git a/migrations/002-fix-plus-tier.js b/migrations/002-fix-plus-tier.js deleted file mode 100644 index 44aa77618..000000000 --- a/migrations/002-fix-plus-tier.js +++ /dev/null @@ -1,103 +0,0 @@ -// add missing min() call to handle multiple results w/ suggests correctly - -export function up(db) { - db.prepare(`drop view "PlusTier"`).run(); - - db.prepare( - ` - create view "PlusTier" as - select - "votedId" as "userId", - min( - case - when "passedVoting" = 0 - and "wasSuggested" = 1 then null - when "passedVoting" = 1 then "tier" - when "passedVoting" = 0 - and "tier" != 3 then "tier" + 1 - end - ) as "tier" - from - "PlusVotingResult" - where - year = ( - select - "year" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - and "month" = ( - select - "month" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - group by - "votedId"; - `, - ).run(); -} - -export function down(db) { - db.prepare(`drop view "PlusTier"`).run(); - - db.prepare( - ` - create view "PlusTier" as - select - "votedId" as "userId", - case - when "passedVoting" = 0 - and "wasSuggested" = 1 then null - when "passedVoting" = 1 then "tier" - when "passedVoting" = 0 - and "tier" != 3 then "tier" + 1 - end "tier" - from - "PlusVotingResult" - where - year = ( - select - "year" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - and "month" = ( - select - "month" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - group by - "votedId"; - `, - ).run(); -} diff --git a/migrations/003-badges-hue.js b/migrations/003-badges-hue.js deleted file mode 100644 index 3579e0724..000000000 --- a/migrations/003-badges-hue.js +++ /dev/null @@ -1,8 +0,0 @@ -export function up(db) { - db.prepare(`alter table "Badge" add "hue" integer`).run(); - db.prepare(`update "Badge" set "hue" = -72 where "code" = 'ebtv'`).run(); -} - -export function down(db) { - db.prepare(`alter table "Badge" drop column "hue"`).run(); -} diff --git a/migrations/004-itz-badges.js b/migrations/004-itz-badges.js deleted file mode 100644 index 3b7a0db2f..000000000 --- a/migrations/004-itz-badges.js +++ /dev/null @@ -1,28 +0,0 @@ -export function up(db) { - for (const badge of itzBadges) { - db.prepare( - `insert into "Badge" ("code", "displayName") values ($code, $displayName)`, - ).run(badge); - } -} - -export function down(db) { - db.prepare( - `delete from "Badge" where "code" in ('itz_red', 'itz_orange', 'itz_blue')`, - ).run(); -} - -const itzBadges = [ - { - code: "itz_red", - displayName: "In The Zone 1-9", - }, - { - code: "itz_orange", - displayName: "In The Zone 10-19", - }, - { - code: "itz_blue", - displayName: "In The Zone 20-29", - }, -]; diff --git a/migrations/005-patrons.js b/migrations/005-patrons.js deleted file mode 100644 index 97e1edd47..000000000 --- a/migrations/005-patrons.js +++ /dev/null @@ -1,48 +0,0 @@ -export function up(db) { - db.prepare(`alter table "User" add column "patronTier" integer`).run(); - db.prepare(`alter table "User" add column "patronSince" integer`).run(); - - db.prepare( - `insert into "Badge" ("code", "displayName") values ('patreon', 'Supporter')`, - ).run(); - db.prepare( - `insert into "Badge" ("code", "displayName") values ('patreon_plus', 'Supporter+')`, - ).run(); - - db.prepare(`alter table "BadgeOwner" rename to "TournamentBadgeOwner"`).run(); - - const patreonBadgeId = db - .prepare(`select "id" from "Badge" where "code" = 'patreon'`) - .get().id; - const patreonPlusBadgeId = db - .prepare(`select "id" from "Badge" where "code" = 'patreon_plus'`) - .get().id; - - db.prepare( - ` - create view "BadgeOwner" as - select "userId", "badgeId" from "TournamentBadgeOwner" - union all - select - "id" as "userId", - case - when "patronTier" = 2 then ${patreonBadgeId} - else ${patreonPlusBadgeId} - end "badgeId" - from "User" - where "patronTier" > 1 - `, - ).run(); -} - -export function down(db) { - db.prepare(`drop view "BadgeOwner"`).run(); - db.prepare(`alter table "User" drop column "patronTier"`).run(); - db.prepare(`alter table "User" drop column "patronSince"`).run(); - - db.prepare( - `delete from "Badge" where "code" in ('patreon_plus', 'patreon')`, - ).run(); - - db.prepare(`alter table "TournamentBadgeOwner" rename to "BadgeOwner"`).run(); -} diff --git a/migrations/006-calendar.js b/migrations/006-calendar.js deleted file mode 100644 index 787944cca..000000000 --- a/migrations/006-calendar.js +++ /dev/null @@ -1,77 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "CalendarEvent" ( - "id" integer primary key, - "name" text not null, - "authorId" integer not null, - "bracketUrl" text not null, - "description" text, - "discordInviteCode" text, - "discordUrl" text generated always as ('https://discord.gg/' || "discordInviteCode") virtual, - "participantCount" integer, - "tags" text, - foreign key ("authorId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare( - ` - create table "CalendarEventDate" ( - "id" integer primary key, - "eventId" integer not null, - "startTime" integer not null, - foreign key ("eventId") references "CalendarEvent"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - ` - create table "CalendarEventResultTeam" ( - "id" integer primary key, - "eventId" integer not null, - "name" text not null, - "placement" integer not null, - foreign key ("eventId") references "CalendarEvent"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - ` - create table "CalendarEventResultPlayer" ( - "teamId" integer not null, - "userId" integer, - "name" text, - foreign key ("teamId") references "CalendarEventResultTeam"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare( - ` - create table "CalendarEventBadge" ( - "eventId" integer not null, - "badgeId" integer not null, - foreign key ("eventId") references "CalendarEvent"("id") on delete cascade, - foreign key ("badgeId") references "Badge"("id") on delete restrict, - unique("eventId", "badgeId") on conflict rollback - ) strict - `, - ).run(); -} - -export function down(db) { - for (const table of [ - "CalendarEventDate", - "CalendarEventResultPlayer", - "CalendarEventResultTeam", - "CalendarEventBadge", - "CalendarEvent", - ]) { - db.prepare(`drop table "${table}"`).run(); - } -} diff --git a/migrations/007-builds.js b/migrations/007-builds.js deleted file mode 100644 index 5239f9477..000000000 --- a/migrations/007-builds.js +++ /dev/null @@ -1,55 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "Build" ( - "id" integer primary key, - "ownerId" integer not null, - "title" text not null, - "description" text, - "modes" text, - "headGearSplId" integer not null, - "clothesGearSplId" integer not null, - "shoesGearSplId" integer not null, - "updatedAt" integer default (strftime('%s', 'now')) not null, - foreign key ("ownerId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare(`create index build_owner_id on "Build"("ownerId")`).run(); - - db.prepare( - ` - create table "BuildWeapon" ( - "buildId" integer not null, - "weaponSplId" integer not null, - foreign key ("buildId") references "Build"("id") on delete cascade, - unique("buildId", "weaponSplId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index build_weapon_build_id on "BuildWeapon"("buildId")`, - ).run(); - - db.prepare( - ` - create table "BuildAbility" ( - "buildId" integer not null, - "gearType" text not null, - "ability" text not null, - "slotIndex" integer not null, - foreign key ("buildId") references "Build"("id") on delete cascade, - unique("buildId", "gearType", "slotIndex") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index build_ability_build_id on "BuildAbility"("buildId")`, - ).run(); -} - -export function down(db) { - for (const table of ["Build", "BuildWeapon", "BuildAbility"]) { - db.prepare(`drop table "${table}"`).run(); - } -} diff --git a/migrations/008-user-new-fields.js b/migrations/008-user-new-fields.js deleted file mode 100644 index 6fd340af2..000000000 --- a/migrations/008-user-new-fields.js +++ /dev/null @@ -1,19 +0,0 @@ -export function up(db) { - db.prepare(`alter table "User" add "customUrl" text`).run(); - db.prepare( - `create unique index user_custom_url_unique on "User"("customUrl")`, - ).run(); - - db.prepare(`alter table "User" add "stickSens" integer`).run(); - db.prepare(`alter table "User" add "motionSens" integer`).run(); - - db.prepare(`alter table "User" add "inGameName" text`).run(); -} - -export function down(db) { - db.prepare("drop index user_custom_url_unique").run(); - db.prepare(`alter table "User" drop column "customUrl"`).run(); - db.prepare(`alter table "User" drop column "stickSens"`).run(); - db.prepare(`alter table "User" drop column "motionSens"`).run(); - db.prepare(`alter table "User" drop column "inGameName"`).run(); -} diff --git a/migrations/009-maps.js b/migrations/009-maps.js deleted file mode 100644 index f358cb93d..000000000 --- a/migrations/009-maps.js +++ /dev/null @@ -1,43 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "MapPool" ( - "id" integer primary key, - "code" text not null, - "ownerId" integer not null, - foreign key ("ownerId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare(`create index map_pool_owner_id on "MapPool"("ownerId")`).run(); - - db.prepare( - ` - create table "MapPoolMap" ( - "mapPoolId" integer not null, - "stageId" integer not null, - "mode" text not null, - foreign key ("mapPoolId") references "MapPool"("id") on delete cascade - ) strict - `, - ).run(); - db.prepare( - `create index map_pool_map_map_pool_id on "MapPoolMap"("mapPoolId")`, - ).run(); - - db.prepare( - `alter table "CalendarEvent" add "mapPoolId" integer references "MapPool"("id") on delete set null`, - ).run(); - db.prepare( - `create index calendar_event_map_pool_id on "CalendarEvent"("mapPoolId")`, - ).run(); -} - -export function down(db) { - for (const table of ["MapPool", "MapPoolMap"]) { - db.prepare(`drop table "${table}"`).run(); - } - - db.prepare("drop index calendar_event_map_pool_id").run(); - db.prepare(`alter table "CalendarEvent" drop column "mapPoolId"`).run(); -} diff --git a/migrations/010-fix-maps.js b/migrations/010-fix-maps.js deleted file mode 100644 index cd6875695..000000000 --- a/migrations/010-fix-maps.js +++ /dev/null @@ -1,64 +0,0 @@ -export function up(db) { - for (const table of ["MapPool", "MapPoolMap"]) { - db.prepare(`drop table "${table}"`).run(); - } - - db.prepare("drop index calendar_event_map_pool_id").run(); - db.prepare(`alter table "CalendarEvent" drop column "mapPoolId"`).run(); - - // --- - - db.prepare( - ` - create table "MapPoolMap" ( - "calendarEventId" integer, - "stageId" integer not null, - "mode" text not null, - foreign key ("calendarEventId") references "CalendarEvent"("id") on delete cascade, - unique("calendarEventId", "stageId", "mode") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index map_pool_map_calendar_event_id on "MapPoolMap"("calendarEventId")`, - ).run(); -} - -export function down(db) { - db.prepare(`drop table "MapPoolMap"`).run(); - - // --- - - db.prepare( - ` - create table "MapPool" ( - "id" integer primary key, - "code" text not null, - "ownerId" integer not null, - foreign key ("ownerId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare(`create index map_pool_owner_id on "MapPool"("ownerId")`).run(); - - db.prepare( - ` - create table "MapPoolMap" ( - "mapPoolId" integer not null, - "stageId" integer not null, - "mode" text not null, - foreign key ("mapPoolId") references "MapPool"("id") on delete cascade - ) strict - `, - ).run(); - db.prepare( - `create index map_pool_map_map_pool_id on "MapPoolMap"("mapPoolId")`, - ).run(); - - db.prepare( - `alter table "CalendarEvent" add "mapPoolId" integer references "MapPool"("id") on delete set null`, - ).run(); - db.prepare( - `create index calendar_event_map_pool_id on "CalendarEvent"("mapPoolId")`, - ).run(); -} diff --git a/migrations/011-user-result-highlights.js b/migrations/011-user-result-highlights.js deleted file mode 100644 index badebb5c6..000000000 --- a/migrations/011-user-result-highlights.js +++ /dev/null @@ -1,25 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "UserResultHighlight" ( - "teamId" integer not null, - "userId" integer not null, - foreign key ("teamId") references "CalendarEventResultTeam"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("teamId", "userId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index user_result_highlight_user_id on "UserResultHighlight"("userId")`, - ).run(); - - db.prepare( - `create index user_result_highlight_team_id on "UserResultHighlight"("teamId")`, - ).run(); -} - -export function down(db) { - db.prepare(`drop table "UserResultHighlight"`).run(); -} diff --git a/migrations/012-to-tools.js b/migrations/012-to-tools.js deleted file mode 100644 index c8fa0d2f0..000000000 --- a/migrations/012-to-tools.js +++ /dev/null @@ -1,76 +0,0 @@ -export function up(db) { - db.prepare(`alter table "CalendarEvent" add "customUrl" text`).run(); - db.prepare( - `alter table "CalendarEvent" add "toToolsEnabled" integer default 0`, - ).run(); - db.prepare( - `alter table "CalendarEvent" add "isBeforeStart" integer default 1`, - ).run(); - db.prepare( - `create unique index calendar_event_custom_url_unique on "CalendarEvent"("customUrl")`, - ).run(); - - db.prepare(`alter table "MapPoolMap" add "tournamentTeamId" integer`).run(); - db.prepare( - `alter table "MapPoolMap" add "tieBreakerCalendarEventId" integer`, - ).run(); - db.prepare( - `create index map_pool_map_tournament_team_id on "MapPoolMap"("tournamentTeamId")`, - ).run(); - db.prepare( - `create index map_pool_map_tie_breaker_calendar_event_id on "MapPoolMap"("tieBreakerCalendarEventId")`, - ).run(); - - db.prepare( - ` - create table "TournamentTeam" ( - "id" integer primary key, - "name" text not null, - "createdAt" integer not null, - "seed" integer, - "calendarEventId" integer not null, - foreign key ("calendarEventId") references "CalendarEvent"("id") on delete cascade, - unique("calendarEventId", "name") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_team_calendar_event_id on "TournamentTeam"("calendarEventId")`, - ).run(); - - db.prepare( - ` - create table "TournamentTeamMember" ( - "tournamentTeamId" integer not null, - "userId" integer not null, - "isOwner" integer not null, - "createdAt" integer not null, - foreign key ("tournamentTeamId") references "TournamentTeam"("id") on delete cascade, - unique("tournamentTeamId", "userId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_team_member_tournament_team_id on "TournamentTeamMember"("tournamentTeamId")`, - ).run(); -} - -export function down(db) { - db.prepare("drop index calendar_event_custom_url_unique").run(); - db.prepare("drop index map_pool_map_tournament_team_id").run(); - db.prepare("drop index map_pool_map_tie_breaker_calendar_event_id").run(); - - db.prepare(`alter table "CalendarEvent" drop column "customUrl"`).run(); - db.prepare(`alter table "CalendarEvent" drop column "toToolsEnabled"`).run(); - db.prepare(`alter table "CalendarEvent" drop column "isBeforeStart"`).run(); - db.prepare(`alter table "MapPoolMap" drop column "tournamentTeamId"`).run(); - db.prepare( - `alter table "MapPoolMap" drop column "tieBreakerCalendarEventId"`, - ).run(); - - db.prepare("drop index tournament_team_calendar_event_id").run(); - db.prepare("drop index tournament_team_member_tournament_team_id").run(); - - db.prepare(`drop table "TournamentTeam"`).run(); - db.prepare(`drop table "TournamentTeamMember"`).run(); -} diff --git a/migrations/013-weapon-pool.js b/migrations/013-weapon-pool.js deleted file mode 100644 index 437dd1fcf..000000000 --- a/migrations/013-weapon-pool.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.prepare( - ` - create table "UserWeapon" ( - "userId" integer not null, - "weaponSplId" integer not null, - "order" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - unique("userId", "weaponSplId") on conflict rollback, - unique("userId", "order") on conflict rollback, - foreign key ("userId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare( - `create index user_weapon_user_id on "UserWeapon"("userId")`, - ).run(); -} - -export function down(db) { - db.prepare(`drop table "UserWeapon"`).run(); -} diff --git a/migrations/014-full-tournament.js b/migrations/014-full-tournament.js deleted file mode 100644 index 5c2e69a3b..000000000 --- a/migrations/014-full-tournament.js +++ /dev/null @@ -1,131 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ `alter table "CalendarEvent" drop column "isBeforeStart"`, - ).run(); - - db.prepare(/*sql*/ `drop table "TournamentTeam"`).run(); - db.prepare( - /*sql*/ ` - create table "TournamentTeam" ( - "id" integer primary key, - "name" text, - "friendCode" text, - "createdAt" integer default (strftime('%s', 'now')) not null, - "seed" integer, - "checkedInAt" integer, - "inviteCode" text not null unique, - "calendarEventId" integer not null, - foreign key ("calendarEventId") references "CalendarEvent"("id") on delete cascade, - unique("calendarEventId", "name") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_team_calendar_event_id on "TournamentTeam"("calendarEventId")`, - ).run(); - - db.prepare(/*sql*/ `drop table "TournamentTeamMember"`).run(); - db.prepare( - /*sql*/ ` - create table "TournamentTeamMember" ( - "tournamentTeamId" integer not null, - "userId" integer not null, - "isOwner" integer not null default 0, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("tournamentTeamId") references "TournamentTeam"("id") on delete cascade, - unique("tournamentTeamId", "userId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_team_member_tournament_team_id on "TournamentTeamMember"("tournamentTeamId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentBracket" ( - "id" integer primary key, - "calendarEventId" integer not null, - "type" text not null, - foreign key ("calendarEventId") references "CalendarEvent"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_bracket_calendar_event_id on "TournamentBracket"("calendarEventId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentRound" ( - "id" integer primary key, - "position" integer not null, - "bracketId" integer not null, - "bestOf" integer not null, - foreign key ("bracketId") references "TournamentBracket"("id") on delete cascade, - unique("bracketId", "position") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentMatch" ( - "id" integer primary key, - "roundId" integer not null, - "number" integer, - "position" integer not null, - "winnerDestinationMatchId" integer, - "loserDestinationMatchId" integer, - foreign key ("roundId") references "TournamentRound"("id") on delete cascade, - foreign key ("winnerDestinationMatchId") references "TournamentMatch"("id") on delete restrict, - foreign key ("loserDestinationMatchId") references "TournamentMatch"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_round_id on "TournamentMatch"("roundId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentMatchParticipant" ( - "order" text not null, - "teamId" integer not null, - "matchId" integer not null, - foreign key ("teamId") references "TournamentTeam"("id") on delete restrict, - foreign key ("matchId") references "TournamentMatch"("id") on delete restrict, - unique("teamId", "matchId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_participant_team_id on "TournamentMatchParticipant"("teamId")`, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_participant_match_id on "TournamentMatchParticipant"("matchId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentMatchGameResult" ( - "id" integer primary key, - "matchId" integer unique not null, - "stageId" integer not null, - "mode" text not null, - "winnerTeamId" integer not null, - "reporterId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("matchId") references "TournamentMatch"("id") on delete cascade, - foreign key ("winnerTeamId") references "TournamentTeam"("id") on delete restrict, - foreign key ("reporterId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_game_result_match_id on "TournamentMatchGameResult"("matchId")`, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_game_result_winner_team_id on "TournamentMatchGameResult"("winnerTeamId")`, - ).run(); -} diff --git a/migrations/015-teams.js b/migrations/015-teams.js deleted file mode 100644 index e3564116e..000000000 --- a/migrations/015-teams.js +++ /dev/null @@ -1,77 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ ` - create table "UnvalidatedUserSubmittedImage" ( - "id" integer primary key, - "validatedAt" integer, - "url" text not null unique - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create view "UserSubmittedImage" - as - select * from "UnvalidatedUserSubmittedImage" where "validatedAt" is not null - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "AllTeam" ( - "id" integer primary key, - "name" text not null, - "customUrl" text not null, - "inviteCode" text not null, - "bio" text, - "twitter" text, - "avatarImgId" integer, - "bannerImgId" integer, - "createdAt" integer default (strftime('%s', 'now')) not null, - "deletedAt" integer, - foreign key ("avatarImgId") references "UnvalidatedUserSubmittedImage"("id") on delete set null, - foreign key ("bannerImgId") references "UnvalidatedUserSubmittedImage"("id") on delete set null - ) strict - `, - ).run(); - db.prepare(`create index team_custom_url on "AllTeam"("customUrl")`).run(); - - db.prepare( - /*sql*/ ` - create view "Team" - as - select * from "AllTeam" where "deletedAt" is null - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "AllTeamMember" ( - "teamId" integer not null, - "userId" integer not null, - "role" text, - "isOwner" integer not null default 0, - "createdAt" integer default (strftime('%s', 'now')) not null, - "leftAt" integer, - foreign key ("teamId") references "AllTeam"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("teamId", "userId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create view "TeamMember" - as - select "AllTeamMember".* - from "AllTeamMember" - left join "Team" on "Team"."id" = "AllTeamMember"."teamId" - where "AllTeamMember"."leftAt" is null - and - -- if team id is null the team is deleted - "Team"."id" is not null - `, - ).run(); -} diff --git a/migrations/016-adjust-submitted-img.js b/migrations/016-adjust-submitted-img.js deleted file mode 100644 index 8770a2479..000000000 --- a/migrations/016-adjust-submitted-img.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ ` - drop table "UnvalidatedUserSubmittedImage" - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "UnvalidatedUserSubmittedImage" ( - "id" integer primary key, - "validatedAt" integer, - "url" text not null unique, - "submitterUserId" integer not null, - foreign key ("submitterUserId") references "User"("id") on delete set null - ) strict - `, - ).run(); - - db.prepare( - `create index submitter_user_id on "UnvalidatedUserSubmittedImage"("submitterUserId")`, - ).run(); -} diff --git a/migrations/017-persisted-plus-tier.js b/migrations/017-persisted-plus-tier.js deleted file mode 100644 index 76272ee90..000000000 --- a/migrations/017-persisted-plus-tier.js +++ /dev/null @@ -1,67 +0,0 @@ -export function up(db) { - db.prepare(`drop view "PlusTier"`).run(); - - db.prepare( - /* sql */ ` - create view "FreshPlusTier" as - select - "votedId" as "userId", - min( - case - when "passedVoting" = 0 - and "wasSuggested" = 1 then null - when "passedVoting" = 1 then "tier" - when "passedVoting" = 0 - and "tier" != 3 then "tier" + 1 - end - ) as "tier" - from - "PlusVotingResult" - where - year = ( - select - "year" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - and "month" = ( - select - "month" - from - "PlusVote" - where - "validAfter" < strftime('%s', 'now') - order by - "year" desc, - "month" desc - limit - 1 - ) - group by - "votedId"; - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "PlusTier" ( - "userId" integer primary key, - "tier" integer not null, - foreign key ("userId") references "User"("id") on delete set null - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "PlusTier" ("userId", "tier") select "userId", "tier" from "FreshPlusTier" where "tier" is not null; - `, - ).run(); -} diff --git a/migrations/018-add-user-team-css.js b/migrations/018-add-user-team-css.js deleted file mode 100644 index 941cca107..000000000 --- a/migrations/018-add-user-team-css.js +++ /dev/null @@ -1,4 +0,0 @@ -export function up(db) { - db.prepare(/* sql */ `alter table "User" add "css" text`).run(); - db.prepare(/* sql */ `alter table "AllTeam" add "css" text`).run(); -} diff --git a/migrations/019-add-patron-till.js b/migrations/019-add-patron-till.js deleted file mode 100644 index d889898a3..000000000 --- a/migrations/019-add-patron-till.js +++ /dev/null @@ -1,3 +0,0 @@ -export function up(db) { - db.prepare(/* sql */ `alter table "User" add "patronTill" integer`).run(); -} diff --git a/migrations/020-vods.js b/migrations/020-vods.js deleted file mode 100644 index 6579cbcb3..000000000 --- a/migrations/020-vods.js +++ /dev/null @@ -1,70 +0,0 @@ -export function up(db) { - db.prepare( - `alter table "User" add column "isVideoAdder" integer default 0`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "UnvalidatedVideo" ( - "id" integer primary key, - "title" text not null, - "type" text not null, - "youtubeId" text not null, - "youtubeDate" integer not null, - "submitterUserId" integer not null, - "validatedAt" integer, - "eventId" integer, - foreign key ("submitterUserId") references "User"("id") on delete restrict, - foreign key ("eventId") references "CalendarEvent"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare( - `create index video_event_id on "UnvalidatedVideo"("eventId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create view "Video" - as - select * from "UnvalidatedVideo" where "validatedAt" is not null - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "VideoMatch" ( - "id" integer primary key, - "videoId" integer not null, - "startsAt" integer not null, - "stageId" integer not null, - "mode" text not null, - foreign key ("videoId") references "UnvalidatedVideo"("id") on delete cascade - ) strict - `, - ).run(); - db.prepare( - `create index video_match_video_id on "VideoMatch"("videoId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "VideoMatchPlayer" ( - "videoMatchId" integer not null, - "playerUserId" integer, - "playerName" text, - "weaponSplId" integer not null, - "player" integer not null, - foreign key ("videoMatchId") references "VideoMatch"("id") on delete cascade, - foreign key ("playerUserId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - db.prepare( - `create index video_match_player_video_match_id on "VideoMatchPlayer"("videoMatchId")`, - ).run(); - db.prepare( - `create index video_match_player_player_user_id on "VideoMatchPlayer"("playerUserId")`, - ).run(); -} diff --git a/migrations/021-abilities.js b/migrations/021-abilities.js deleted file mode 100644 index c01817a98..000000000 --- a/migrations/021-abilities.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "BuildAbility" add "abilityPoints" integer generated always as (case when "slotIndex" = 0 then 10 else 3 end) virtual`, - ).run(); -} diff --git a/migrations/022-xrank.js b/migrations/022-xrank.js deleted file mode 100644 index c1f662d1b..000000000 --- a/migrations/022-xrank.js +++ /dev/null @@ -1,43 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ ` - create table "XRankPlacement" ( - "id" integer primary key, - "weaponSplId" integer not null, - "name" text not null, - "nameDiscriminator" text not null, - "power" real not null, - "rank" integer not null, - "title" text not null, - "badges" text not null, - "bannerSplId" integer not null, - "playerId" integer not null, - "month" integer not null, - "year" integer not null, - "mode" text not null, - "region" text not null, - foreign key ("playerId") references "SplatoonPlayer"("id") on delete cascade, - unique("rank", "month", "year", "region", "mode") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index splatoon_placement_player_id on "XRankPlacement"("playerId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "SplatoonPlayer" ( - "id" integer primary key, - "userId" integer unique, - "splId" text unique not null, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - `create index splatoon_player_user_id on "SplatoonPlayer"("userId")`, - ).run(); -} diff --git a/migrations/023-add-user-fav-badge.js b/migrations/023-add-user-fav-badge.js deleted file mode 100644 index cbe7184e0..000000000 --- a/migrations/023-add-user-fav-badge.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "User" add "favoriteBadgeId" integer`, - ).run(); -} diff --git a/migrations/024-adjust-tournament.js b/migrations/024-adjust-tournament.js deleted file mode 100644 index df8c254dd..000000000 --- a/migrations/024-adjust-tournament.js +++ /dev/null @@ -1,12 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "CalendarEvent" add "isBeforeStart" integer default 1`, - ).run(); - db.prepare( - /* sql */ `alter table "CalendarEvent" add "toToolsMode" text`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentTeam" drop column "friendCode"`, - ).run(); -} diff --git a/migrations/025-private-builds.js b/migrations/025-private-builds.js deleted file mode 100644 index 2c1083acb..000000000 --- a/migrations/025-private-builds.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "Build" add "private" integer default 0`, - ).run(); -} diff --git a/migrations/026-full-tournament-v2.js b/migrations/026-full-tournament-v2.js deleted file mode 100644 index af3c1b037..000000000 --- a/migrations/026-full-tournament-v2.js +++ /dev/null @@ -1,234 +0,0 @@ -export function up(db) { - db.prepare(/* sql */ `drop index "calendar_event_custom_url_unique"`).run(); - db.prepare(/*sql*/ `drop table "TournamentBracket"`).run(); - db.prepare(/*sql*/ `drop table "TournamentMatchParticipant"`).run(); - db.prepare(/*sql*/ `drop table "TournamentRound"`).run(); - db.prepare(/*sql*/ `drop table "TournamentMatch"`).run(); - db.prepare(/*sql*/ `drop table "TournamentTeam"`).run(); - db.prepare(/*sql*/ `drop table "TournamentTeamMember"`).run(); - db.prepare(/*sql*/ `drop table "TournamentMatchGameResult"`).run(); - - db.prepare( - /* sql */ `alter table "CalendarEvent" drop column "customUrl"`, - ).run(); - db.prepare( - /* sql */ `alter table "CalendarEvent" drop column "toToolsEnabled"`, - ).run(); - db.prepare( - /* sql */ `alter table "CalendarEvent" drop column "toToolsMode"`, - ).run(); - db.prepare( - /* sql */ `alter table "CalendarEvent" drop column "isBeforeStart"`, - ).run(); - - db.prepare( - /* sql */ `alter table "CalendarEvent" add "tournamentId" integer`, - ).run(); - db.prepare( - /*sql*/ `create index calendar_event_tournament_id on "CalendarEvent"("tournamentId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "Tournament" ( - "id" integer primary key, - "mapPickingStyle" text not null, - "format" text not null, - "showMapListGenerator" integer default 0 - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentTeam" ( - "id" integer primary key, - "name" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - "seed" integer, - "inviteCode" text not null unique, - "tournamentId" integer not null, - "prefersNotToHost" integer not null default 0, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - unique("tournamentId", "name") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_team_tournament_id on "TournamentTeam"("tournamentId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentTeamCheckIn" ( - "tournamentTeamId" integer not null, - "checkedInAt" integer not null, - foreign key ("tournamentTeamId") references "TournamentTeam"("id") on delete cascade - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_team_check_in_tournament_team_id on "TournamentTeamCheckIn"("tournamentTeamId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentTeamMember" ( - "tournamentTeamId" integer not null, - "userId" integer not null, - "isOwner" integer not null default 0, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("tournamentTeamId") references "TournamentTeam"("id") on delete cascade, - unique("tournamentTeamId", "userId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_team_member_tournament_team_id on "TournamentTeamMember"("tournamentTeamId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentStage" ( - "id" integer primary key, - "tournamentId" integer not null, - "name" text not null, - "type" text not null, - "settings" text not null, - "number" integer not null, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - unique("number", "tournamentId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_stage_tournament_id on "TournamentStage"("tournamentId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentGroup" ( - "id" integer primary key, - "stageId" integer not null, - "number" integer not null, - foreign key ("stageId") references "TournamentStage"("id") on delete cascade, - unique("number", "stageId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_group_stage_id on "TournamentGroup"("stageId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentRound" ( - "id" integer primary key, - "stageId" integer not null, - "groupId" integer not null, - "number" integer not null, - foreign key ("stageId") references "TournamentStage"("id") on delete cascade, - foreign key ("groupId") references "TournamentGroup"("id") on delete cascade, - unique("number", "groupId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_round_stage_id on "TournamentRound"("stageId")`, - ).run(); - db.prepare( - `create index tournament_round_group_id on "TournamentRound"("groupId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentMatch" ( - "id" integer primary key, - "childCount" integer not null, - "bestOf" integer not null default 3, - "roundId" integer not null, - "stageId" integer not null, - "groupId" integer not null, - "number" integer not null, - "opponentOne" text not null, - "opponentTwo" text not null, - "status" integer not null, - foreign key ("roundId") references "TournamentRound"("id") on delete cascade, - foreign key ("stageId") references "TournamentStage"("id") on delete cascade, - foreign key ("groupId") references "TournamentGroup"("id") on delete cascade, - unique("number", "roundId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_match_round_id on "TournamentMatch"("roundId")`, - ).run(); - db.prepare( - `create index tournament_match_stage_id on "TournamentMatch"("stageId")`, - ).run(); - db.prepare( - `create index tournament_match_group_id on "TournamentMatch"("groupId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentMatchGameResult" ( - "id" integer primary key, - "matchId" integer not null, - "number" integer not null, - "stageId" integer not null, - "mode" text not null, - "source" text not null, - "winnerTeamId" integer not null, - "reporterId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("matchId") references "TournamentMatch"("id") on delete cascade, - foreign key ("winnerTeamId") references "TournamentTeam"("id") on delete restrict, - foreign key ("reporterId") references "User"("id") on delete restrict, - unique("matchId", "number") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_game_result_match_id on "TournamentMatchGameResult"("matchId")`, - ).run(); - db.prepare( - /*sql*/ `create index tournament_match_game_result_winner_team_id on "TournamentMatchGameResult"("winnerTeamId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentMatchGameResultParticipant" ( - "matchGameResultId" integer not null, - "userId" integer not null, - foreign key ("matchGameResultId") references "TournamentMatchGameResult"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("matchGameResultId", "userId") on conflict rollback - ) strict - `, - ).run(); - db.prepare( - `create index tournament_match_game_result_participant_match_game_result_id on "TournamentMatchGameResultParticipant"("matchGameResultId")`, - ).run(); - db.prepare( - `create index tournament_match_game_result_participant_user_id on "TournamentMatchGameResultParticipant"("userId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TrustRelationship" ( - "trustGiverUserId" integer not null, - "trustReceiverUserId" integer not null, - foreign key ("trustGiverUserId") references "User"("id") on delete cascade, - foreign key ("trustReceiverUserId") references "User"("id") on delete cascade, - unique("trustGiverUserId", "trustReceiverUserId") on conflict ignore - ) strict - `, - ).run(); - db.prepare( - `create index trust_relationship_trust_giver_user_id on "TrustRelationship"("trustGiverUserId")`, - ).run(); - db.prepare( - `create index trust_relationship_trust_receiver_user_id on "TrustRelationship"("trustReceiverUserId")`, - ).run(); -} diff --git a/migrations/027-tournament-subs.js b/migrations/027-tournament-subs.js deleted file mode 100644 index fb1923518..000000000 --- a/migrations/027-tournament-subs.js +++ /dev/null @@ -1,19 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ ` - create table "TournamentSub" ( - "userId" integer not null, - "tournamentId" integer not null, - "canVc" integer not null, - "bestWeapons" text not null, - "okWeapons" text, - "message" text, - "visibility" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - unique("userId", "tournamentId") on conflict rollback - ) strict - `, - ).run(); -} diff --git a/migrations/028-user-changes.js b/migrations/028-user-changes.js deleted file mode 100644 index 735e121d3..000000000 --- a/migrations/028-user-changes.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.prepare(/* sql */ `alter table "User" add "discordUniqueName" text`).run(); - db.prepare( - /* sql */ `alter table "User" add "showDiscordUniqueName" integer not null default 1`, - ).run(); - db.prepare( - /* sql */ `alter table "UserWeapon" add "isFavorite" integer not null default 0`, - ).run(); -} diff --git a/migrations/029-end-tournament.js b/migrations/029-end-tournament.js deleted file mode 100644 index d12e29e09..000000000 --- a/migrations/029-end-tournament.js +++ /dev/null @@ -1,114 +0,0 @@ -export function up(db) { - db.prepare( - `create index tournament_sub_user_id on "TournamentSub"("userId")`, - ).run(); - db.prepare( - `create index tournament_sub_tournament_id on "TournamentSub"("tournamentId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "Skill" ( - "id" integer primary key, - "mu" real not null, - "sigma" real not null, - "ordinal" real not null, - "userId" integer, - "identifier" text, - "matchesCount" integer not null, - "tournamentId" integer, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("tournamentId") references "Tournament"("id") on delete restrict, - unique("userId", "tournamentId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare(`create index skill_user_id on "Skill"("userId")`).run(); - db.prepare( - `create index skill_tournament_id on "Skill"("tournamentId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "SkillTeamUser" ( - "userId" integer not null, - "skillId" integer not null, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("skillId") references "Skill"("id") on delete cascade, - unique("userId", "skillId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index skill_team_user_user_id on "SkillTeamUser"("userId")`, - ).run(); - db.prepare( - `create index skill_team_user_skill_id on "SkillTeamUser"("skillId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "MapResult" ( - "mode" text not null, - "stageId" integer not null, - "userId" integer not null, - "wins" integer not null, - "losses" integer not null, - foreign key ("userId") references "User"("id") on delete cascade, - unique("userId", "stageId", "mode") on conflict rollback - ) strict - `, - ).run(); - - db.prepare(`create index map_result_user_id on "MapResult"("userId")`).run(); - - db.prepare( - /*sql*/ ` - create table "PlayerResult" ( - "ownerUserId" integer not null, - "otherUserId" integer not null, - "mapWins" integer not null, - "mapLosses" integer not null, - "setWins" integer not null, - "setLosses" integer not null, - "type" text not null, - foreign key ("ownerUserId") references "User"("id") on delete cascade, - foreign key ("otherUserId") references "User"("id") on delete cascade, - unique("ownerUserId", "otherUserId", "type") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index player_result_owner_user_id on "PlayerResult"("ownerUserId")`, - ).run(); - db.prepare( - `create index player_result_other_user_id on "PlayerResult"("otherUserId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentResult" ( - "tournamentId" integer not null, - "userId" integer not null, - "placement" integer not null, - "isHighlight" integer not null default 0, - "participantCount" integer not null, - "tournamentTeamId" integer not null, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - foreign key ("tournamentTeamId") references "TournamentTeam"("id") on delete cascade, - unique("userId", "tournamentId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index tournament_result_user_id on "TournamentResult"("userId")`, - ).run(); - db.prepare( - `create index tournament_result_tournament_id on "TournamentResult"("tournamentId")`, - ).run(); -} diff --git a/migrations/030-art.js b/migrations/030-art.js deleted file mode 100644 index ad756b755..000000000 --- a/migrations/030-art.js +++ /dev/null @@ -1,45 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "User" add "commissionsOpen" integer default 0`, - ).run(); - db.prepare( - /* sql */ `alter table "User" add "isArtist" integer default 0`, - ).run(); - db.prepare(/* sql */ `alter table "User" add "commissionText" text`).run(); - - db.prepare( - /*sql*/ ` - create table "Art" ( - "id" integer primary key, - "imgId" integer not null, - "authorId" integer not null, - "isShowcase" integer not null default 0, - "description" text, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("authorId") references "User"("id") on delete restrict, - foreign key ("imgId") references "UnvalidatedUserSubmittedImage"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare(`create index art_author_id on "Art"("authorId")`).run(); - db.prepare(`create index art_img_id on "Art"("imgId")`).run(); - - db.prepare( - /*sql*/ ` - create table "ArtUserMetadata" ( - "artId" integer not null, - "userId" integer not null, - foreign key ("artId") references "Art"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - `create index art_user_metadata_art_id on "ArtUserMetadata"("artId")`, - ).run(); - db.prepare( - `create index art_user_metadata_user_id on "ArtUserMetadata"("userId")`, - ).run(); -} diff --git a/migrations/031-art-tags.js b/migrations/031-art-tags.js deleted file mode 100644 index 0cc3ab44a..000000000 --- a/migrations/031-art-tags.js +++ /dev/null @@ -1,27 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ ` - create table "ArtTag" ( - "id" integer primary key, - "name" text unique not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - "authorId" integer not null, - foreign key ("authorId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TaggedArt" ( - "artId" integer not null, - "tagId" integer not null, - foreign key ("artId") references "Art"("id") on delete cascade, - foreign key ("tagId") references "ArtTag"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare(`create index tagged_art_art_id on "TaggedArt"("artId")`).run(); - db.prepare(`create index tagged_art_tag_id on "TaggedArt"("tagId")`).run(); -} diff --git a/migrations/032-q.js b/migrations/032-q.js deleted file mode 100644 index d8f497590..000000000 --- a/migrations/032-q.js +++ /dev/null @@ -1,200 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(`delete from "Skill"`).run(); - db.prepare(`create index skill_identifier on "Skill"("identifier")`).run(); - - db.prepare( - /* sql */ `alter table "MapPoolMap" add "groupId" integer`, - ).run(); - db.prepare( - `create index map_pool_map_group_id on "MapPoolMap"("groupId")`, - ).run(); - - db.prepare( - /* sql */ `alter table "Skill" add "groupMatchId" integer`, - ).run(); - db.prepare( - `create index skill_group_match_id on "Skill"("groupMatchId")`, - ).run(); - db.prepare( - /* sql */ `alter table "Skill" add "season" integer not null`, - ).run(); - - db.prepare(/*sql*/ `drop table "MapResult"`).run(); - db.prepare(/*sql*/ `drop table "PlayerResult"`).run(); - - db.prepare( - /*sql*/ ` - create table "MapResult" ( - "mode" text not null, - "stageId" integer not null, - "userId" integer not null, - "wins" integer not null, - "losses" integer not null, - "season" integer not null, - foreign key ("userId") references "User"("id") on delete cascade, - unique("userId", "stageId", "mode", "season") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index map_result_user_id on "MapResult"("userId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "PlayerResult" ( - "ownerUserId" integer not null, - "otherUserId" integer not null, - "mapWins" integer not null, - "mapLosses" integer not null, - "setWins" integer not null, - "setLosses" integer not null, - "type" text not null, - "season" integer not null, - foreign key ("ownerUserId") references "User"("id") on delete cascade, - foreign key ("otherUserId") references "User"("id") on delete cascade, - unique("ownerUserId", "otherUserId", "type", "season") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index player_result_owner_user_id on "PlayerResult"("ownerUserId")`, - ).run(); - db.prepare( - `create index player_result_other_user_id on "PlayerResult"("otherUserId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "Group" ( - "id" integer primary key, - "teamId" integer, - "createdAt" integer default (strftime('%s', 'now')) not null, - "latestActionAt" integer default (strftime('%s', 'now')) not null, - "mapListPreference" text not null, - "inviteCode" text not null, - "status" text not null, - foreign key ("teamId") references "AllTeam"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare(`create index group_team_id on "Group"("teamId")`).run(); - - db.prepare( - /*sql*/ ` - create table "GroupMember" ( - "groupId" integer not null, - "userId" integer not null, - "role" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete restrict, - foreign key ("groupId") references "Group"("id") on delete cascade, - unique("userId", "groupId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index group_member_group_id on "GroupMember"("groupId")`, - ).run(); - db.prepare( - `create index group_member_user_id on "GroupMember"("userId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "GroupLike" ( - "likerGroupId" integer not null, - "targetGroupId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("likerGroupId") references "Group"("id") on delete cascade, - foreign key ("targetGroupId") references "Group"("id") on delete cascade, - unique("likerGroupId", "targetGroupId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index group_like_liker_group_id on "GroupLike"("likerGroupId")`, - ).run(); - db.prepare( - `create index group_like_target_group_id on "GroupLike"("targetGroupId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "GroupMatch" ( - "id" integer primary key, - "alphaGroupId" integer not null, - "bravoGroupId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - "reportedAt" integer, - "reportedByUserId" integer, - foreign key ("alphaGroupId") references "Group"("id") on delete restrict, - foreign key ("bravoGroupId") references "Group"("id") on delete restrict, - foreign key ("reportedByUserId") references "User"("id") on delete restrict, - unique("alphaGroupId") on conflict rollback, - unique("bravoGroupId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index group_match_alpha_group_id on "GroupMatch"("alphaGroupId")`, - ).run(); - db.prepare( - `create index group_match_bravo_group_id on "GroupMatch"("bravoGroupId")`, - ).run(); - db.prepare( - `create index group_match_reported_by_user_id on "GroupMatch"("reportedByUserId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "GroupMatchMap" ( - "id" integer primary key, - "matchId" integer not null, - "index" integer not null, - "mode" text not null, - "stageId" integer not null, - "source" text not null, - "winnerGroupId" integer, - foreign key ("matchId") references "GroupMatch"("id") on delete cascade, - foreign key ("winnerGroupId") references "Group"("id") on delete restrict, - unique("matchId", "index") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index group_match_map_match_id on "GroupMatchMap"("matchId")`, - ).run(); - db.prepare( - `create index group_match_map_winner_group_id on "GroupMatchMap"("winnerGroupId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "ReportedWeapon" ( - "groupMatchMapId" integer, - "weaponSplId" integer not null, - "userId" integer not null, - foreign key ("groupMatchMapId") references "GroupMatchMap"("id") on delete restrict, - foreign key ("userId") references "User"("id") on delete restrict, - unique("groupMatchMapId", "userId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - `create index reported_weapon_group_match_map_id on "ReportedWeapon"("groupMatchMapId")`, - ).run(); - db.prepare( - `create index reported_weapon_user_id on "ReportedWeapon"("userId")`, - ).run(); - })(); -} diff --git a/migrations/033-banned.js b/migrations/033-banned.js deleted file mode 100644 index 4619911ee..000000000 --- a/migrations/033-banned.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "User" add "banned" integer default 0`, - ).run(); -} diff --git a/migrations/034-vc.js b/migrations/034-vc.js deleted file mode 100644 index 71d63261f..000000000 --- a/migrations/034-vc.js +++ /dev/null @@ -1,6 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "vc" text default "NO"`).run(); - db.prepare(/* sql */ `alter table "User" add "languages" text`).run(); - })(); -} diff --git a/migrations/035-log-in-link.js b/migrations/035-log-in-link.js deleted file mode 100644 index e73dade85..000000000 --- a/migrations/035-log-in-link.js +++ /dev/null @@ -1,12 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ ` - create table "LogInLink" ( - "code" text unique not null, - "expiresAt" integer not null, - "userId" integer not null, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); -} diff --git a/migrations/036-add-chat-code.js b/migrations/036-add-chat-code.js deleted file mode 100644 index e7274ed9c..000000000 --- a/migrations/036-add-chat-code.js +++ /dev/null @@ -1,6 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "Group" add "chatCode" text`).run(); - db.prepare(/* sql */ `alter table "GroupMatch" add "chatCode" text`).run(); - })(); -} diff --git a/migrations/037-add-memento.js b/migrations/037-add-memento.js deleted file mode 100644 index 41f8b6c89..000000000 --- a/migrations/037-add-memento.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "GroupMatch" add "memento" text`).run(); - })(); -} diff --git a/migrations/038-group-member-note.js b/migrations/038-group-member-note.js deleted file mode 100644 index 9e9a17d1b..000000000 --- a/migrations/038-group-member-note.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "GroupMember" add "note" text`).run(); - })(); -} diff --git a/migrations/039-tournament-match-chat-code.js b/migrations/039-tournament-match-chat-code.js deleted file mode 100644 index 8cc1e1432..000000000 --- a/migrations/039-tournament-match-chat-code.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentMatch" add "chatCode" text`, - ).run(); - })(); -} diff --git a/migrations/040-indexes.js b/migrations/040-indexes.js deleted file mode 100644 index c44e2e089..000000000 --- a/migrations/040-indexes.js +++ /dev/null @@ -1,14 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `create index user_patron_tier on "User"("patronTier")`, - ).run(); - - db.prepare( - /* sql */ `create index calendar_event_result_player_user_id on "CalendarEventResultPlayer"("userId")`, - ).run(); - db.prepare( - /* sql */ `create index calendar_event_result_player_team_id on "CalendarEventResultPlayer"("teamId")`, - ).run(); - })(); -} diff --git a/migrations/041-plus-sixty.js b/migrations/041-plus-sixty.js deleted file mode 100644 index e9f5fe14f..000000000 --- a/migrations/041-plus-sixty.js +++ /dev/null @@ -1,37 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(`drop view "PlusVotingResult"`).run(); - - // same as 000-initial.js except 60% criteria - db.prepare( - /* sql */ ` - create view "PlusVotingResult" as - select - "votedId", - "tier", - avg("score") as "score", - avg("score") >= 0.2 as "passedVoting", - "month", - "year", - exists ( - select - 1 - from - "PlusSuggestion" - where - "PlusSuggestion"."month" = "PlusVote"."month" - and "PlusSuggestion"."year" = "PlusVote"."year" - and "PlusSuggestion"."suggestedId" = "PlusVote"."votedId" - and "PlusSuggestion"."tier" = "PlusVote"."tier" - ) as "wasSuggested" - from - "PlusVote" - group by - "votedId", - "tier", - "month", - "year"; - `, - ).run(); - })(); -} diff --git a/migrations/042-plus-skipped.js b/migrations/042-plus-skipped.js deleted file mode 100644 index 0540bf5cd..000000000 --- a/migrations/042-plus-skipped.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "User" add "plusSkippedForSeasonNth" integer`, - ).run(); -} diff --git a/migrations/043-q-new-map-pick.js b/migrations/043-q-new-map-pick.js deleted file mode 100644 index 21fc0c583..000000000 --- a/migrations/043-q-new-map-pick.js +++ /dev/null @@ -1,29 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "User" add "mapModePreferences" text`, - ).run(); - db.prepare(/* sql */ `alter table "User" add "qWeaponPool" text`).run(); - - db.prepare(`alter table "Group" drop column "mapListPreference"`).run(); - - db.prepare("drop index map_pool_map_group_id").run(); - db.prepare(`delete from "MapPoolMap" where "groupId" is not null`).run(); - db.prepare(`alter table "MapPoolMap" drop column "groupId"`).run(); - - db.prepare( - /*sql*/ ` - create table "PrivateUserNote" ( - "authorId" integer not null, - "targetId" integer not null, - "text" text, - "sentiment" text not null, - "updatedAt" integer default (strftime('%s', 'now')) not null, - foreign key ("authorId") references "User"("id") on delete cascade, - foreign key ("targetId") references "User"("id") on delete cascade, - unique("authorId", "targetId") on conflict rollback - ) strict - `, - ).run(); - })(); -} diff --git a/migrations/044-no-screen.js b/migrations/044-no-screen.js deleted file mode 100644 index bbd370d28..000000000 --- a/migrations/044-no-screen.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "User" add "noScreen" integer default 0`, - ).run(); -} diff --git a/migrations/045-tournament-staff.js b/migrations/045-tournament-staff.js deleted file mode 100644 index a4d7712c9..000000000 --- a/migrations/045-tournament-staff.js +++ /dev/null @@ -1,18 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ ` - create table "TournamentStaff" ( - "tournamentId" integer not null, - "userId" integer not null, - "role" text not null, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("tournamentId", "userId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `alter table "Tournament" add "castTwitchAccounts" text`, - ).run(); -} diff --git a/migrations/046-tournament-progression.js b/migrations/046-tournament-progression.js deleted file mode 100644 index 9fc9fba0b..000000000 --- a/migrations/046-tournament-progression.js +++ /dev/null @@ -1,18 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "Tournament" add "settings" text not null default '{"bracketProgression":[{"type":"double_elimination","name":"Main bracket"}]}'`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentTeamCheckIn" add "bracketIdx" integer`, - ).run(); - - db.prepare(/* sql */ `alter table "Tournament" drop column "format"`).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatchGameResult" add "opponentOnePoints" integer`, - ).run(); - db.prepare( - /* sql */ `alter table "TournamentMatchGameResult" add "opponentTwoPoints" integer`, - ).run(); -} diff --git a/migrations/047-bracket-stuff.js b/migrations/047-bracket-stuff.js deleted file mode 100644 index 4d19f4353..000000000 --- a/migrations/047-bracket-stuff.js +++ /dev/null @@ -1,15 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentStage" add "createdAt" integer`, - ).run(); - - db.prepare( - /* sql */ `alter table "Tournament" add "castedMatchesInfo" text`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatch" drop "childCount"`, - ).run(); - })(); -} diff --git a/migrations/048-season-3-sq.js b/migrations/048-season-3-sq.js deleted file mode 100644 index 57aa4d0c2..000000000 --- a/migrations/048-season-3-sq.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `update "User" set "mapModePreferences" = null`).run(); - db.prepare(/* sql */ `update "User" set "noScreen" = 0`).run(); - - db.prepare( - /* sql */ `alter table "GroupLike" add "isRechallenge" integer`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "UserFriendCode" ( - "friendCode" text not null, - "userId" integer not null, - "submitterUserId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("submitterUserId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - })(); -} diff --git a/migrations/049-tournament-round-maps.js b/migrations/049-tournament-round-maps.js deleted file mode 100644 index 163ff188b..000000000 --- a/migrations/049-tournament-round-maps.js +++ /dev/null @@ -1,3 +0,0 @@ -export function up(db) { - db.prepare(/* sql */ `alter table "TournamentRound" add "maps" text`).run(); -} diff --git a/migrations/050-tournament-no-screen.js b/migrations/050-tournament-no-screen.js deleted file mode 100644 index 26e50024c..000000000 --- a/migrations/050-tournament-no-screen.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "TournamentTeam" add "noScreen" integer not null default 0`, - ).run(); -} diff --git a/migrations/051-pick-ban.js b/migrations/051-pick-ban.js deleted file mode 100644 index f680e4de6..000000000 --- a/migrations/051-pick-ban.js +++ /dev/null @@ -1,32 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "TournamentMatchPickBanEvent" ( - "type" text not null, - "stageId" integer not null, - "mode" text not null, - "matchId" integer not null, - "authorId" integer not null, - "number" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("authorId") references "User"("id") on delete restrict, - foreign key ("matchId") references "TournamentMatch"("id") on delete cascade, - unique("matchId", "number") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index pick_ban_event_author_id on "TournamentMatchPickBanEvent"("authorId")`, - ).run(); - db.prepare( - /* sql */ `create index pick_ban_event_match_id on "TournamentMatchPickBanEvent"("matchId")`, - ).run(); - - db.prepare(/* sql */ `alter table "Tournament" add "rules" text`).run(); - db.prepare( - /* sql */ `alter table "TournamentTeam" add "teamId" integer`, - ).run(); - })(); -} diff --git a/migrations/052-indexes.js b/migrations/052-indexes.js deleted file mode 100644 index 557e9c211..000000000 --- a/migrations/052-indexes.js +++ /dev/null @@ -1,8 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql */ `create index group_match_created_at on "GroupMatch"("createdAt")`, - ).run(); - db.prepare(/*sql */ `create index skill_season on "Skill"("season")`).run(); - })(); -} diff --git a/migrations/053-banned-reason.js b/migrations/053-banned-reason.js deleted file mode 100644 index 6e311f625..000000000 --- a/migrations/053-banned-reason.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "bannedReason" text`).run(); - })(); -} diff --git a/migrations/054-swiss.js b/migrations/054-swiss.js deleted file mode 100644 index a44e8b032..000000000 --- a/migrations/054-swiss.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentTeam" add "droppedOut" integer default 0`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatch" add "createdAt" integer`, - ).run(); - })(); -} diff --git a/migrations/055-lfg.js b/migrations/055-lfg.js deleted file mode 100644 index a7fd81597..000000000 --- a/migrations/055-lfg.js +++ /dev/null @@ -1,29 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "LFGPost" ( - "id" integer primary key, - "type" text not null, - "text" text not null, - "timezone" text not null, - "authorId" integer not null, - "teamId" integer, - "plusTierVisibility" integer, - "updatedAt" integer default (strftime('%s', 'now')) not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("authorId") references "User"("id") on delete restrict, - foreign key ("teamId") references "AllTeam"("id") on delete cascade, - unique("authorId", "type") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index lfg_post_author_id on "LFGPost"("authorId")`, - ).run(); - db.prepare( - /*sql*/ `create index lfg_post_team_id on "LFGPost"("teamId")`, - ).run(); - })(); -} diff --git a/migrations/056-skill-index.js b/migrations/056-skill-index.js deleted file mode 100644 index 438bb486d..000000000 --- a/migrations/056-skill-index.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `create index skill_user_id_season on "Skill" ("userId", "season");`, - ).run(); - })(); -} diff --git a/migrations/057-calendar-event-avatar.js b/migrations/057-calendar-event-avatar.js deleted file mode 100644 index 0c7a6e2a8..000000000 --- a/migrations/057-calendar-event-avatar.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "CalendarEvent" add "avatarImgId" integer`, - ).run(); - - db.prepare( - /* sql */ `alter table "CalendarEvent" add "avatarMetadata" text`, - ).run(); - })(); -} diff --git a/migrations/058-active-roster.js b/migrations/058-active-roster.js deleted file mode 100644 index 0a511d812..000000000 --- a/migrations/058-active-roster.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentTeam" add "activeRosterUserIds" text`, - ).run(); - })(); -} diff --git a/migrations/059-user-name.js b/migrations/059-user-name.js deleted file mode 100644 index 41a68ac45..000000000 --- a/migrations/059-user-name.js +++ /dev/null @@ -1,13 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "customName" text`).run(); - })(); - - db.prepare( - /* sql */ `alter table "User" add "username" text generated always as (coalesce("customName", "discordName")) virtual`, - ).run(); - - db.prepare( - /* sql */ `alter table "User" drop column "discordDiscriminator"`, - ).run(); -} diff --git a/migrations/060-tournament-team-member-ign.js b/migrations/060-tournament-team-member-ign.js deleted file mode 100644 index 6c6d4077b..000000000 --- a/migrations/060-tournament-team-member-ign.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "tournamentTeamMember" add "inGameName" text`, - ).run(); - })(); -} diff --git a/migrations/061-fc-index.js b/migrations/061-fc-index.js deleted file mode 100644 index 15d1af1e8..000000000 --- a/migrations/061-fc-index.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `create index user_friend_code_user_id on "UserFriendCode"("userId")`, - ).run(); - })(); -} diff --git a/migrations/062-tournament-team-avatar.js b/migrations/062-tournament-team-avatar.js deleted file mode 100644 index 2148cc3ad..000000000 --- a/migrations/062-tournament-team-avatar.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentTeam" add "avatarImgId" integer`, - ).run(); - })(); -} diff --git a/migrations/063-user-battlefy.js b/migrations/063-user-battlefy.js deleted file mode 100644 index 86182fd2a..000000000 --- a/migrations/063-user-battlefy.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "battlefy" text`).run(); - })(); -} diff --git a/migrations/064-build-sorting.js b/migrations/064-build-sorting.js deleted file mode 100644 index cc15efb93..000000000 --- a/migrations/064-build-sorting.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "buildSorting" text`).run(); - })(); -} diff --git a/migrations/065-tournament-orgs.js b/migrations/065-tournament-orgs.js deleted file mode 100644 index c54b096d6..000000000 --- a/migrations/065-tournament-orgs.js +++ /dev/null @@ -1,72 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "TournamentOrganization" ( - "id" integer primary key, - "name" text not null, - "slug" text unique not null, - "description" text, - "socials" text, - "avatarImgId" integer, - foreign key ("avatarImgId") references "UnvalidatedUserSubmittedImage"("id") on delete set null - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index tournament_organization_slug on "TournamentOrganization"("slug")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentOrganizationMember" ( - "organizationId" integer not null, - "userId" integer not null, - "role" text not null, - "roleDisplayName" text, - foreign key ("organizationId") references "TournamentOrganization"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("organizationId", "userId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentOrganizationBadge" ( - "organizationId" integer not null, - "badgeId" integer not null, - foreign key ("organizationId") references "TournamentOrganization"("id") on delete cascade, - foreign key ("badgeId") references "Badge"("id") on delete cascade, - unique("organizationId", "badgeId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentOrganizationSeries" ( - "id" integer primary key, - "organizationId" integer not null, - "name" text not null, - "description" text, - "substringMatches" text not null, - "showLeaderboard" integer not null default 0, - foreign key ("organizationId") references "TournamentOrganization"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index tournament_organization_series_organization_id on "TournamentOrganizationSeries"("organizationId")`, - ).run(); - - db.prepare( - /* sql */ `alter table "CalendarEvent" add "organizationId" integer references "TournamentOrganization"("id") on delete set null`, - ).run(); - db.prepare( - /*sql*/ `create index calendar_event_organization_id on "CalendarEvent"("organizationId")`, - ).run(); - })(); -} diff --git a/migrations/066-prepared-maps.js b/migrations/066-prepared-maps.js deleted file mode 100644 index 2718c23f5..000000000 --- a/migrations/066-prepared-maps.js +++ /dev/null @@ -1,10 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "Tournament" add "preparedMaps" text`, - ).run(); - db.prepare( - /* sql */ `alter table "Tournament" drop column "showMapListGenerator"`, - ).run(); - })(); -} diff --git a/migrations/067-tournament-organizer-perms.js b/migrations/067-tournament-organizer-perms.js deleted file mode 100644 index f3cfebbc7..000000000 --- a/migrations/067-tournament-organizer-perms.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - `alter table "User" add column "isTournamentOrganizer" integer default 0`, - ).run(); -} diff --git a/migrations/068-add-missing-user-results-index.js b/migrations/068-add-missing-user-results-index.js deleted file mode 100644 index 6334b135c..000000000 --- a/migrations/068-add-missing-user-results-index.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /*sql*/ `create index tournament_result_tournament_team_id on "TournamentResult"("tournamentTeamId")`, - ).run(); -} diff --git a/migrations/069-many-teams.js b/migrations/069-many-teams.js deleted file mode 100644 index 5bc9af5a0..000000000 --- a/migrations/069-many-teams.js +++ /dev/null @@ -1,38 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "AllTeamMember" add "isMainTeam" integer default 1`, - ).run(); - - db.prepare(/*sql */ `drop view "TeamMember"`).run(); - db.prepare( - /*sql*/ ` - create view "TeamMember" - as - select "AllTeamMember".* - from "AllTeamMember" - left join "Team" on "Team"."id" = "AllTeamMember"."teamId" - where "AllTeamMember"."leftAt" is null - and - -- if team id is null the team is deleted - "Team"."id" is not null - and - "AllTeamMember"."isMainTeam" = 1 - `, - ).run(); - - db.prepare( - /*sql*/ ` - create view "TeamMemberWithSecondary" - as - select "AllTeamMember".* - from "AllTeamMember" - left join "Team" on "Team"."id" = "AllTeamMember"."teamId" - where "AllTeamMember"."leftAt" is null - and - -- if team id is null the team is deleted - "Team"."id" is not null - `, - ).run(); - })(); -} diff --git a/migrations/070-bsky.js b/migrations/070-bsky.js deleted file mode 100644 index 998d38b3a..000000000 --- a/migrations/070-bsky.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "bsky" text`).run(); - - db.prepare(/* sql */ `alter table "AllTeam" add "bsky" text`).run(); - })(); -} diff --git a/migrations/071-homemade-badges.js b/migrations/071-homemade-badges.js deleted file mode 100644 index 3f09f2140..000000000 --- a/migrations/071-homemade-badges.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "Badge" add "authorId" integer`).run(); - })(); - - db.prepare( - /* sql */ `create index badge_author_id on "Badge"("authorId")`, - ).run(); -} diff --git a/migrations/072-free-bracket-progression.js b/migrations/072-free-bracket-progression.js deleted file mode 100644 index e0df2a836..000000000 --- a/migrations/072-free-bracket-progression.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentTeamCheckIn" add "isCheckOut" integer default 0`, - ).run(); - })(); -} diff --git a/migrations/073-trust-timestamp.js b/migrations/073-trust-timestamp.js deleted file mode 100644 index f649ff636..000000000 --- a/migrations/073-trust-timestamp.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TrustRelationship" add "lastUsedAt" integer default 0`, - ).run(); - - db.prepare( - /* sql */ `update "TrustRelationship" set "lastUsedAt" = strftime('%s', 'now')`, - ).run(); - })(); -} diff --git a/migrations/074-seeding-skill.js b/migrations/074-seeding-skill.js deleted file mode 100644 index 4374da428..000000000 --- a/migrations/074-seeding-skill.js +++ /dev/null @@ -1,17 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "SeedingSkill" ( - "mu" real not null, - "sigma" real not null, - "ordinal" real not null, - "userId" integer not null, - "type" text not null, - foreign key ("userId") references "User"("id") on delete cascade, - unique("userId", "type") on conflict replace - ) strict - `, - ).run(); - })(); -} diff --git a/migrations/075-tournament-result-team-id.js b/migrations/075-tournament-result-team-id.js deleted file mode 100644 index 88547aca5..000000000 --- a/migrations/075-tournament-result-team-id.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentMatchGameResultParticipant" add "tournamentTeamId" integer`, - ).run(); - })(); -} diff --git a/migrations/076-progression-override.js b/migrations/076-progression-override.js deleted file mode 100644 index 858bd5ad2..000000000 --- a/migrations/076-progression-override.js +++ /dev/null @@ -1,21 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "TournamentBracketProgressionOverride" ( - "sourceBracketIdx" integer not null, - "destinationBracketIdx" integer not null, - "tournamentTeamId" integer not null, - "tournamentId" integer not null, - unique("sourceBracketIdx", "tournamentTeamId") on conflict replace, - foreign key ("tournamentTeamId") references "TournamentTeam"("id") on delete cascade, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index tournament_bracket_progression_override_tournament_id on "TournamentBracketProgressionOverride"("tournamentId")`, - ).run(); - })(); -} diff --git a/migrations/077-starting-bracket-idx.js b/migrations/077-starting-bracket-idx.js deleted file mode 100644 index 1257aa998..000000000 --- a/migrations/077-starting-bracket-idx.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentTeam" add "startingBracketIdx" integer`, - ).run(); - })(); -} diff --git a/migrations/078-parent-tournament-id.js b/migrations/078-parent-tournament-id.js deleted file mode 100644 index 486073fc0..000000000 --- a/migrations/078-parent-tournament-id.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "Tournament" add "parentTournamentId" integer references "Tournament"("id") on delete restrict`, - ).run(); - - db.prepare( - /* sql */ `alter table "CalendarEvent" add "hidden" integer default 0`, - ).run(); - })(); -} diff --git a/migrations/079-remove-twitter.js b/migrations/079-remove-twitter.js deleted file mode 100644 index 3eace34c3..000000000 --- a/migrations/079-remove-twitter.js +++ /dev/null @@ -1,8 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" drop column "twitter"`).run(); - db.prepare(/* sql */ `alter table "AllTeam" drop column "twitter"`).run(); - - db.prepare(/* sql */ `update "User" set "bsky" = null`).run(); - })(); -} diff --git a/migrations/080-team-manager.js b/migrations/080-team-manager.js deleted file mode 100644 index 03bad8b87..000000000 --- a/migrations/080-team-manager.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "AllTeamMember" add "isManager" integer default 0`, - ).run(); - })(); -} diff --git a/migrations/081-user-preferences.js b/migrations/081-user-preferences.js deleted file mode 100644 index 93fe420e2..000000000 --- a/migrations/081-user-preferences.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "preferences" text`).run(); - })(); -} diff --git a/migrations/082-notification.js b/migrations/082-notification.js deleted file mode 100644 index 80f94d8e3..000000000 --- a/migrations/082-notification.js +++ /dev/null @@ -1,51 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "Notification" ( - "id" integer primary key, - "type" text not null, - "meta" text, - "pictureUrl" text, - "createdAt" integer default (strftime('%s', 'now')) not null - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index notification_type on "Notification"("type")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "NotificationUser" ( - "notificationId" integer not null, - "userId" integer not null, - "seen" integer default 0 not null, - unique("notificationId", "userId"), - foreign key ("notificationId") references "Notification"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index notification_user_id on "NotificationUser"("userId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "NotificationUserSubscription" ( - "id" integer primary key, - "userId" integer not null, - "subscription" text not null, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index notification_push_url_user_id on "NotificationUserSubscription"("userId")`, - ).run(); - })(); -} diff --git a/migrations/083-scrims.js b/migrations/083-scrims.js deleted file mode 100644 index 15b6d7870..000000000 --- a/migrations/083-scrims.js +++ /dev/null @@ -1,112 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "ScrimPost" ( - "id" integer primary key, - "at" integer not null, - "maxDiv" integer, - "minDiv" integer, - "visibility" text, - "text" text, - "chatCode" text not null, - "teamId" integer, - "createdAt" integer default (strftime('%s', 'now')) not null, - "updatedAt" integer default (strftime('%s', 'now')) not null, - foreign key ("teamId") references "AllTeam"("id") on delete cascade - ) strict -`, - ).run(); - - db.prepare( - /*sql*/ `create index scrim_post_team_id on "ScrimPost"("teamId")`, - ).run(); - db.prepare(/*sql*/ `create index scrim_post_at on "ScrimPost"("at")`).run(); - - db.prepare( - /*sql*/ ` - create table "ScrimPostUser" ( - "scrimPostId" integer not null, - "userId" integer not null, - "isOwner" integer not null, - unique("scrimPostId", "userId") on conflict rollback, - foreign key ("scrimPostId") references "ScrimPost"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade - ) strict -`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "ScrimPostRequest" ( - "id" integer primary key, - "scrimPostId" integer not null, - "teamId" integer, - "isAccepted" integer default 0 not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - unique("scrimPostId", "teamId") on conflict rollback, - foreign key ("scrimPostId") references "ScrimPost"("id") on delete cascade, - foreign key ("teamId") references "AllTeam"("id") on delete cascade - ) strict -`, - ).run(); - - db.prepare( - /*sql*/ `create index scrim_post_request_scrim_post_id on "ScrimPostRequest"("scrimPostId")`, - ).run(); - db.prepare( - /*sql*/ `create index scrim_post_request_team_id on "ScrimPostRequest"("teamId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "ScrimPostRequestUser" ( - "scrimPostRequestId" integer not null, - "userId" integer not null, - "isOwner" integer not null, - unique("scrimPostRequestId", "userId") on conflict rollback, - foreign key ("scrimPostRequestId") references "ScrimPostRequest"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade - ) strict -`, - ).run(); - - db.prepare( - /*sql*/ `create index scrim_post_request_user_scrim_post_request_id on "ScrimPostRequestUser"("scrimPostRequestId")`, - ).run(); - db.prepare( - /*sql*/ `create index scrim_post_request_user_user_id on "ScrimPostRequestUser"("userId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "Association" ( - "id" integer primary key, - "name" text not null, - "inviteCode" text not null unique, - "createdAt" integer default (strftime('%s', 'now')) not null - ) strict -`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "AssociationMember" ( - "userId" integer not null, - "associationId" integer not null, - "role" text not null, - unique("userId", "associationId") on conflict rollback, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("associationId") references "Association"("id") on delete cascade - ) strict -`, - ).run(); - - db.prepare( - /*sql*/ `create index association_member_user_id on "AssociationMember"("userId")`, - ).run(); - db.prepare( - /*sql*/ `create index association_member_association_id on "AssociationMember"("associationId")`, - ).run(); - })(); -} diff --git a/migrations/084-favorite-badges.js b/migrations/084-favorite-badges.js deleted file mode 100644 index 87e12f4b8..000000000 --- a/migrations/084-favorite-badges.js +++ /dev/null @@ -1,16 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "User" add "favoriteBadgeIds" text`, - ).run(); - db.prepare(/* sql */ `update "User" - set "favoriteBadgeIds" = - case - when "favoriteBadgeId" is not null then '[' || "favoriteBadgeId" || ']' - else null - end;`).run(); - db.prepare( - /* sql */ `alter table "User" drop column "favoriteBadgeId"`, - ).run(); - })(); -} diff --git a/migrations/085-fix-badge-names.js b/migrations/085-fix-badge-names.js deleted file mode 100644 index cfee0cc89..000000000 --- a/migrations/085-fix-badge-names.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `update "Badge" set "code" = 'fl-collegiate' where "code" = 'FLcollegiate'`, - ).run(); - })(); -} diff --git a/migrations/086-add-weapon-pool-favorites.js b/migrations/086-add-weapon-pool-favorites.js deleted file mode 100644 index ddd1863d8..000000000 --- a/migrations/086-add-weapon-pool-favorites.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.transaction(() => { - const users = db - .prepare(/* sql */ "SELECT id, qWeaponPool FROM User") - .all(); - - const updateStatement = db.prepare( - /* sql */ "UPDATE User SET qWeaponPool = ? WHERE id = ?", - ); - - for (const user of users) { - if (!user.qWeaponPool) continue; - - const pool = JSON.parse(user.qWeaponPool); - const newPool = pool.map((id) => ({ - weaponSplId: id, - isFavorite: 0, - })); - - updateStatement.run(JSON.stringify(newPool), user.id); - } - })(); -} diff --git a/migrations/087-finalize-tournament-bool.js b/migrations/087-finalize-tournament-bool.js deleted file mode 100644 index d7dfcdfc4..000000000 --- a/migrations/087-finalize-tournament-bool.js +++ /dev/null @@ -1,25 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "createdAt" integer`).run(); - - db.prepare( - /* sql */ `alter table "Tournament" add "isFinalized" integer not null default 0`, - ).run(); - - const finalizedTournamentIds = db - .prepare( - /* sql */ `select "tournamentId" from "TournamentResult" group by "tournamentId"`, - ) - .all(); - - const updateStatement = db.prepare( - /* sql */ `update "Tournament" set isFinalized = 1 where id = @tournamentId`, - ); - - for (const tournamentId of finalizedTournamentIds) { - updateStatement.run({ - tournamentId: tournamentId.tournamentId, - }); - } - })(); -} diff --git a/migrations/088-scrimpost-managed-by-anyone.js b/migrations/088-scrimpost-managed-by-anyone.js deleted file mode 100644 index 295101c18..000000000 --- a/migrations/088-scrimpost-managed-by-anyone.js +++ /dev/null @@ -1,16 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "ScrimPost" add column "managedByAnyone" integer default 0 not null`, - ).run(); - db.prepare( - /* sql */ `alter table "ScrimPost" add column "canceledAt" integer`, - ).run(); - db.prepare( - /* sql */ `alter table "ScrimPost" add column "canceledByUserId" integer references "User"("id") on delete restrict`, - ).run(); - db.prepare( - /* sql */ `alter table "ScrimPost" add column "cancelReason" text`, - ).run(); - })(); -} diff --git a/migrations/089-ban-log.js b/migrations/089-ban-log.js deleted file mode 100644 index 8d3dd428b..000000000 --- a/migrations/089-ban-log.js +++ /dev/null @@ -1,37 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `create table "BanLog" ( - "id" integer primary key, - "userId" integer not null, - "banned" integer, - "bannedReason" text, - "bannedByUserId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete restrict, - foreign key ("bannedByUserId") references "User"("id") on delete restrict - )`, - ).run(); - - db.prepare( - /*sql*/ `create index ban_log_user_id on "BanLog"("userId")`, - ).run(); - - db.prepare( - /* sql */ `create table "ModNote" ( - "id" integer primary key, - "userId" integer not null, - "authorId" integer not null, - "text" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - "isDeleted" integer not null default 0, - foreign key ("userId") references "User"("id") on delete restrict, - foreign key ("authorId") references "User"("id") on delete restrict - )`, - ).run(); - - db.prepare( - /*sql*/ `create index mod_note_user_id on "ModNote"("userId")`, - ).run(); - })(); -} diff --git a/migrations/090-tournament-org-banned-players.js b/migrations/090-tournament-org-banned-players.js deleted file mode 100644 index 61eb0c655..000000000 --- a/migrations/090-tournament-org-banned-players.js +++ /dev/null @@ -1,15 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "TournamentOrganizationBannedUser" ( - "organizationId" integer not null references "TournamentOrganization"("id") on delete cascade, - "userId" integer not null references "User"("id") on delete restrict, - "privateNote" text, - "updatedAt" integer default (strftime('%s', 'now')) not null, - unique("organizationId", "userId") on conflict replace - ) - `, - ).run(); - })(); -} diff --git a/migrations/091-scrim-now.js b/migrations/091-scrim-now.js deleted file mode 100644 index 64e02eb19..000000000 --- a/migrations/091-scrim-now.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "ScrimPost" add "isScheduledForFuture" integer default 1`, - ).run(); - })(); -} diff --git a/migrations/092-user-created-at-null.js b/migrations/092-user-created-at-null.js deleted file mode 100644 index 4d45b84a5..000000000 --- a/migrations/092-user-created-at-null.js +++ /dev/null @@ -1,6 +0,0 @@ -export function up(db) { - db.transaction(() => { - // there was a bug in the past where createdAt was set when account was updated instead - db.prepare(/* sql */ `update "User" set "createdAt" = null`).run(); - })(); -} diff --git a/migrations/093-ranked-tournament-results.js b/migrations/093-ranked-tournament-results.js deleted file mode 100644 index 0f4d543ae..000000000 --- a/migrations/093-ranked-tournament-results.js +++ /dev/null @@ -1,15 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentResult" add "setResults" text not null default '[]'`, - ).run(); - db.prepare( - /* sql */ `alter table "TournamentResult" add "spDiff" real`, - ).run(); - db.prepare(/* sql */ `alter table "Skill" add "createdAt" integer`).run(); - - db.prepare( - /*sql*/ `create index tournament_team_team_id on "TournamentTeam"("teamId")`, - ).run(); - })(); -} diff --git a/migrations/094-badge-tournament-id.js b/migrations/094-badge-tournament-id.js deleted file mode 100644 index 052fc9e22..000000000 --- a/migrations/094-badge-tournament-id.js +++ /dev/null @@ -1,10 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentBadgeOwner" add "tournamentId" integer`, - ).run(); - db.prepare( - `create unique index badge_owner_tournament_user_unique on "TournamentBadgeOwner"("tournamentId", "userId")`, - ).run(); - })(); -} diff --git a/migrations/095-drop-unused-tournament-columns.js b/migrations/095-drop-unused-tournament-columns.js deleted file mode 100644 index c922ca1be..000000000 --- a/migrations/095-drop-unused-tournament-columns.js +++ /dev/null @@ -1,35 +0,0 @@ -export function up(db) { - db.transaction(() => { - const roundsWithNullMaps = db - .prepare( - /* sql */ `select "id" from "TournamentRound" where "maps" is null`, - ) - .all() - .map((row) => row.id); - - for (const roundId of roundsWithNullMaps) { - const count = db - .prepare( - /* sql */ `select "bestOf" from "TournamentMatch" where "roundId" = @roundId`, - ) - .get({ roundId }).bestOf; - - db.prepare( - /* sql */ `update "TournamentRound" set "maps" = @maps where "id" = @id`, - ).run({ - id: roundId, - maps: JSON.stringify({ - type: "BEST_OF", - count, - }), - }); - } - - db.prepare( - /* sql */ `alter table "TournamentMatch" drop column "bestOf"`, - ).run(); - db.prepare( - /* sql */ `alter table "CalendarEvent" drop column "avatarMetadata"`, - ).run(); - })(); -} diff --git a/migrations/096-commissions-opened-at.js b/migrations/096-commissions-opened-at.js deleted file mode 100644 index 8bd4e949a..000000000 --- a/migrations/096-commissions-opened-at.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "User" add column "commissionsOpenedAt" integer`, - ).run(); - - db.prepare( - /* sql */ `update "User" set "commissionsOpen" = 0 where "commissionsOpen" = 1`, - ).run(); - })(); -} diff --git a/migrations/097-tournament-org-ban-expires.js b/migrations/097-tournament-org-ban-expires.js deleted file mode 100644 index 275532845..000000000 --- a/migrations/097-tournament-org-ban-expires.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - alter table "TournamentOrganizationBannedUser" add column "expiresAt" integer - `, - ).run(); - })(); -} diff --git a/migrations/098-tournament-match-game-result-indexes.js b/migrations/098-tournament-match-game-result-indexes.js deleted file mode 100644 index 919e7fe56..000000000 --- a/migrations/098-tournament-match-game-result-indexes.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `create index idx_tmgrp_tournament_team_id on "TournamentMatchGameResultParticipant"("tournamentTeamId")`, - ).run(); - })(); -} diff --git a/migrations/099-missing-user-results-index.js b/migrations/099-missing-user-results-index.js deleted file mode 100644 index 004ffe41c..000000000 --- a/migrations/099-missing-user-results-index.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create index calendar_event_date_event_id_start_time on "CalendarEventDate"("eventId", "startTime" desc) - `, - ).run(); - })(); -} diff --git a/migrations/100-build-indexes.js b/migrations/100-build-indexes.js deleted file mode 100644 index ecd25ed71..000000000 --- a/migrations/100-build-indexes.js +++ /dev/null @@ -1,25 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "BuildWeapon" add column "isTop500" integer not null default 0`, - ).run(); - - db.prepare( - /* sql */ `alter table "BuildWeapon" add column "tier" integer not null default 4`, - ).run(); - - db.prepare( - /* sql */ `alter table "BuildWeapon" add column "updatedAt" integer default 1760608251`, - ).run(); - - // speeds up resolving /popular builds - db.prepare( - /* sql */ `create index build_weapon_weapon_spl_id_build_id on "BuildWeapon"("weaponSplId", "buildId")`, - ).run(); - - // speeds up weapon builds list page - db.prepare( - /* sql */ `create index idx_buildweapon_lookup on "BuildWeapon"("weaponSplId", "tier" asc, "isTop500" desc, "updatedAt" desc)`, - ).run(); - })(); -} diff --git a/migrations/101-scrim-request-message.js b/migrations/101-scrim-request-message.js deleted file mode 100644 index 0ace5b9d8..000000000 --- a/migrations/101-scrim-request-message.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "ScrimPostRequest" add "message" text`, - ).run(); - db.prepare( - /* sql */ `alter table "ScrimPost" add "rangeEnd" integer`, - ).run(); - db.prepare( - /* sql */ `alter table "ScrimPostRequest" add "at" integer`, - ).run(); - db.prepare(/* sql */ `alter table "ScrimPost" add "maps" text`).run(); - db.prepare( - /* sql */ `alter table "ScrimPost" add "mapsTournamentId" integer references "Tournament"("id") on delete cascade`, - ).run(); - db.prepare( - /* sql */ `create index "scrim_post_maps_tournament_id" on "ScrimPost"("mapsTournamentId")`, - ).run(); - db.prepare( - /* sql */ `alter table "TournamentTeam" drop column "noScreen"`, - ).run(); - })(); -} diff --git a/migrations/102-tournament-org-is-established.js b/migrations/102-tournament-org-is-established.js deleted file mode 100644 index 8895d0dca..000000000 --- a/migrations/102-tournament-org-is-established.js +++ /dev/null @@ -1,8 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentOrganization" add "isEstablished" integer not null default 0`, - ).run(); - db.prepare(/* sql */ `update "User" set "isTournamentOrganizer" = 0`).run(); - })(); -} diff --git a/migrations/103-tournament-result-div.js b/migrations/103-tournament-result-div.js deleted file mode 100644 index 546aac74b..000000000 --- a/migrations/103-tournament-result-div.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "TournamentResult" add "div" text`).run(); - })(); -} diff --git a/migrations/104-tournament-match-opponent-indexes.js b/migrations/104-tournament-match-opponent-indexes.js deleted file mode 100644 index c15644c81..000000000 --- a/migrations/104-tournament-match-opponent-indexes.js +++ /dev/null @@ -1,11 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `create index idx_tournament_match_opponent_one_id on "TournamentMatch"("opponentOne" ->> '$.id')`, - ).run(); - - db.prepare( - /* sql */ `create index idx_tournament_match_opponent_two_id on "TournamentMatch"("opponentTwo" ->> '$.id')`, - ).run(); - })(); -} diff --git a/migrations/105-api-tokens.js b/migrations/105-api-tokens.js deleted file mode 100644 index c35d80453..000000000 --- a/migrations/105-api-tokens.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "ApiToken" ( - "id" integer primary key, - "token" text not null unique, - "userId" integer not null unique, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index api_token_user_id on "ApiToken"("userId")`, - ).run(); - - db.prepare( - /* sql */ `alter table "User" add "isApiAccesser" integer`, - ).run(); - })(); -} diff --git a/migrations/106-team-tag.js b/migrations/106-team-tag.js deleted file mode 100644 index 8c061e870..000000000 --- a/migrations/106-team-tag.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "AllTeam" add "tag" text`).run(); - })(); -} diff --git a/migrations/107-user-last-sub-message.js b/migrations/107-user-last-sub-message.js deleted file mode 100644 index 400150a1f..000000000 --- a/migrations/107-user-last-sub-message.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "lastSubMessage" text`).run(); - })(); -} diff --git a/migrations/108-match-started-at.js b/migrations/108-match-started-at.js deleted file mode 100644 index bee335548..000000000 --- a/migrations/108-match-started-at.js +++ /dev/null @@ -1,62 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentMatch" add "startedAt" integer`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatch" drop column "createdAt"`, - ).run(); - - db.prepare( - /* sql */ ` - create trigger set_started_at_on_insert - after insert on "TournamentMatch" - for each row - when json_extract(new."opponentOne", '$.id') is not null - and json_extract(new."opponentTwo", '$.id') is not null - and new."status" = 2 - and new."startedAt" is null - begin - update "TournamentMatch" - set "startedAt" = (strftime('%s', 'now')) - where "id" = new."id"; - end - `, - ).run(); - - db.prepare( - /* sql */ ` - create trigger set_started_at_on_update - after update on "TournamentMatch" - for each row - when new."startedAt" is null - and json_extract(new."opponentOne", '$.id') is not null - and json_extract(new."opponentTwo", '$.id') is not null - and new."status" = 2 - begin - update "TournamentMatch" - set "startedAt" = (strftime('%s', 'now')) - where "id" = new."id"; - end - `, - ).run(); - - // note: we are on purpose not handling the case where round robin match is reopened - // this could be a future improvement - db.prepare( - /* sql */ ` - create trigger clear_started_at_on_update - after update on "TournamentMatch" - for each row - when new."startedAt" is not null - and (json_extract(new."opponentOne", '$.id') is null or json_extract(new."opponentTwo", '$.id') is null) - begin - update "TournamentMatch" - set "startedAt" = null - where "id" = new."id"; - end - `, - ).run(); - })(); -} diff --git a/migrations/109-lfg-post-languages.js b/migrations/109-lfg-post-languages.js deleted file mode 100644 index e98448dd0..000000000 --- a/migrations/109-lfg-post-languages.js +++ /dev/null @@ -1,8 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `alter table "LFGPost" add "languages" text`).run(); - db.prepare( - /* sql */ `update "LFGPost" set "languages" = (select "languages" from "User" where "User"."id" = "LFGPost"."authorId")`, - ).run(); - })(); -} diff --git a/migrations/110-pronouns.js b/migrations/110-pronouns.js deleted file mode 100644 index 7ecbf7fba..000000000 --- a/migrations/110-pronouns.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "User" add "pronouns" text default null`, - ).run(); - })(); -} diff --git a/migrations/111-seeding-snapshot.js b/migrations/111-seeding-snapshot.js deleted file mode 100644 index 020ff1b11..000000000 --- a/migrations/111-seeding-snapshot.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "Tournament" add "seedingSnapshot" text default null`, - ).run(); - })(); -} diff --git a/migrations/112-group-match-reported-at-index.js b/migrations/112-group-match-reported-at-index.js deleted file mode 100644 index ff39cec75..000000000 --- a/migrations/112-group-match-reported-at-index.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `create index group_match_reported_at on "GroupMatch"("reportedAt")`, - ).run(); -} diff --git a/migrations/113-season-query-indexes.js b/migrations/113-season-query-indexes.js deleted file mode 100644 index 1de2fa736..000000000 --- a/migrations/113-season-query-indexes.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `create index map_result_user_id_season ON "MapResult"("userId", "season")`, - ).run(); - - db.prepare( - /* sql */ `create index player_result_owner_user_id_season ON "PlayerResult"("ownerUserId", "season")`, - ).run(); -} diff --git a/migrations/114-live-streams.js b/migrations/114-live-streams.js deleted file mode 100644 index c33a6a5e9..000000000 --- a/migrations/114-live-streams.js +++ /dev/null @@ -1,21 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "LiveStream" ( - "id" integer primary key, - "userId" integer unique, - "viewerCount" integer not null, - "thumbnailUrl" text not null, - "twitch" text, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare(/*sql*/ `create index user_twitch on "User"("twitch")`).run(); - db.prepare( - /*sql*/ `create index livestream_twitch on "LiveStream"("twitch")`, - ).run(); - })(); -} diff --git a/migrations/115-splatoon-player-peak-xp.js b/migrations/115-splatoon-player-peak-xp.js deleted file mode 100644 index 1380d9d2b..000000000 --- a/migrations/115-splatoon-player-peak-xp.js +++ /dev/null @@ -1,21 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - alter table "SplatoonPlayer" - add column "peakXp" real - `, - ).run(); - - db.prepare( - /*sql*/ ` - update "SplatoonPlayer" - set "peakXp" = ( - select max("XRankPlacement"."power") - from "XRankPlacement" - where "XRankPlacement"."playerId" = "SplatoonPlayer"."id" - ) - `, - ).run(); - })(); -} diff --git a/migrations/116-tournament-tier.js b/migrations/116-tournament-tier.js deleted file mode 100644 index efe5263e3..000000000 --- a/migrations/116-tournament-tier.js +++ /dev/null @@ -1,6 +0,0 @@ -export function up(db) { - db.prepare(/* sql */ `alter table "Tournament" add "tier" integer`).run(); - db.prepare( - /* sql */ `alter table "TournamentOrganizationSeries" add "tierHistory" text`, - ).run(); -} diff --git a/migrations/117-api-token-types.js b/migrations/117-api-token-types.js deleted file mode 100644 index 28f5f19a8..000000000 --- a/migrations/117-api-token-types.js +++ /dev/null @@ -1,34 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "ApiToken_new" ( - "id" integer primary key, - "token" text not null unique, - "userId" integer not null, - "type" text not null default 'read', - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "ApiToken_new" ("id", "token", "userId", "type", "createdAt") - select "id", "token", "userId", 'read', "createdAt" - from "ApiToken" - `, - ).run(); - - db.prepare(/* sql */ "drop table ApiToken").run(); - - db.prepare( - /* sql */ `alter table "ApiToken_new" rename to "ApiToken"`, - ).run(); - - db.prepare( - /* sql */ `create unique index api_token_user_id_type on "ApiToken"("userId", "type")`, - ).run(); - })(); -} diff --git a/migrations/118-user-widget.js b/migrations/118-user-widget.js deleted file mode 100644 index 41b98847c..000000000 --- a/migrations/118-user-widget.js +++ /dev/null @@ -1,19 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "UserWidget" ( - "userId" integer not null, - "index" integer not null, - "widget" text not null, - primary key ("userId", "index"), - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index user_widget_user_id on "UserWidget"("userId")`, - ).run(); - })(); -} diff --git a/migrations/119-plus-suggestion-updated-at.js b/migrations/119-plus-suggestion-updated-at.js deleted file mode 100644 index e236d7a0f..000000000 --- a/migrations/119-plus-suggestion-updated-at.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "PlusSuggestion" add column "updatedAt" integer`, - ).run(); -} diff --git a/migrations/120-custom-theme.js b/migrations/120-custom-theme.js deleted file mode 100644 index 6585c8efc..000000000 --- a/migrations/120-custom-theme.js +++ /dev/null @@ -1,13 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "User" add "customTheme" text default null`, - ).run(); - db.prepare(/* sql */ `alter table "User" drop column "css"`).run(); - - db.prepare( - /* sql */ `alter table "AllTeam" add "customTheme" text default null`, - ).run(); - db.prepare(/* sql */ `alter table "AllTeam" drop column "css"`).run(); - })(); -} diff --git a/migrations/121-friends-system.js b/migrations/121-friends-system.js deleted file mode 100644 index 7b771cfed..000000000 --- a/migrations/121-friends-system.js +++ /dev/null @@ -1,56 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "Friendship" ( - "id" integer primary key, - "userOneId" integer not null, - "userTwoId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - unique("userOneId", "userTwoId") on conflict rollback, - foreign key ("userOneId") references "User"("id") on delete cascade, - foreign key ("userTwoId") references "User"("id") on delete cascade - ) strict`, - ).run(); - - db.prepare( - `create index friendship_user_one_id on "Friendship"("userOneId")`, - ).run(); - db.prepare( - `create index friendship_user_two_id on "Friendship"("userTwoId")`, - ).run(); - - db.prepare( - /* sql */ ` - create table "FriendRequest" ( - "id" integer primary key, - "senderId" integer not null, - "receiverId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - unique("senderId", "receiverId") on conflict rollback, - foreign key ("senderId") references "User"("id") on delete cascade, - foreign key ("receiverId") references "User"("id") on delete cascade - ) strict`, - ).run(); - - db.prepare( - `create index friend_request_receiver_id on "FriendRequest"("receiverId")`, - ).run(); - - db.prepare( - `create index all_team_member_user_id on "AllTeamMember"("userId")`, - ).run(); - - db.prepare( - /* sql */ ` - INSERT INTO "Friendship" ("userOneId", "userTwoId") - SELECT t1."trustGiverUserId", t1."trustReceiverUserId" - FROM "TrustRelationship" t1 - INNER JOIN "TrustRelationship" t2 - ON t1."trustGiverUserId" = t2."trustReceiverUserId" - AND t1."trustReceiverUserId" = t2."trustGiverUserId" - WHERE t1."trustGiverUserId" < t1."trustReceiverUserId" - ON CONFLICT DO NOTHING`, - ).run(); - })(); -} diff --git a/migrations/122-saved-calendar-event.js b/migrations/122-saved-calendar-event.js deleted file mode 100644 index e252abde4..000000000 --- a/migrations/122-saved-calendar-event.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "SavedCalendarEvent" ( - "id" integer primary key, - "userId" integer not null, - "calendarEventId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - unique("userId", "calendarEventId") on conflict rollback, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("calendarEventId") references "CalendarEvent"("id") on delete cascade - ) strict`, - ).run(); - - db.prepare( - `create index saved_calendar_event_user_id on "SavedCalendarEvent"("userId")`, - ).run(); - db.prepare( - `create index saved_calendar_event_calendar_event_id on "SavedCalendarEvent"("calendarEventId")`, - ).run(); - })(); -} diff --git a/migrations/123-splatoon-rotation.js b/migrations/123-splatoon-rotation.js deleted file mode 100644 index 91784fc35..000000000 --- a/migrations/123-splatoon-rotation.js +++ /dev/null @@ -1,16 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "SplatoonRotation" ( - "id" integer primary key, - "type" text not null, - "mode" text not null, - "stageId1" integer not null, - "stageId2" integer not null, - "startTime" integer not null, - "endTime" integer not null - ) strict`, - ).run(); - })(); -} diff --git a/migrations/124-tournament-lfg.js b/migrations/124-tournament-lfg.js deleted file mode 100644 index 387ff6adb..000000000 --- a/migrations/124-tournament-lfg.js +++ /dev/null @@ -1,77 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ `alter table "TournamentTeam" add column "isLooking" integer not null default 0`, - ).run(); - db.prepare( - /*sql*/ `alter table "TournamentTeam" add column "isPlaceholder" integer not null default 0`, - ).run(); - db.prepare( - /*sql*/ `alter table "TournamentTeam" add column "lfgNote" text`, - ).run(); - db.prepare( - /*sql*/ `alter table "TournamentTeam" add column "chatCode" text`, - ).run(); - - db.prepare( - /*sql*/ `alter table "TournamentTeamMember" add column "role" text not null default 'REGULAR'`, - ).run(); - db.prepare( - /*sql*/ `alter table "TournamentTeamMember" add column "isStayAsSub" integer not null default 0`, - ).run(); - db.prepare( - /*sql*/ `alter table "TournamentTeamMember" add column "isLooking" integer not null default 0`, - ).run(); - - db.prepare( - /*sql*/ `create index tournament_team_member_user_id_is_looking on "TournamentTeamMember"("userId", "isLooking")`, - ).run(); - - db.prepare( - /*sql*/ ` - create trigger sync_is_looking_on_team_update - after update of isLooking on "TournamentTeam" - begin - update "TournamentTeamMember" - set "isLooking" = NEW."isLooking" - where "tournamentTeamId" = NEW."id"; - end - `, - ).run(); - db.prepare( - /*sql*/ ` - create trigger sync_is_looking_on_member_insert - after insert on "TournamentTeamMember" - begin - update "TournamentTeamMember" - set "isLooking" = (select "isLooking" from "TournamentTeam" where "id" = NEW."tournamentTeamId") - where rowid = NEW.rowid; - end - `, - ).run(); - - db.prepare( - /*sql*/ `update "TournamentTeamMember" set "role" = 'OWNER' where "isOwner" = 1`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TournamentLFGLike" ( - "likerTeamId" integer not null, - "targetTeamId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("likerTeamId") references "TournamentTeam"("id") on delete cascade, - foreign key ("targetTeamId") references "TournamentTeam"("id") on delete cascade, - unique("likerTeamId", "targetTeamId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index tournament_lfg_like_liker_team_id on "TournamentLFGLike"("likerTeamId")`, - ).run(); - db.prepare( - /*sql*/ `create index tournament_lfg_like_target_team_id on "TournamentLFGLike"("targetTeamId")`, - ).run(); - })(); -} diff --git a/migrations/125-tournament-streamer.js b/migrations/125-tournament-streamer.js deleted file mode 100644 index 50b53db95..000000000 --- a/migrations/125-tournament-streamer.js +++ /dev/null @@ -1,29 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "TournamentStreamer" ( - "id" integer primary key autoincrement, - "userId" integer, - "tournamentId" integer not null, - "twitchAccount" text not null, - unique("twitchAccount", "tournamentId") on conflict ignore - ) strict - `, - ).run(); - - const rows = db - .prepare( - /*sql*/ `select "id", "castedMatchesInfo" from "Tournament" where "castedMatchesInfo" is not null`, - ) - .all(); - - for (const row of rows) { - const info = JSON.parse(row.castedMatchesInfo); - info.lockedMatches = []; - db.prepare( - /*sql*/ `update "Tournament" set "castedMatchesInfo" = ? where "id" = ?`, - ).run(JSON.stringify(info), row.id); - } - })(); -} diff --git a/migrations/126-pick-ban-custom-flow.js b/migrations/126-pick-ban-custom-flow.js deleted file mode 100644 index a9b9db8d6..000000000 --- a/migrations/126-pick-ban-custom-flow.js +++ /dev/null @@ -1,41 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "TournamentMatchPickBanEvent_new" ( - "type" text not null, - "stageId" integer, - "mode" text, - "matchId" integer not null, - "authorId" integer, - "number" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("authorId") references "User"("id") on delete restrict, - foreign key ("matchId") references "TournamentMatch"("id") on delete cascade, - unique("matchId", "number") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - insert into "TournamentMatchPickBanEvent_new" ("type", "stageId", "mode", "matchId", "authorId", "number", "createdAt") - select "type", "stageId", "mode", "matchId", "authorId", "number", "createdAt" - from "TournamentMatchPickBanEvent" - `, - ).run(); - - db.prepare(/*sql*/ `drop table "TournamentMatchPickBanEvent"`).run(); - - db.prepare( - /*sql*/ `alter table "TournamentMatchPickBanEvent_new" rename to "TournamentMatchPickBanEvent"`, - ).run(); - - db.prepare( - /*sql*/ `create index pick_ban_event_author_id on "TournamentMatchPickBanEvent"("authorId")`, - ).run(); - db.prepare( - /*sql*/ `create index pick_ban_event_match_id on "TournamentMatchPickBanEvent"("matchId")`, - ).run(); - })(); -} diff --git a/migrations/127-tournament-match-vod.js b/migrations/127-tournament-match-vod.js deleted file mode 100644 index 0432339b0..000000000 --- a/migrations/127-tournament-match-vod.js +++ /dev/null @@ -1,22 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "TournamentMatchVod" ( - "id" integer primary key autoincrement, - "matchId" integer not null references "TournamentMatch"("id"), - "userId" integer references "User"("id"), - "platform" text not null, - "account" text not null, - "platformVideoId" text not null, - "timestampSeconds" integer not null, - "viewCount" integer not null - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create unique index "tournament_match_vod_match_id_account" on "TournamentMatchVod"("matchId", "account")`, - ).run(); - })(); -} diff --git a/migrations/128-team-map-mode-preferences.js b/migrations/128-team-map-mode-preferences.js deleted file mode 100644 index 8152599b5..000000000 --- a/migrations/128-team-map-mode-preferences.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "AllTeam" add column "mapModePreferences" text`, - ).run(); -} diff --git a/migrations/129-tournament-vod-sync-timestamps.js b/migrations/129-tournament-vod-sync-timestamps.js deleted file mode 100644 index 5dc74fcd1..000000000 --- a/migrations/129-tournament-vod-sync-timestamps.js +++ /dev/null @@ -1,8 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "Tournament" add column "vodsLastSyncAt" integer`, - ).run(); - db.prepare( - /* sql */ `alter table "Tournament" add column "vodsSyncCount" integer not null default 0`, - ).run(); -} diff --git a/migrations/130-join-order.js b/migrations/130-join-order.js deleted file mode 100644 index 8b515c8df..000000000 --- a/migrations/130-join-order.js +++ /dev/null @@ -1,34 +0,0 @@ -import { readFileSync } from "node:fs"; -import { dirname, resolve } from "node:path"; -import { fileURLToPath } from "node:url"; - -export function up(db) { - const dir = dirname(fileURLToPath(import.meta.url)); - const jsonPath = resolve(dir, "../scripts/join-order.json"); - const mapping = JSON.parse(readFileSync(jsonPath, "utf-8")); - - db.transaction(() => { - db.prepare(/* sql */ `alter table "User" add "joinOrder" integer`).run(); - - const stmt = db.prepare( - /* sql */ `update "User" set "joinOrder" = ? where "id" = ?`, - ); - for (const [sqliteId, joinOrder] of Object.entries(mapping)) { - stmt.run(joinOrder, Number(sqliteId)); - } - - const maxJoinOrder = db - .prepare(/* sql */ `select max("joinOrder") as m from "User"`) - .get().m; - - const unmapped = db - .prepare( - /* sql */ `select "id" from "User" where "joinOrder" is null order by "id" asc`, - ) - .all(); - - for (let i = 0; i < unmapped.length; i++) { - stmt.run(maxJoinOrder + 1 + i, unmapped[i].id); - } - })(); -} diff --git a/migrations/131-tournament-team-member-drop-is-owner.js b/migrations/131-tournament-team-member-drop-is-owner.js deleted file mode 100644 index f94ae8de4..000000000 --- a/migrations/131-tournament-team-member-drop-is-owner.js +++ /dev/null @@ -1,14 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `update "TournamentTeamMember" set "role" = 'OWNER' where "isOwner" = 1 and "role" != 'OWNER'`, - ).run(); - db.prepare( - /* sql */ `update "TournamentTeamMember" set "role" = 'REGULAR' where "isOwner" = 0 and "role" = 'OWNER'`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentTeamMember" drop column "isOwner"`, - ).run(); - })(); -} diff --git a/migrations/132-build-gear-nullable.js b/migrations/132-build-gear-nullable.js deleted file mode 100644 index 035db381b..000000000 --- a/migrations/132-build-gear-nullable.js +++ /dev/null @@ -1,53 +0,0 @@ -export function up(db) { - db.pragma("foreign_keys = OFF"); - - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "Build_new" ( - "id" integer primary key, - "ownerId" integer not null, - "title" text not null, - "description" text, - "modes" text, - "headGearSplId" integer, - "clothesGearSplId" integer, - "shoesGearSplId" integer, - "updatedAt" integer default (strftime('%s', 'now')) not null, - "private" integer default 0, - foreign key ("ownerId") references "User"("id") on delete restrict - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - insert into "Build_new" ("id", "ownerId", "title", "description", "modes", "headGearSplId", "clothesGearSplId", "shoesGearSplId", "updatedAt", "private") - select - "id", - "ownerId", - "title", - "description", - "modes", - case when "headGearSplId" = -1 then null else "headGearSplId" end, - case when "clothesGearSplId" = -1 then null else "clothesGearSplId" end, - case when "shoesGearSplId" = -1 then null else "shoesGearSplId" end, - "updatedAt", - "private" - from "Build" - `, - ).run(); - - db.prepare(/*sql*/ `drop table "Build"`).run(); - - db.prepare(/*sql*/ `alter table "Build_new" rename to "Build"`).run(); - - db.prepare( - /*sql*/ `create index build_owner_id on "Build"("ownerId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); - - db.pragma("foreign_keys = ON"); -} diff --git a/migrations/133-tournament-team-ab-division.js b/migrations/133-tournament-team-ab-division.js deleted file mode 100644 index d4042ad02..000000000 --- a/migrations/133-tournament-team-ab-division.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "TournamentTeam" add column "abDivision" integer`, - ).run(); -} diff --git a/migrations/134-calendar-event-strip-mode-tags.js b/migrations/134-calendar-event-strip-mode-tags.js deleted file mode 100644 index 3caa20517..000000000 --- a/migrations/134-calendar-event-strip-mode-tags.js +++ /dev/null @@ -1,25 +0,0 @@ -export function up(db) { - db.transaction(() => { - const rows = db - .prepare( - /* sql */ `select "id", "tags" from "CalendarEvent" where "tags" is not null`, - ) - .all(); - - const stmt = db.prepare( - /* sql */ `update "CalendarEvent" set "tags" = ? where "id" = ?`, - ); - - for (const row of rows) { - const cleaned = row.tags - .split(",") - .filter((tag) => tag !== "SZ" && tag !== "TW") - .join(","); - const newTags = cleaned === "" ? null : cleaned; - - if (newTags !== row.tags) { - stmt.run(newTags, row.id); - } - } - })(); -} diff --git a/migrations/135-tournament-team-check-in-unique.js b/migrations/135-tournament-team-check-in-unique.js deleted file mode 100644 index 325e79ee8..000000000 --- a/migrations/135-tournament-team-check-in-unique.js +++ /dev/null @@ -1,19 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - delete from "TournamentTeamCheckIn" - where "rowid" not in ( - select max("rowid") - from "TournamentTeamCheckIn" - group by "tournamentTeamId", coalesce("bracketIdx", -1) - )`, - ).run(); - - db.prepare( - /* sql */ ` - create unique index "tournament_team_check_in_team_bracket_unique" - on "TournamentTeamCheckIn"("tournamentTeamId", coalesce("bracketIdx", -1))`, - ).run(); - })(); -} diff --git a/migrations/136-fix-empty-placements-progression.js b/migrations/136-fix-empty-placements-progression.js deleted file mode 100644 index 03b06b4f8..000000000 --- a/migrations/136-fix-empty-placements-progression.js +++ /dev/null @@ -1,19 +0,0 @@ -const TOURNAMENT_ID = 1078; - -export function up(db) { - const row = db - .prepare(/* sql */ `select "settings" from "Tournament" where "id" = ?`) - .get(TOURNAMENT_ID); - - if (!row) return; - - const settings = JSON.parse(row.settings); - const source = settings.bracketProgression?.[1]?.sources?.[0]; - if (source?.placements?.length !== 0) return; - - source.placements = [-1]; - - db.prepare( - /* sql */ `update "Tournament" set "settings" = ? where "id" = ?`, - ).run(JSON.stringify(settings), TOURNAMENT_ID); -} diff --git a/migrations/137-match-page.js b/migrations/137-match-page.js deleted file mode 100644 index c386968a8..000000000 --- a/migrations/137-match-page.js +++ /dev/null @@ -1,172 +0,0 @@ -export function up(db) { - db.pragma("foreign_keys = OFF"); - - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "RoomLink" ( - "userId" integer not null unique, - "url" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - "refreshedAt" integer default (strftime('%s', 'now')) not null, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `alter table "User" add "noSplatnet" integer default 0 not null`, - ).run(); - - db.prepare( - /* sql */ `alter table "Group" add "matchmade" integer default 0 not null`, - ).run(); - - db.prepare( - /* sql */ `alter table "GroupMatchMap" add "reportedAt" integer`, - ).run(); - - db.prepare( - /* sql */ `alter table "GroupMatchMap" add "reportedByUserId" integer references "User"("id")`, - ).run(); - - db.prepare( - /* sql */ ` - update "GroupMatchMap" - set - "reportedAt" = ( - select "reportedAt" from "GroupMatch" - where "GroupMatch"."id" = "GroupMatchMap"."matchId" - ), - "reportedByUserId" = ( - select "reportedByUserId" from "GroupMatch" - where "GroupMatch"."id" = "GroupMatchMap"."matchId" - ) - where "winnerGroupId" is not null - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "GroupMatch_new" ( - "id" integer primary key, - "alphaGroupId" integer not null, - "bravoGroupId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - "chatCode" text, - "memento" text, - "confirmedAt" integer, - "confirmedByUserId" integer references "User"("id"), - "cancelRequestedByUserId" integer references "User"("id"), - "cancelAcceptedByUserId" integer references "User"("id"), - foreign key ("alphaGroupId") references "Group"("id") on delete restrict, - foreign key ("bravoGroupId") references "Group"("id") on delete restrict, - unique("alphaGroupId") on conflict rollback, - unique("bravoGroupId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "GroupMatch_new" ( - "id", "alphaGroupId", "bravoGroupId", "createdAt", "chatCode", "memento" - ) - select - "id", "alphaGroupId", "bravoGroupId", "createdAt", "chatCode", "memento" - from "GroupMatch" - `, - ).run(); - - db.prepare(/* sql */ `drop table "GroupMatch"`).run(); - db.prepare( - /* sql */ `alter table "GroupMatch_new" rename to "GroupMatch"`, - ).run(); - - db.prepare( - /* sql */ `create index group_match_alpha_group_id on "GroupMatch"("alphaGroupId")`, - ).run(); - db.prepare( - /* sql */ `create index group_match_bravo_group_id on "GroupMatch"("bravoGroupId")`, - ).run(); - db.prepare( - /* sql */ `create index group_match_created_at on "GroupMatch"("createdAt")`, - ).run(); - db.prepare( - /* sql */ `create index group_match_confirmed_at on "GroupMatch"("confirmedAt")`, - ).run(); - - db.prepare( - /* sql */ `create index group_match_map_reported_at on "GroupMatchMap"("reportedAt")`, - ).run(); - - db.prepare( - /* sql */ ` - create table "GroupMatchContinueVote" ( - "id" integer primary key, - "groupId" integer not null, - "userId" integer not null, - "isContinuing" integer not null check ("isContinuing" in (0, 1)), - "votedAt" integer default (strftime('%s', 'now')) not null, - foreign key ("groupId") references "Group"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("groupId", "userId") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index group_match_continue_vote_group_id on "GroupMatchContinueVote"("groupId")`, - ).run(); - - db.prepare( - /* sql */ ` - create table "ReportedWeapon_new" ( - "groupMatchId" integer, - "tournamentMatchId" integer, - "mapIndex" integer not null, - "weaponSplId" integer not null, - "userId" integer not null, - foreign key ("groupMatchId") references "GroupMatch"("id") on delete cascade, - foreign key ("tournamentMatchId") references "TournamentMatch"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete restrict, - unique("groupMatchId", "mapIndex", "userId") on conflict rollback, - unique("tournamentMatchId", "mapIndex", "userId") on conflict rollback, - check (("groupMatchId" is not null) <> ("tournamentMatchId" is not null)) - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "ReportedWeapon_new" ( - "groupMatchId", "tournamentMatchId", "mapIndex", "weaponSplId", "userId" - ) - select - "GroupMatchMap"."matchId", null, "GroupMatchMap"."index", - "ReportedWeapon"."weaponSplId", "ReportedWeapon"."userId" - from "ReportedWeapon" - inner join "GroupMatchMap" on "GroupMatchMap"."id" = "ReportedWeapon"."groupMatchMapId" - `, - ).run(); - - db.prepare(/* sql */ `drop table "ReportedWeapon"`).run(); - db.prepare( - /* sql */ `alter table "ReportedWeapon_new" rename to "ReportedWeapon"`, - ).run(); - - db.prepare( - /* sql */ `create index reported_weapon_group_match_id on "ReportedWeapon"("groupMatchId")`, - ).run(); - db.prepare( - /* sql */ `create index reported_weapon_tournament_match_id on "ReportedWeapon"("tournamentMatchId")`, - ).run(); - db.prepare( - /* sql */ `create index reported_weapon_user_id on "ReportedWeapon"("userId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); - - db.pragma("foreign_keys = ON"); -} diff --git a/migrations/138-cap-tournament-placements.js b/migrations/138-cap-tournament-placements.js deleted file mode 100644 index fa821f02d..000000000 --- a/migrations/138-cap-tournament-placements.js +++ /dev/null @@ -1,38 +0,0 @@ -const PLACEMENT_MAX = 100; - -export function up(db) { - const rows = db - .prepare(/* sql */ `select "id", "settings" from "Tournament"`) - .all(); - - const updates = []; - for (const row of rows) { - const settings = JSON.parse(row.settings); - const progression = settings.bracketProgression; - if (!Array.isArray(progression)) continue; - - let changed = false; - for (const bracket of progression) { - for (const source of bracket.sources ?? []) { - if (!Array.isArray(source.placements)) continue; - const filtered = source.placements.filter((p) => p <= PLACEMENT_MAX); - if (filtered.length !== source.placements.length) { - source.placements = filtered; - changed = true; - } - } - } - - if (changed) { - updates.push({ id: row.id, settings: JSON.stringify(settings) }); - } - } - - const update = db.prepare( - /* sql */ `update "Tournament" set "settings" = ? where "id" = ?`, - ); - - for (const u of updates) { - update.run(u.settings, u.id); - } -} diff --git a/migrations/139-plus-voting-criteria.js b/migrations/139-plus-voting-criteria.js deleted file mode 100644 index 8b7a0a10f..000000000 --- a/migrations/139-plus-voting-criteria.js +++ /dev/null @@ -1,36 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(`drop view "FreshPlusTier"`).run(); - db.prepare(`drop view "PlusVotingResult"`).run(); - - db.prepare( - /* sql */ ` - create view "PlusVotingResult" as - select - "votedId", - "tier", - avg("score") as "score", - "month", - "year", - exists ( - select - 1 - from - "PlusSuggestion" - where - "PlusSuggestion"."month" = "PlusVote"."month" - and "PlusSuggestion"."year" = "PlusVote"."year" - and "PlusSuggestion"."suggestedId" = "PlusVote"."votedId" - and "PlusSuggestion"."tier" = "PlusVote"."tier" - ) as "wasSuggested" - from - "PlusVote" - group by - "votedId", - "tier", - "month", - "year"; - `, - ).run(); - })(); -} diff --git a/migrations/140-tournament-badge-owner-count.js b/migrations/140-tournament-badge-owner-count.js deleted file mode 100644 index 417f65c1a..000000000 --- a/migrations/140-tournament-badge-owner-count.js +++ /dev/null @@ -1,56 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "TournamentBadgeOwner" add column "count" integer not null default 1`, - ).run(); - - db.prepare( - /* sql */ ` - update "TournamentBadgeOwner" - set "count" = ( - select count(*) from "TournamentBadgeOwner" t2 - where t2."userId" = "TournamentBadgeOwner"."userId" - and t2."badgeId" = "TournamentBadgeOwner"."badgeId" - and t2."tournamentId" is null - ) - where rowid in ( - select min(rowid) from "TournamentBadgeOwner" - where "tournamentId" is null - group by "userId", "badgeId" - ) - `, - ).run(); - - db.prepare( - /* sql */ ` - delete from "TournamentBadgeOwner" - where "tournamentId" is null - and rowid not in ( - select min(rowid) from "TournamentBadgeOwner" - where "tournamentId" is null - group by "userId", "badgeId" - ) - `, - ).run(); - - db.prepare(/* sql */ `drop view "BadgeOwner"`).run(); - - db.prepare( - /* sql */ ` - create view "BadgeOwner" as - select "userId", "badgeId", "count" from "TournamentBadgeOwner" - union all - select - "id" as "userId", - case when "patronTier" = 2 then 40 else 41 end as "badgeId", - 1 as "count" - from "User" - where "patronTier" > 1 - `, - ).run(); - - db.prepare( - /* sql */ `create index tournament_badge_owner_user_id on "TournamentBadgeOwner"("userId")`, - ).run(); - })(); -} diff --git a/migrations/141-reported-weapon-created-at.js b/migrations/141-reported-weapon-created-at.js deleted file mode 100644 index 3827f0790..000000000 --- a/migrations/141-reported-weapon-created-at.js +++ /dev/null @@ -1,87 +0,0 @@ -export function up(db) { - db.pragma("foreign_keys = OFF"); - - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "ReportedWeapon_new" ( - "groupMatchId" integer, - "tournamentMatchId" integer, - "mapIndex" integer not null, - "weaponSplId" integer not null, - "userId" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("groupMatchId") references "GroupMatch"("id") on delete cascade, - foreign key ("tournamentMatchId") references "TournamentMatch"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete restrict, - unique("groupMatchId", "mapIndex", "userId") on conflict rollback, - unique("tournamentMatchId", "mapIndex", "userId") on conflict rollback, - check (("groupMatchId" is not null) <> ("tournamentMatchId" is not null)) - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "ReportedWeapon_new" - ("groupMatchId", "tournamentMatchId", "mapIndex", "weaponSplId", "userId", "createdAt") - select - "rw"."groupMatchId", - "rw"."tournamentMatchId", - "rw"."mapIndex", - "rw"."weaponSplId", - "rw"."userId", - case - when "rw"."groupMatchId" is not null then ( - select "GroupMatch"."createdAt" - from "GroupMatch" - where "GroupMatch"."id" = "rw"."groupMatchId" - ) - else coalesce( - ( - select min("CalendarEventDate"."startTime") - from "CalendarEventDate" - inner join "CalendarEvent" - on "CalendarEvent"."id" = "CalendarEventDate"."eventId" - inner join "Tournament" - on "Tournament"."id" = "CalendarEvent"."tournamentId" - inner join "TournamentStage" - on "TournamentStage"."tournamentId" = "Tournament"."id" - inner join "TournamentMatch" - on "TournamentMatch"."stageId" = "TournamentStage"."id" - where "TournamentMatch"."id" = "rw"."tournamentMatchId" - ), - strftime('%s', 'now') - ) - end - from "ReportedWeapon" as "rw" - `, - ).run(); - - db.prepare(/* sql */ `drop table "ReportedWeapon"`).run(); - - db.prepare( - /* sql */ `alter table "ReportedWeapon_new" rename to "ReportedWeapon"`, - ).run(); - - db.prepare( - /* sql */ `create index reported_weapon_group_match_id on "ReportedWeapon"("groupMatchId")`, - ).run(); - - db.prepare( - /* sql */ `create index reported_weapon_tournament_match_id on "ReportedWeapon"("tournamentMatchId")`, - ).run(); - - db.prepare( - /* sql */ `create index reported_weapon_user_id on "ReportedWeapon"("userId")`, - ).run(); - - db.prepare( - /* sql */ `create index reported_weapon_user_created_at_weapon on "ReportedWeapon"("userId", "createdAt", "weaponSplId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); - - db.pragma("foreign_keys = ON"); -} diff --git a/migrations/142-builds-optimization.js b/migrations/142-builds-optimization.js deleted file mode 100644 index d420817be..000000000 --- a/migrations/142-builds-optimization.js +++ /dev/null @@ -1,255 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "Build" add column "abilities" text`, - ).run(); - - db.prepare( - /* sql */ `alter table "Build" add column "abilitiesSignature" text`, - ).run(); - - db.prepare( - /* sql */ ` - create table "BuildAbilitySum" ( - "buildId" integer not null, - "ability" text not null, - "abilityPoints" integer not null, - foreign key ("buildId") references "Build"("id") on delete cascade, - unique("buildId", "ability") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "BuildWeaponAbility" ( - "canonicalWeaponSplId" integer not null, - "buildId" integer not null, - "ability" text not null, - "abilityPoints" integer not null, - foreign key ("buildId") references "Build"("id") on delete cascade, - unique("canonicalWeaponSplId", "buildId", "ability") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - update "Build" set "abilities" = ( - select json_array( - ( - select json_group_array("ability") from ( - select "ability" from "BuildAbility" - where "buildId" = "Build"."id" and "gearType" = 'HEAD' - order by "slotIndex" - ) - ), - ( - select json_group_array("ability") from ( - select "ability" from "BuildAbility" - where "buildId" = "Build"."id" and "gearType" = 'CLOTHES' - order by "slotIndex" - ) - ), - ( - select json_group_array("ability") from ( - select "ability" from "BuildAbility" - where "buildId" = "Build"."id" and "gearType" = 'SHOES' - order by "slotIndex" - ) - ) - ) - ) - `, - ).run(); - - // Public builds only: private builds are never surfaced in stats/popular - // queries, so excluding them here turns the sum-table queries into pure - // covering-index scans (no Build join needed for the private filter). - db.prepare( - /* sql */ ` - insert into "BuildAbilitySum" ("buildId", "ability", "abilityPoints") - select "ba"."buildId", "ba"."ability", sum("ba"."abilityPoints") - from "BuildAbility" as "ba" - inner join "Build" as "b" on "b"."id" = "ba"."buildId" - where "b"."private" = 0 - group by "ba"."buildId", "ba"."ability" - `, - ).run(); - - // Alt skins are folded into their base weapon so a build that lists - // multiple alt skins of the same weapon only contributes its ability - // points once. `insert or ignore` handles the dedup against the - // unique(canonicalWeaponSplId, buildId, ability). - db.prepare( - /* sql */ ` - insert or ignore into "BuildWeaponAbility" ("canonicalWeaponSplId", "buildId", "ability", "abilityPoints") - select - case "bw"."weaponSplId" - when 45 then 40 - when 47 then 40 - when 46 then 41 - when 205 then 200 - when 1015 then 1010 - when 1115 then 1110 - when 2015 then 2010 - when 3005 then 3000 - when 4015 then 4010 - when 5015 then 5010 - when 6005 then 6000 - when 7015 then 7010 - when 8005 then 8000 - else "bw"."weaponSplId" - end, - "bs"."buildId", "bs"."ability", "bs"."abilityPoints" - from "BuildAbilitySum" as "bs" - inner join "BuildWeapon" as "bw" on "bw"."buildId" = "bs"."buildId" - `, - ).run(); - - db.prepare( - /* sql */ ` - update "Build" set "abilitiesSignature" = ( - select group_concat("ability" || '_' || "abilityPoints", ',') from ( - select "ability", "abilityPoints" from "BuildAbilitySum" - where "buildId" = "Build"."id" - order by "abilityPoints" desc, "ability" asc - ) - ) - `, - ).run(); - - // Covering indexes: `abilityPoints` included so SUM(...) GROUP BY ability - // can be answered entirely from the index without rowid lookups. - db.prepare( - /* sql */ `create index build_ability_sum_ability_ap on "BuildAbilitySum"("ability", "abilityPoints")`, - ).run(); - - db.prepare( - /* sql */ `create index build_weapon_ability_weapon_ability_ap on "BuildWeaponAbility"("canonicalWeaponSplId", "ability", "abilityPoints")`, - ).run(); - - db.prepare( - /* sql */ `create index build_abilities_signature on "Build"("abilitiesSignature")`, - ).run(); - - // sortValue lives only on BuildWeapon — it depends on the owner's plus - // tier and on whether the owner has an X Rank placement for *this - // specific weapon*. The `(weaponSplId, sortValue, updatedAt DESC, - // buildId)` covering index below answers builds-by-weapon end-to-end. - db.prepare( - /* sql */ `alter table "BuildWeapon" add column "sortValue" integer`, - ).run(); - - // Pass 1: tier*2 + 1 for public, NULL for private. Mirror Build.updatedAt. - db.prepare( - /* sql */ ` - update "BuildWeapon" set - "updatedAt" = (select "updatedAt" from "Build" where "id" = "BuildWeapon"."buildId"), - "sortValue" = ( - select case - when "b"."private" = 1 then null - else coalesce( - (select "tier" from "PlusTier" where "userId" = "b"."ownerId"), - 4 - ) * 2 + 1 - end - from "Build" as "b" - where "b"."id" = "BuildWeapon"."buildId" - ) - `, - ).run(); - - // Pass 2: subtract 1 where THIS weapon is top500 for the owner. Per-weapon, - // not per-build, so a build with Luna Blaster + Blaster gets the crown only - // on the weapon the owner actually placed with. - db.prepare( - /* sql */ ` - update "BuildWeapon" set "sortValue" = "sortValue" - 1 - where "sortValue" is not null - and exists ( - select 1 - from "Build" as "b" - inner join "SplatoonPlayer" as "sp" on "sp"."userId" = "b"."ownerId" - inner join "XRankPlacement" as "xrp" - on "xrp"."playerId" = "sp"."id" - and "xrp"."weaponSplId" = "BuildWeapon"."weaponSplId" - where "b"."id" = "BuildWeapon"."buildId" - ) - `, - ).run(); - - db.prepare(/* sql */ `drop index "idx_buildweapon_lookup"`).run(); - db.prepare( - /* sql */ `drop index "build_weapon_weapon_spl_id_build_id"`, - ).run(); - - // Canonicalize weaponSplId: alt skins collapse to their base weapon so - // the builds-by-weapon and popular/stats queries can filter with a - // single `= ?` against the covering index instead of an IN-list across - // alt skins. - db.prepare( - /* sql */ `alter table "BuildWeapon" add column "canonicalWeaponSplId" integer`, - ).run(); - - db.prepare( - /* sql */ ` - update "BuildWeapon" set "canonicalWeaponSplId" = case "weaponSplId" - when 45 then 40 - when 47 then 40 - when 46 then 41 - when 205 then 200 - when 1015 then 1010 - when 1115 then 1110 - when 2015 then 2010 - when 3005 then 3000 - when 4015 then 4010 - when 5015 then 5010 - when 6005 then 6000 - when 7015 then 7010 - when 8005 then 8000 - else "weaponSplId" - end - `, - ).run(); - - // Collapse alt-skin duplicates within a build down to one row per - // canonical weapon. Prefer the base weapon (weaponSplId = canonical), - // falling back to the lowest weaponSplId when only alts are present. - db.prepare( - /* sql */ ` - delete from "BuildWeapon" where rowid in ( - select rowid from ( - select rowid, - row_number() over ( - partition by "buildId", "canonicalWeaponSplId" - order by ("weaponSplId" = "canonicalWeaponSplId") desc, "weaponSplId" asc - ) as rn - from "BuildWeapon" - ) where rn > 1 - ) - `, - ).run(); - - db.prepare( - /* sql */ `create unique index build_weapon_canonical_unique on "BuildWeapon"("buildId", "canonicalWeaponSplId")`, - ).run(); - - // `updatedAt desc` matches the query's ORDER BY direction so the index - // also covers the secondary sort — no temp B-tree. - db.prepare( - /* sql */ `create index build_weapon_lookup on "BuildWeapon"("canonicalWeaponSplId", "sortValue", "updatedAt" desc, "buildId")`, - ).run(); - - // Drop dead schema: `BuildAbility` is fully replaced by `Build.abilities` - // (JSON), `BuildAbilitySum` and `BuildWeaponAbility`. `BuildWeapon`'s - // `isTop500` / `tier` are folded into `Build.sortValue` / `BuildWeapon.sortValue`. - db.prepare(/* sql */ `drop table "BuildAbility"`).run(); - db.prepare( - /* sql */ `alter table "BuildWeapon" drop column "isTop500"`, - ).run(); - db.prepare(/* sql */ `alter table "BuildWeapon" drop column "tier"`).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/143-match-profile-rename.js b/migrations/143-match-profile-rename.js deleted file mode 100644 index c7b41d150..000000000 --- a/migrations/143-match-profile-rename.js +++ /dev/null @@ -1,5 +0,0 @@ -export function up(db) { - db.prepare( - /* sql */ `alter table "User" rename column "qWeaponPool" to "weaponPool"`, - ).run(); -} diff --git a/migrations/144-scrim-map-by-map.js b/migrations/144-scrim-map-by-map.js deleted file mode 100644 index 19982beca..000000000 --- a/migrations/144-scrim-map-by-map.js +++ /dev/null @@ -1,44 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "ScrimMapList" ( - "id" integer primary key autoincrement, - "scrimPostId" integer not null, - "side" text not null check ("side" in ('ALPHA','BRAVO')), - "source" text not null check ("source" in ('TOURNAMENT','POOL')), - "tournamentId" integer, - "serializedPool" text, - "updatedAt" integer not null, - foreign key ("scrimPostId") references "ScrimPost"("id") on delete cascade, - foreign key ("tournamentId") references "Tournament"("id"), - unique("scrimPostId", "side") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "ScrimMap" ( - "id" integer primary key autoincrement, - "scrimPostId" integer not null, - "index" integer not null, - "mode" text not null, - "stageId" integer not null, - "winnerSide" text check ("winnerSide" in ('ALPHA','BRAVO')), - "reportedAt" integer, - "reportedByUserId" integer, - foreign key ("scrimPostId") references "ScrimPost"("id") on delete cascade, - foreign key ("reportedByUserId") references "User"("id"), - unique("scrimPostId", "index") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index scrim_map_scrim_post_id_index_idx on "ScrimMap"("scrimPostId", "index")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/145-user-weapon-pool-table.js b/migrations/145-user-weapon-pool-table.js deleted file mode 100644 index 28be1772b..000000000 --- a/migrations/145-user-weapon-pool-table.js +++ /dev/null @@ -1,56 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "UserWeaponPool" ( - "userId" integer not null, - "sortOrder" integer not null, - "weaponSplId" integer not null, - "isFavorite" integer not null default 0, - foreign key ("userId") references "User"("id") on delete cascade, - primary key ("userId", "sortOrder") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "UserWeaponPool" ("userId", "sortOrder", "weaponSplId", "isFavorite") - select - u."id", - je."key", - json_extract(je."value", '$.weaponSplId'), - coalesce(json_extract(je."value", '$.isFavorite'), 0) - from "User" u, json_each(u."weaponPool") je - where u."weaponPool" is not null - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "TenStarWeapon" ( - "userId" integer not null, - "weaponSplId" integer not null, - foreign key ("userId") references "User"("id") on delete cascade, - primary key ("userId", "weaponSplId") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "TenStarWeapon" ("userId", "weaponSplId") - select distinct sp."userId", xrp."weaponSplId" - from "XRankPlacement" xrp - inner join "SplatoonPlayer" sp on sp."id" = xrp."playerId" - where sp."userId" is not null - and ( - xrp."region" = 'JPN' - or (xrp."region" = 'WEST' and xrp."rank" <= 100) - ) - `, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/146-leaderboard-indexes.js b/migrations/146-leaderboard-indexes.js deleted file mode 100644 index ff1c55815..000000000 --- a/migrations/146-leaderboard-indexes.js +++ /dev/null @@ -1,23 +0,0 @@ -export function up(db) { - db.transaction(() => { - // Covering index for season-scoped per-user Skill aggregates: the user SP - // leaderboard's latest-skill-per-user group-by and the SQ match count - // (groupMatchId included so neither needs rowid lookups). - db.prepare( - /* sql */ `create index skill_season_user_id_group_match_id on "Skill"("season", "userId", "groupMatchId")`, - ).run(); - - // Covering index for the team leaderboard's latest-skill-per-identifier - // group-by (previously filtered via skill_season + temp B-tree). - db.prepare( - /* sql */ `create index skill_season_identifier on "Skill"("season", "identifier")`, - ).run(); - - // Covering index for the XP leaderboards' max(power) per player group-by; - // mode/weaponSplId/name included so the all/mode/weapon variants are all - // answered without touching the table. - db.prepare( - /* sql */ `create index xrank_placement_player_power on "XRankPlacement"("playerId", "power", "mode", "weaponSplId", "name")`, - ).run(); - })(); -} diff --git a/migrations/147-badge-owner-badge-id-index.js b/migrations/147-badge-owner-badge-id-index.js deleted file mode 100644 index 81c9e303b..000000000 --- a/migrations/147-badge-owner-badge-id-index.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.transaction(() => { - // Lets badge page owner listings (BadgeOwner view filtered by badgeId) - // search instead of scanning the whole table. - db.prepare( - /* sql */ `create index tournament_badge_owner_badge_id on "TournamentBadgeOwner"("badgeId")`, - ).run(); - })(); -} diff --git a/migrations/148-user-search-fts.js b/migrations/148-user-search-fts.js deleted file mode 100644 index 8b7603dcc..000000000 --- a/migrations/148-user-search-fts.js +++ /dev/null @@ -1,50 +0,0 @@ -export function up(db) { - db.transaction(() => { - // trigram-tokenized full text search index over the columns user search - // matches against, so substring (LIKE '%query%') searches can use an - // index instead of scanning the whole User table. - // external content table: rows are not stored twice, the index reads - // from User and is kept in sync by the triggers below. - db.prepare( - /* sql */ `create virtual table "UserSearch" using fts5( - "username", - "inGameName", - "discordUniqueName", - "customUrl", - content='User', - content_rowid='id', - tokenize='trigram' - )`, - ).run(); - - db.prepare( - /* sql */ `insert into "UserSearch"("UserSearch") values ('rebuild')`, - ).run(); - - db.prepare( - /* sql */ `create trigger "user_search_after_insert" after insert on "User" begin - insert into "UserSearch"(rowid, "username", "inGameName", "discordUniqueName", "customUrl") - values (new."id", new."username", new."inGameName", new."discordUniqueName", new."customUrl"); - end`, - ).run(); - - db.prepare( - /* sql */ `create trigger "user_search_after_delete" after delete on "User" begin - insert into "UserSearch"("UserSearch", rowid, "username", "inGameName", "discordUniqueName", "customUrl") - values ('delete', old."id", old."username", old."inGameName", old."discordUniqueName", old."customUrl"); - end`, - ).run(); - - // "username" is a generated column (coalesce of customName/discordName) - // and generated columns can not be listed in "update of", so the - // trigger watches its source columns instead - db.prepare( - /* sql */ `create trigger "user_search_after_update" after update of "customName", "discordName", "inGameName", "discordUniqueName", "customUrl" on "User" begin - insert into "UserSearch"("UserSearch", rowid, "username", "inGameName", "discordUniqueName", "customUrl") - values ('delete', old."id", old."username", old."inGameName", old."discordUniqueName", old."customUrl"); - insert into "UserSearch"(rowid, "username", "inGameName", "discordUniqueName", "customUrl") - values (new."id", new."username", new."inGameName", new."discordUniqueName", new."customUrl"); - end`, - ).run(); - })(); -} diff --git a/migrations/149-tournament-audit-log.js b/migrations/149-tournament-audit-log.js deleted file mode 100644 index b7b5b0a80..000000000 --- a/migrations/149-tournament-audit-log.js +++ /dev/null @@ -1,52 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "TournamentTeamHistory" ( - "id" integer primary key autoincrement, - "tournamentTeamId" integer not null, - "tournamentId" integer not null, - "name" text not null, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "TournamentAuditLog" ( - "id" integer primary key autoincrement, - "tournamentId" integer not null, - "type" text not null, - "actorUserId" integer not null, - "subjectUserId" integer, - "tournamentTeamHistoryId" integer, - "metadata" text, - "createdAt" integer not null, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - foreign key ("actorUserId") references "User"("id"), - foreign key ("subjectUserId") references "User"("id"), - foreign key ("tournamentTeamHistoryId") references "TournamentTeamHistory"("id") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentTeam" add column "tournamentTeamHistoryId" integer references "TournamentTeamHistory"("id")`, - ).run(); - - db.prepare( - /* sql */ `create index tournament_audit_log_tournament_id_created_at_idx on "TournamentAuditLog"("tournamentId", "createdAt")`, - ).run(); - - db.prepare( - /* sql */ `create index tournament_audit_log_tournament_id_team_history_id_type_created_at_idx on "TournamentAuditLog"("tournamentId", "tournamentTeamHistoryId", "type", "createdAt")`, - ).run(); - - db.prepare( - /* sql */ `create index tournament_team_history_tournament_id_idx on "TournamentTeamHistory"("tournamentId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/150-team-member-custom-roles.js b/migrations/150-team-member-custom-roles.js deleted file mode 100644 index 7e706bb3c..000000000 --- a/migrations/150-team-member-custom-roles.js +++ /dev/null @@ -1,29 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "AllTeamMember" add "customRole" text`, - ).run(); - db.prepare( - /* sql */ `alter table "AllTeamMember" add "roleType" text`, - ).run(); - db.prepare( - /* sql */ `alter table "AllTeamMember" add "order" integer not null default 0`, - ).run(); - db.prepare( - /* sql */ `update "AllTeamMember" - set "order" = sub.rn - from ( - select - "userId", - "teamId", - row_number() over ( - partition by "teamId" - order by "isOwner" desc, "createdAt" asc, "userId" asc - ) - 1 as rn - from "AllTeamMember" - ) as sub - where "AllTeamMember"."userId" = sub."userId" - and "AllTeamMember"."teamId" = sub."teamId"`, - ).run(); - })(); -} diff --git a/migrations/151-user-custom-avatar.js b/migrations/151-user-custom-avatar.js deleted file mode 100644 index 2889c8a0a..000000000 --- a/migrations/151-user-custom-avatar.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ `alter table "User" add "customAvatarImgId" integer`, - ).run(); - })(); -} diff --git a/migrations/152-external-stream.js b/migrations/152-external-stream.js deleted file mode 100644 index 6c5c7ee5f..000000000 --- a/migrations/152-external-stream.js +++ /dev/null @@ -1,19 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "ExternalStream" ( - "id" integer primary key autoincrement, - "name" text not null, - "url" text not null, - "avatarImgId" integer, - "startTime" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("avatarImgId") references "UnvalidatedUserSubmittedImage"("id") on delete set null - ) strict - `, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/153-match-page-simplification.js b/migrations/153-match-page-simplification.js deleted file mode 100644 index 71740b263..000000000 --- a/migrations/153-match-page-simplification.js +++ /dev/null @@ -1,9 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `drop table if exists "RoomLink"`).run(); - - db.prepare(/* sql */ `alter table "User" drop column "noSplatnet"`).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/154-user-card-fields.js b/migrations/154-user-card-fields.js deleted file mode 100644 index 997992569..000000000 --- a/migrations/154-user-card-fields.js +++ /dev/null @@ -1,92 +0,0 @@ -export function up(db) { - db.pragma("foreign_keys = OFF"); - - db.transaction(() => { - db.prepare(`alter table "User" drop column "lastSubMessage"`).run(); - db.prepare(/* sql */ `alter table "User" add "shortBio" text`).run(); - db.prepare(/* sql */ `alter table "User" add "div" text`).run(); - db.prepare( - /* sql */ `alter table "User" add "unverifiedPeakXP" text`, - ).run(); - // nullable: null means no explicit choice, the card derives a preset color from the user id - db.prepare(/* sql */ `alter table "User" add "bannerPresetImg" text`).run(); - // supporter-uploaded banner (UserSubmittedImage id), takes precedence over bannerPresetImg - db.prepare(/* sql */ `alter table "User" add "bannerImgId" integer`).run(); - // json array of card stat types the user has chosen to hide - db.prepare(/* sql */ `alter table "User" add "hiddenCardStats" text`).run(); - - // backfill unverifiedPeakXP from the existing "peak-xp-unverified" profile widget - db.prepare( - /* sql */ ` - update "User" - set "unverifiedPeakXP" = ( - select json_object( - 'overall', json_extract(uw."widget", '$.settings.peakXp'), - 'tentatek', iif(json_extract(uw."widget", '$.settings.division') = 'tentatek', json_extract(uw."widget", '$.settings.peakXp'), null), - 'takoroka', iif(json_extract(uw."widget", '$.settings.division') = 'takoroka', json_extract(uw."widget", '$.settings.peakXp'), null) - ) - from "UserWidget" uw - where uw."userId" = "User"."id" - and json_extract(uw."widget", '$.id') = 'peak-xp-unverified' - limit 1 - ) - where exists ( - select 1 from "UserWidget" uw - where uw."userId" = "User"."id" - and json_extract(uw."widget", '$.id') = 'peak-xp-unverified' - ) - `, - ).run(); - - // rebuild SplatoonPlayer to change peakXp from a scalar (real) into the - // denormalized PeakXP json shape. per-division peaks are resolved from XRankPlacement - // (region 'WEST' = tentatek, otherwise takoroka), matching refreshAllPeakXp. - db.prepare( - /* sql */ ` - create table "SplatoonPlayer_new" ( - "id" integer primary key, - "userId" integer unique, - "splId" text unique not null, - "peakXp" text, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "SplatoonPlayer_new" ("id", "userId", "splId", "peakXp") - select - "id", - "userId", - "splId", - iif("peakXp" is null, null, json_object( - 'overall', "peakXp", - 'takoroka', ( - select max("XRankPlacement"."power") from "XRankPlacement" - where "XRankPlacement"."playerId" = "SplatoonPlayer"."id" - and "XRankPlacement"."region" <> 'WEST' - ), - 'tentatek', ( - select max("XRankPlacement"."power") from "XRankPlacement" - where "XRankPlacement"."playerId" = "SplatoonPlayer"."id" - and "XRankPlacement"."region" = 'WEST' - ) - )) - from "SplatoonPlayer" - `, - ).run(); - - db.prepare(/* sql */ `drop table "SplatoonPlayer"`).run(); - db.prepare( - /* sql */ `alter table "SplatoonPlayer_new" rename to "SplatoonPlayer"`, - ).run(); - db.prepare( - /* sql */ `create index splatoon_player_user_id on "SplatoonPlayer"("userId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); - - db.pragma("foreign_keys = ON"); -} diff --git a/migrations/155-tournament-team-member-is-sub.js b/migrations/155-tournament-team-member-is-sub.js deleted file mode 100644 index 9c9fe695c..000000000 --- a/migrations/155-tournament-team-member-is-sub.js +++ /dev/null @@ -1,31 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ `alter table "TournamentTeamMember" add column "isSub" integer not null default 0`, - ).run(); - - // backfill from the previous time-based detection: a member registered after - // the tournament's registration closed (organizer-set regClosesAt, otherwise - // the tournament start time) is considered a sub - db.prepare( - /*sql*/ ` - update "TournamentTeamMember" - set "isSub" = 1 - where "createdAt" > ( - select coalesce( - "Tournament"."settings" ->> 'regClosesAt', - min("CalendarEventDate"."startTime") - ) - from "TournamentTeam" - inner join "Tournament" - on "Tournament"."id" = "TournamentTeam"."tournamentId" - inner join "CalendarEvent" - on "CalendarEvent"."tournamentId" = "Tournament"."id" - inner join "CalendarEventDate" - on "CalendarEventDate"."eventId" = "CalendarEvent"."id" - where "TournamentTeam"."id" = "TournamentTeamMember"."tournamentTeamId" - ) - `, - ).run(); - })(); -} diff --git a/migrations/156-db-perf-indexes.js b/migrations/156-db-perf-indexes.js deleted file mode 100644 index 011743e5a..000000000 --- a/migrations/156-db-perf-indexes.js +++ /dev/null @@ -1,60 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - `create index all_team_avatar_img_id on "AllTeam"("avatarImgId")`, - ).run(); - db.prepare( - `create index all_team_banner_img_id on "AllTeam"("bannerImgId")`, - ).run(); - db.prepare( - `create index calendar_event_avatar_img_id on "CalendarEvent"("avatarImgId")`, - ).run(); - // votedId/tier/score included so the PlusVotingResult view's group by can - // follow index order over a voting's ~35k rows instead of a temp b-tree - db.prepare( - `create index plus_vote_year_month on "PlusVote"("year", "month", "votedId", "tier", "score")`, - ).run(); - db.prepare( - `create index reported_weapon_tournament_created_at on "ReportedWeapon"("createdAt", "userId", "weaponSplId", "tournamentMatchId") where "tournamentMatchId" is not null`, - ).run(); - db.prepare( - `create index reported_weapon_group_match_user_weapon on "ReportedWeapon"("groupMatchId", "userId", "weaponSplId")`, - ).run(); - // widened versions of migration 146's Skill indexes: ordinal + matchesCount - // included so the leaderboards' latest-skill-per-group queries are answered - // without rowid lookups (the bare-column max(id) form) - db.prepare("drop index skill_season_identifier").run(); - db.prepare( - `create index skill_season_identifier_leaderboard on "Skill"("season", "identifier", "ordinal", "matchesCount")`, - ).run(); - db.prepare("drop index skill_season_user_id_group_match_id").run(); - db.prepare( - `create index skill_season_user_id_leaderboard on "Skill"("season", "userId", "groupMatchId", "ordinal", "matchesCount")`, - ).run(); - // power-descending indexes let the XP leaderboards walk placements from - // the top and stop at the 500th distinct player instead of aggregating - // every player's max power first - db.prepare( - `create index xrank_placement_power on "XRankPlacement"("power" desc)`, - ).run(); - db.prepare( - `create index xrank_placement_mode_power on "XRankPlacement"("mode", "power" desc)`, - ).run(); - db.prepare( - `create index xrank_placement_weapon_power on "XRankPlacement"("weaponSplId", "power" desc)`, - ).run(); - db.prepare( - `create index calendar_event_result_team_event_id on "CalendarEventResultTeam"("eventId")`, - ).run(); - // covering partial index so map/mode preference aggregation doesn't scan - // the full (wide-row) User table - db.prepare( - `create index user_map_mode_preferences on "User"("id", "mapModePreferences") where "mapModePreferences" is not null`, - ).run(); - // only ~20 of the hundreds of thousands of Group rows are not INACTIVE - db.prepare( - `create index group_status_active on "Group"("status") where "status" != 'INACTIVE'`, - ).run(); - db.prepare(`create index art_created_at on "Art"("createdAt" desc)`).run(); - })(); -} diff --git a/migrations/157-user-report.js b/migrations/157-user-report.js deleted file mode 100644 index 4975c7040..000000000 --- a/migrations/157-user-report.js +++ /dev/null @@ -1,25 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "UserReport" ( - "id" integer primary key autoincrement, - "reportedUserId" integer not null, - "reporterUserId" integer not null, - "category" text not null, - "description" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("reportedUserId") references "User"("id") on delete cascade, - foreign key ("reporterUserId") references "User"("id") on delete cascade, - unique ("reportedUserId", "reporterUserId") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index user_report_reported_user_id_idx on "UserReport"("reportedUserId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/158-user-report-match-id.js b/migrations/158-user-report-match-id.js deleted file mode 100644 index 2dbc2a82f..000000000 --- a/migrations/158-user-report-match-id.js +++ /dev/null @@ -1,13 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - alter table "UserReport" - add column "matchId" integer - references "GroupMatch"("id") on delete set null - `, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/159-group-match-no-screen.js b/migrations/159-group-match-no-screen.js deleted file mode 100644 index aab7d7d06..000000000 --- a/migrations/159-group-match-no-screen.js +++ /dev/null @@ -1,12 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - alter table "GroupMatch" - add column "noScreen" integer default 0 not null - `, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/160-strip-youtube-id-url-params.js b/migrations/160-strip-youtube-id-url-params.js deleted file mode 100644 index c8169b5d3..000000000 --- a/migrations/160-strip-youtube-id-url-params.js +++ /dev/null @@ -1,13 +0,0 @@ -export function up(db) { - db.transaction(() => { - for (const delimiter of ["?", "&", "#"]) { - db.prepare( - /* sql */ ` - update "UnvalidatedVideo" - set "youtubeId" = substr("youtubeId", 1, instr("youtubeId", ?) - 1) - where instr("youtubeId", ?) > 0 - `, - ).run(delimiter, delimiter); - } - })(); -} diff --git a/migrations/161-tournament-match-nullable-opponents.js b/migrations/161-tournament-match-nullable-opponents.js deleted file mode 100644 index 204b3e7ba..000000000 --- a/migrations/161-tournament-match-nullable-opponents.js +++ /dev/null @@ -1,107 +0,0 @@ -export function up(db) { - db.pragma("foreign_keys = OFF"); - - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "TournamentMatch_new" ( - "id" integer primary key, - "roundId" integer not null, - "stageId" integer not null, - "groupId" integer not null, - "number" integer not null, - "opponentOne" text, - "opponentTwo" text, - "winnerSide" text check ("winnerSide" in ('opponent1','opponent2')), - "chatCode" text, - "startedAt" integer, - foreign key ("roundId") references "TournamentRound"("id") on delete cascade, - foreign key ("stageId") references "TournamentStage"("id") on delete cascade, - foreign key ("groupId") references "TournamentGroup"("id") on delete cascade, - unique("number", "roundId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "TournamentMatch_new" ("id", "roundId", "stageId", "groupId", "number", "opponentOne", "opponentTwo", "winnerSide", "chatCode", "startedAt") - select - "id", - "roundId", - "stageId", - "groupId", - "number", - case when "opponentOne" = 'null' then null else json_remove("opponentOne", '$.result', '$.forfeit', '$.totalPoints', '$.totalKos') end, - case when "opponentTwo" = 'null' then null else json_remove("opponentTwo", '$.result', '$.forfeit', '$.totalPoints', '$.totalKos') end, - case - when "opponentOne" ->> '$.result' = 'win' then 'opponent1' - when "opponentTwo" ->> '$.result' = 'win' then 'opponent2' - end, - "chatCode", - "startedAt" - from "TournamentMatch" - `, - ).run(); - - db.prepare(/* sql */ `drop table "TournamentMatch"`).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatch_new" rename to "TournamentMatch"`, - ).run(); - - db.prepare( - /* sql */ `create index tournament_match_round_id on "TournamentMatch"("roundId")`, - ).run(); - db.prepare( - /* sql */ `create index tournament_match_stage_id on "TournamentMatch"("stageId")`, - ).run(); - db.prepare( - /* sql */ `create index tournament_match_group_id on "TournamentMatch"("groupId")`, - ).run(); - db.prepare( - /* sql */ `create index idx_tournament_match_opponent_one_id on "TournamentMatch"("opponentOne" ->> '$.id')`, - ).run(); - db.prepare( - /* sql */ `create index idx_tournament_match_opponent_two_id on "TournamentMatch"("opponentTwo" ->> '$.id')`, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatchGameResult" add "ko" integer`, - ).run(); - - db.prepare( - /* sql */ ` - update "TournamentMatchGameResult" - set "ko" = 1 - where ("opponentOnePoints" = 100 and "opponentTwoPoints" = 0) - or ("opponentOnePoints" = 0 and "opponentTwoPoints" = 100) - `, - ).run(); - - db.prepare( - /* sql */ `alter table "TournamentMatchGameResult" drop column "opponentOnePoints"`, - ).run(); - db.prepare( - /* sql */ `alter table "TournamentMatchGameResult" drop column "opponentTwoPoints"`, - ).run(); - - db.prepare( - /* sql */ ` - update "TournamentStage" - set "settings" = json_patch( - json_remove("settings", '$.swiss'), - json_object( - 'groupCount', "settings" ->> '$.swiss.groupCount', - 'roundCount', "settings" ->> '$.swiss.roundCount' - ) - ) - where "settings" ->> '$.swiss' is not null - `, - ).run(); - - db.pragma("foreign_key_check"); - })(); - - db.pragma("foreign_keys = ON"); -} diff --git a/migrations/162-boolean-columns-not-null.js b/migrations/162-boolean-columns-not-null.js deleted file mode 100644 index b096050c4..000000000 --- a/migrations/162-boolean-columns-not-null.js +++ /dev/null @@ -1,213 +0,0 @@ -const NULLABLE_BOOLEAN_COLUMNS = [ - { table: "GroupLike", column: "isRechallenge" }, - { table: "User", column: "isArtist" }, - { table: "User", column: "isVideoAdder" }, - { table: "User", column: "isTournamentOrganizer" }, - { table: "User", column: "isApiAccesser" }, - { table: "User", column: "commissionsOpen" }, -]; - -const COMMA_SEPARATED_STRING_COLUMNS = [ - { table: "CalendarEvent", column: "tags" }, - { table: "User", column: "languages" }, - { table: "LFGPost", column: "languages" }, -]; - -const COMMA_SEPARATED_NUMBER_COLUMNS = [ - { table: "TournamentSub", column: "okWeapons" }, -]; - -const RENAMED_TIMESTAMP_COLUMNS = [ - { table: "CalendarEventDate", from: "startTime", to: "startsAt" }, - { table: "ExternalStream", from: "startTime", to: "startsAt" }, - { table: "SplatoonRotation", from: "startTime", to: "startsAt" }, - { table: "SplatoonRotation", from: "endTime", to: "endsAt" }, - { table: "ScrimPost", from: "at", to: "startsAt" }, - { table: "ScrimPost", from: "rangeEnd", to: "rangeEndsAt" }, - { table: "ScrimPostRequest", from: "at", to: "startsAt" }, - { table: "PlusVote", from: "validAfter", to: "becomesValidAt" }, - { table: "UnvalidatedVideo", from: "youtubeDate", to: "youtubePublishedAt" }, - { table: "User", from: "patronSince", to: "patronStartedAt" }, - { table: "User", from: "patronTill", to: "patronExpiresAt" }, -]; - -export function up(db) { - db.pragma("foreign_keys = OFF"); - - db.transaction(() => { - db.prepare( - /*sql*/ `alter table "Build" add column "isPrivate" integer not null default 0`, - ).run(); - - db.prepare( - /*sql*/ `update "Build" set "isPrivate" = coalesce("private", 0)`, - ).run(); - - db.prepare(/*sql*/ `alter table "Build" drop column "private"`).run(); - - for (const { table, column } of NULLABLE_BOOLEAN_COLUMNS) { - db.prepare( - /*sql*/ `alter table "${table}" add column "${column}_new" integer not null default 0`, - ).run(); - - db.prepare( - /*sql*/ `update "${table}" set "${column}_new" = coalesce("${column}", 0)`, - ).run(); - - db.prepare( - /*sql*/ `alter table "${table}" drop column "${column}"`, - ).run(); - - db.prepare( - /*sql*/ `alter table "${table}" rename column "${column}_new" to "${column}"`, - ).run(); - } - - for (const { table, from, to } of RENAMED_TIMESTAMP_COLUMNS) { - db.prepare( - /*sql*/ `alter table "${table}" rename column "${from}" to "${to}"`, - ).run(); - } - - for (const { table, column } of COMMA_SEPARATED_STRING_COLUMNS) { - db.prepare( - /*sql*/ `update "${table}" set "${column}" = null where "${column}" = ''`, - ).run(); - - db.prepare( - /*sql*/ ` - update "${table}" - set "${column}" = '["' || replace("${column}", ',', '","') || '"]' - where "${column}" is not null - `, - ).run(); - } - - for (const { table, column } of COMMA_SEPARATED_NUMBER_COLUMNS) { - db.prepare( - /*sql*/ `update "${table}" set "${column}" = null where "${column}" = ''`, - ).run(); - - db.prepare( - /*sql*/ ` - update "${table}" - set "${column}" = '[' || "${column}" || ']' - where "${column}" is not null - `, - ).run(); - } - - db.prepare( - /*sql*/ ` - update "TournamentSub" - set "bestWeapons" = iif("bestWeapons" = '', '[]', '[' || "bestWeapons" || ']') - `, - ).run(); - - db.prepare( - /*sql*/ "drop index calendar_event_date_event_id_start_time", - ).run(); - db.prepare( - /*sql*/ `create index calendar_event_date_event_id_starts_at on "CalendarEventDate"("eventId", "startsAt" desc)`, - ).run(); - - db.prepare(/*sql*/ "drop index scrim_post_at").run(); - db.prepare( - /*sql*/ `create index scrim_post_starts_at on "ScrimPost"("startsAt")`, - ).run(); - - db.prepare( - /* sql */ ` - create table "TournamentAuditLog_new" ( - "id" integer primary key autoincrement, - "tournamentId" integer not null, - "type" text not null, - "actorUserId" integer not null, - "subjectUserId" integer, - "tournamentTeamHistoryId" integer, - "metadata" text, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - foreign key ("actorUserId") references "User"("id"), - foreign key ("subjectUserId") references "User"("id"), - foreign key ("tournamentTeamHistoryId") references "TournamentTeamHistory"("id") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "TournamentAuditLog_new" ("id", "tournamentId", "type", "actorUserId", "subjectUserId", "tournamentTeamHistoryId", "metadata", "createdAt") - select "id", "tournamentId", "type", "actorUserId", "subjectUserId", "tournamentTeamHistoryId", "metadata", "createdAt" - from "TournamentAuditLog" - `, - ).run(); - - db.prepare(/* sql */ `drop table "TournamentAuditLog"`).run(); - - db.prepare( - /* sql */ `alter table "TournamentAuditLog_new" rename to "TournamentAuditLog"`, - ).run(); - - db.prepare( - /* sql */ `create index tournament_audit_log_tournament_id_created_at_idx on "TournamentAuditLog"("tournamentId", "createdAt")`, - ).run(); - db.prepare( - /* sql */ `create index tournament_audit_log_tournament_id_team_history_id_type_created_at_idx on "TournamentAuditLog"("tournamentId", "tournamentTeamHistoryId", "type", "createdAt")`, - ).run(); - - db.prepare( - /* sql */ ` - update "TournamentStage" - set "createdAt" = coalesce( - ( - select min("CalendarEventDate"."startsAt") - from "CalendarEvent" - inner join "CalendarEventDate" on "CalendarEventDate"."eventId" = "CalendarEvent"."id" - where "CalendarEvent"."tournamentId" = "TournamentStage"."tournamentId" - ), - strftime('%s', 'now') - ) - where "createdAt" is null - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "TournamentStage_new" ( - "id" integer primary key, - "tournamentId" integer not null, - "name" text not null, - "type" text not null, - "settings" text not null, - "number" integer not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade, - unique("number", "tournamentId") on conflict rollback - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - insert into "TournamentStage_new" ("id", "tournamentId", "name", "type", "settings", "number", "createdAt") - select "id", "tournamentId", "name", "type", "settings", "number", "createdAt" - from "TournamentStage" - `, - ).run(); - - db.prepare(/* sql */ `drop table "TournamentStage"`).run(); - - db.prepare( - /* sql */ `alter table "TournamentStage_new" rename to "TournamentStage"`, - ).run(); - - db.prepare( - /* sql */ `create index tournament_stage_tournament_id on "TournamentStage"("tournamentId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); - - db.pragma("foreign_keys = ON"); -} diff --git a/migrations/163-trophies.js b/migrations/163-trophies.js deleted file mode 100644 index 9346accea..000000000 --- a/migrations/163-trophies.js +++ /dev/null @@ -1,116 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /*sql*/ ` - create table "Trophy" ( - "id" integer primary key, - "name" text not null, - "model" text not null, - "code" text unique, - "organizationId" integer, - "creatorId" integer, - "managerId" integer, - foreign key ("organizationId") references "TournamentOrganization"("id") on delete set null, - foreign key ("creatorId") references "User"("id") on delete set null, - foreign key ("managerId") references "User"("id") on delete set null - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "TrophyOwner" ( - "trophyId" integer not null, - "userId" integer not null, - "tournamentId" integer not null, - "tier" integer, - foreign key ("trophyId") references "Trophy"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - foreign key ("tournamentId") references "Tournament"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create unique index "trophy_owner_tournament_user_unique" on "TrophyOwner"("tournamentId", "userId", "trophyId")`, - ).run(); - - db.prepare( - /*sql*/ `create index "trophy_owner_user_id" on "TrophyOwner"("userId")`, - ).run(); - - db.prepare( - /*sql*/ `create index "trophy_owner_trophy_id" on "TrophyOwner"("trophyId", "userId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "SpecialTrophyOwner" ( - "trophyId" integer not null, - "userId" integer not null, - "createdAt" integer not null, - primary key ("trophyId", "userId"), - foreign key ("trophyId") references "Trophy"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ ` - create table "PendingTrophy" ( - "id" integer primary key, - "name" text not null, - "model" text not null, - "description" text not null, - "organizationId" integer, - "submitterUserId" integer not null, - "createdAt" integer not null, - "declineReason" text, - "declinedAt" integer, - "declinedByUserId" integer, - "targetTrophyId" integer, - "managerId" integer, - foreign key ("organizationId") references "TournamentOrganization"("id") on delete set null, - foreign key ("submitterUserId") references "User"("id") on delete cascade, - foreign key ("declinedByUserId") references "User"("id") on delete set null, - foreign key ("targetTrophyId") references "Trophy"("id") on delete cascade, - foreign key ("managerId") references "User"("id") on delete set null - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `create index "pending_trophy_submitter_idx" on "PendingTrophy"("submitterUserId")`, - ).run(); - - db.prepare( - /*sql*/ ` - create table "PendingTrophyApproval" ( - "pendingTrophyId" integer not null, - "userId" integer not null, - "createdAt" integer not null, - foreign key ("pendingTrophyId") references "PendingTrophy"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique("pendingTrophyId", "userId") - ) strict - `, - ).run(); - - db.prepare( - /*sql*/ `alter table "CalendarEvent" add column "trophyId" integer references "Trophy"("id") on delete set null`, - ).run(); - - db.prepare( - /*sql*/ `create index "calendar_event_trophy_id" on "CalendarEvent"("trophyId")`, - ).run(); - - db.prepare( - /*sql*/ `alter table "User" add column "favoriteTrophyIds" text`, - ).run(); - - db.prepare( - /*sql*/ `alter table "User" add column "hiddenTrophyIds" text`, - ).run(); - })(); -} diff --git a/migrations/164-drop-tournament-sub.js b/migrations/164-drop-tournament-sub.js deleted file mode 100644 index c573af4b0..000000000 --- a/migrations/164-drop-tournament-sub.js +++ /dev/null @@ -1,7 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare(/* sql */ `drop table if exists "TournamentSub"`).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/165-group-match-cancel-report.js b/migrations/165-group-match-cancel-report.js deleted file mode 100644 index a20a2fa28..000000000 --- a/migrations/165-group-match-cancel-report.js +++ /dev/null @@ -1,38 +0,0 @@ -export function up(db) { - db.transaction(() => { - db.prepare( - /* sql */ ` - create table "GroupMatchCancelReport" ( - "id" integer primary key autoincrement, - "groupMatchId" integer not null, - "groupId" integer not null, - "authorUserId" integer not null, - "reason" text not null, - "createdAt" integer default (strftime('%s', 'now')) not null, - foreign key ("groupMatchId") references "GroupMatch"("id") on delete cascade, - foreign key ("groupId") references "Group"("id") on delete cascade, - foreign key ("authorUserId") references "User"("id") on delete cascade, - unique ("groupMatchId", "groupId") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ ` - create table "GroupMatchCancelReportPlayer" ( - "cancelReportId" integer not null, - "userId" integer not null, - foreign key ("cancelReportId") references "GroupMatchCancelReport"("id") on delete cascade, - foreign key ("userId") references "User"("id") on delete cascade, - unique ("cancelReportId", "userId") - ) strict - `, - ).run(); - - db.prepare( - /* sql */ `create index group_match_cancel_report_player_user_id_idx on "GroupMatchCancelReportPlayer"("userId")`, - ).run(); - - db.pragma("foreign_key_check"); - })(); -} diff --git a/migrations/20260803000000-initial.sql b/migrations/20260803000000-initial.sql new file mode 100644 index 000000000..6e33a6023 --- /dev/null +++ b/migrations/20260803000000-initial.sql @@ -0,0 +1,1791 @@ +create table "User" ( + "id" integer primary key, + "discordId" text unique not null, + "discordName" text not null, + "discordAvatar" text, + "twitch" text, + "youtubeId" text, + "bio" text, + "country" text, + "patronTier" integer, + "patronStartedAt" integer, + "customUrl" text, + "stickSens" integer, + "motionSens" integer, + "inGameName" text, + "patronExpiresAt" integer, + "discordUniqueName" text, + "showDiscordUniqueName" integer not null default 1, + "commissionText" text, + "banned" integer default 0, + "vc" text default "NO", + "languages" text, + "plusSkippedForSeasonNth" integer, + "mapModePreferences" text, + "weaponPool" text, + "noScreen" integer default 0, + "bannedReason" text, + "customName" text, + "username" text generated always as (coalesce("customName", "discordName")) virtual, + "battlefy" text, + "buildSorting" text, + "bsky" text, + "preferences" text, + "favoriteBadgeIds" text, + "createdAt" integer, + "commissionsOpenedAt" integer, + "pronouns" text default null, + "customTheme" text default null, + "joinOrder" integer, + "customAvatarImgId" integer, + "shortBio" text, + "div" text, + "unverifiedPeakXP" text, + "bannerPresetImg" text, + "bannerImgId" integer, + "hiddenCardStats" text, + "isArtist" integer not null default 0, + "isVideoAdder" integer not null default 0, + "isTournamentOrganizer" integer not null default 0, + "isApiAccesser" integer not null default 0, + "commissionsOpen" integer not null default 0, + "favoriteTrophyIds" text, + "hiddenTrophyIds" text +) strict; +--> statement-breakpoint +create table "PlusSuggestion" ( + "id" integer primary key, + "text" text not null, + "authorId" integer not null, + "suggestedId" integer not null, + "month" integer not null, + "year" integer not null, + "tier" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "updatedAt" integer, + foreign key ("authorId") references "User" ("id") on delete cascade, + foreign key ("suggestedId") references "User" ("id") on delete cascade, + unique ( + "month", + "year", + "suggestedId", + "authorId", + "tier" + ) + on conflict rollback +) strict; +--> statement-breakpoint +create index plus_suggestion_author_id on "PlusSuggestion" ("authorId"); +--> statement-breakpoint +create index plus_suggestion_suggested_id on "PlusSuggestion" ("suggestedId"); +--> statement-breakpoint +create table "PlusVote" ( + "month" integer not null, + "year" integer not null, + "tier" integer not null, + "authorId" integer not null, + "votedId" integer not null, + "score" integer not null, + "becomesValidAt" integer not null, + foreign key ("authorId") references "User" ("id") on delete cascade, + foreign key ("votedId") references "User" ("id") on delete cascade, + unique ("month", "year", "authorId", "votedId") + on conflict rollback +) strict; +--> statement-breakpoint +create index plus_vote_author_id on "PlusVote" ("authorId"); +--> statement-breakpoint +create index plus_vote_voted_id on "PlusVote" ("votedId"); +--> statement-breakpoint +create table "Badge" ( + "id" integer primary key, + "code" text not null, + "displayName" text not null, + "hue" integer, + "authorId" integer +) strict; +--> statement-breakpoint +create table "TournamentBadgeOwner" ( + "badgeId" integer not null, + "userId" integer not null, + "tournamentId" integer, + "count" integer not null default 1 +) strict; +--> statement-breakpoint +create table "BadgeManager" ( + "badgeId" integer not null, + "userId" integer not null, + unique ("badgeId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "CalendarEvent" ( + "id" integer primary key, + "name" text not null, + "authorId" integer not null, + "bracketUrl" text not null, + "description" text, + "discordInviteCode" text, + "discordUrl" text generated always as ('https://discord.gg/' || "discordInviteCode") virtual, + "participantCount" integer, + "tags" text, + "tournamentId" integer, + "avatarImgId" integer, + "organizationId" integer references "TournamentOrganization" ("id") on delete set null, + "hidden" integer default 0, + "trophyId" integer references "Trophy" ("id") on delete set null, + foreign key ("authorId") references "User" ("id") on delete restrict +) strict; +--> statement-breakpoint +create table "CalendarEventDate" ( + "id" integer primary key, + "eventId" integer not null, + "startsAt" integer not null, + foreign key ("eventId") references "CalendarEvent" ("id") on delete cascade +) strict; +--> statement-breakpoint +create table "CalendarEventResultTeam" ( + "id" integer primary key, + "eventId" integer not null, + "name" text not null, + "placement" integer not null, + foreign key ("eventId") references "CalendarEvent" ("id") on delete cascade +) strict; +--> statement-breakpoint +create table "CalendarEventResultPlayer" ( + "teamId" integer not null, + "userId" integer, + "name" text, + foreign key ("teamId") references "CalendarEventResultTeam" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete restrict +) strict; +--> statement-breakpoint +create table "CalendarEventBadge" ( + "eventId" integer not null, + "badgeId" integer not null, + foreign key ("eventId") references "CalendarEvent" ("id") on delete cascade, + foreign key ("badgeId") references "Badge" ("id") on delete restrict, + unique ("eventId", "badgeId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "BuildWeapon" ( + "buildId" integer not null, + "weaponSplId" integer not null, + "updatedAt" integer default 1760608251, + "sortValue" integer, + "canonicalWeaponSplId" integer, + foreign key ("buildId") references "Build" ("id") on delete cascade, + unique ("buildId", "weaponSplId") + on conflict rollback +) strict; +--> statement-breakpoint +create index build_weapon_build_id on "BuildWeapon" ("buildId"); +--> statement-breakpoint +create unique index user_custom_url_unique on "User" ("customUrl"); +--> statement-breakpoint +create table "MapPoolMap" ( + "calendarEventId" integer, + "stageId" integer not null, + "mode" text not null, + "tournamentTeamId" integer, + "tieBreakerCalendarEventId" integer, + foreign key ("calendarEventId") references "CalendarEvent" ("id") on delete cascade, + unique ("calendarEventId", "stageId", "mode") + on conflict rollback +) strict; +--> statement-breakpoint +create index map_pool_map_calendar_event_id on "MapPoolMap" ("calendarEventId"); +--> statement-breakpoint +create table "UserResultHighlight" ( + "teamId" integer not null, + "userId" integer not null, + foreign key ("teamId") references "CalendarEventResultTeam" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("teamId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create index user_result_highlight_user_id on "UserResultHighlight" ("userId"); +--> statement-breakpoint +create index user_result_highlight_team_id on "UserResultHighlight" ("teamId"); +--> statement-breakpoint +create index map_pool_map_tournament_team_id on "MapPoolMap" ("tournamentTeamId"); +--> statement-breakpoint +create index map_pool_map_tie_breaker_calendar_event_id on "MapPoolMap" ("tieBreakerCalendarEventId"); +--> statement-breakpoint +create table "UserWeapon" ( + "userId" integer not null, + "weaponSplId" integer not null, + "order" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "isFavorite" integer not null default 0, + unique ("userId", "weaponSplId") + on conflict rollback, + unique ("userId", "order") + on conflict rollback, + foreign key ("userId") references "User" ("id") on delete restrict +) strict; +--> statement-breakpoint +create index user_weapon_user_id on "UserWeapon" ("userId"); +--> statement-breakpoint +create view "UserSubmittedImage" as +select + * +from + "UnvalidatedUserSubmittedImage" +where + "validatedAt" is not null; +--> statement-breakpoint +create table "AllTeam" ( + "id" integer primary key, + "name" text not null, + "customUrl" text not null, + "inviteCode" text not null, + "bio" text, + "avatarImgId" integer, + "bannerImgId" integer, + "createdAt" integer default (strftime('%s', 'now')) not null, + "deletedAt" integer, + "bsky" text, + "tag" text, + "customTheme" text default null, + "mapModePreferences" text, + foreign key ("avatarImgId") references "UnvalidatedUserSubmittedImage" ("id") on delete set null, + foreign key ("bannerImgId") references "UnvalidatedUserSubmittedImage" ("id") on delete set null +) strict; +--> statement-breakpoint +create index team_custom_url on "AllTeam" ("customUrl"); +--> statement-breakpoint +create view "Team" as +select + * +from + "AllTeam" +where + "deletedAt" is null; +--> statement-breakpoint +create table "AllTeamMember" ( + "teamId" integer not null, + "userId" integer not null, + "role" text, + "isOwner" integer not null default 0, + "createdAt" integer default (strftime('%s', 'now')) not null, + "leftAt" integer, + "isMainTeam" integer default 1, + "isManager" integer default 0, + "customRole" text, + "roleType" text, + "order" integer not null default 0, + foreign key ("teamId") references "AllTeam" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("teamId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "UnvalidatedUserSubmittedImage" ( + "id" integer primary key, + "validatedAt" integer, + "url" text not null unique, + "submitterUserId" integer not null, + foreign key ("submitterUserId") references "User" ("id") on delete set null +) strict; +--> statement-breakpoint +create index submitter_user_id on "UnvalidatedUserSubmittedImage" ("submitterUserId"); +--> statement-breakpoint +create table "PlusTier" ( + "userId" integer primary key, + "tier" integer not null, + foreign key ("userId") references "User" ("id") on delete set null +) strict; +--> statement-breakpoint +create table "UnvalidatedVideo" ( + "id" integer primary key, + "title" text not null, + "type" text not null, + "youtubeId" text not null, + "youtubePublishedAt" integer not null, + "submitterUserId" integer not null, + "validatedAt" integer, + "eventId" integer, + foreign key ("submitterUserId") references "User" ("id") on delete restrict, + foreign key ("eventId") references "CalendarEvent" ("id") on delete restrict +) strict; +--> statement-breakpoint +create index video_event_id on "UnvalidatedVideo" ("eventId"); +--> statement-breakpoint +create view "Video" as +select + * +from + "UnvalidatedVideo" +where + "validatedAt" is not null; +--> statement-breakpoint +create table "VideoMatch" ( + "id" integer primary key, + "videoId" integer not null, + "startsAt" integer not null, + "stageId" integer not null, + "mode" text not null, + foreign key ("videoId") references "UnvalidatedVideo" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index video_match_video_id on "VideoMatch" ("videoId"); +--> statement-breakpoint +create table "VideoMatchPlayer" ( + "videoMatchId" integer not null, + "playerUserId" integer, + "playerName" text, + "weaponSplId" integer not null, + "player" integer not null, + foreign key ("videoMatchId") references "VideoMatch" ("id") on delete cascade, + foreign key ("playerUserId") references "User" ("id") on delete restrict +) strict; +--> statement-breakpoint +create index video_match_player_video_match_id on "VideoMatchPlayer" ("videoMatchId"); +--> statement-breakpoint +create index video_match_player_player_user_id on "VideoMatchPlayer" ("playerUserId"); +--> statement-breakpoint +create table "XRankPlacement" ( + "id" integer primary key, + "weaponSplId" integer not null, + "name" text not null, + "nameDiscriminator" text not null, + "power" real not null, + "rank" integer not null, + "title" text not null, + "badges" text not null, + "bannerSplId" integer not null, + "playerId" integer not null, + "month" integer not null, + "year" integer not null, + "mode" text not null, + "region" text not null, + foreign key ("playerId") references "SplatoonPlayer" ("id") on delete cascade, + unique ("rank", "month", "year", "region", "mode") + on conflict rollback +) strict; +--> statement-breakpoint +create index splatoon_placement_player_id on "XRankPlacement" ("playerId"); +--> statement-breakpoint +create index calendar_event_tournament_id on "CalendarEvent" ("tournamentId"); +--> statement-breakpoint +create table "Tournament" ( + "id" integer primary key, + "mapPickingStyle" text not null, + "castTwitchAccounts" text, + "settings" text not null default '{"bracketProgression":[{"type":"double_elimination","name":"Main bracket"}]}', + "castedMatchesInfo" text, + "rules" text, + "preparedMaps" text, + "parentTournamentId" integer references "Tournament" ("id") on delete restrict, + "isFinalized" integer not null default 0, + "seedingSnapshot" text default null, + "tier" integer, + "vodsLastSyncAt" integer, + "vodsSyncCount" integer not null default 0 +) strict; +--> statement-breakpoint +create table "TournamentTeam" ( + "id" integer primary key, + "name" text not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "seed" integer, + "inviteCode" text not null unique, + "tournamentId" integer not null, + "prefersNotToHost" integer not null default 0, + "teamId" integer, + "droppedOut" integer default 0, + "activeRosterUserIds" text, + "avatarImgId" integer, + "startingBracketIdx" integer, + "isLooking" integer not null default 0, + "isPlaceholder" integer not null default 0, + "lfgNote" text, + "chatCode" text, + "abDivision" integer, + "tournamentTeamHistoryId" integer references "TournamentTeamHistory" ("id"), + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade, + unique ("tournamentId", "name") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_team_tournament_id on "TournamentTeam" ("tournamentId"); +--> statement-breakpoint +create table "TournamentTeamCheckIn" ( + "tournamentTeamId" integer not null, + "checkedInAt" integer not null, + "bracketIdx" integer, + "isCheckOut" integer default 0, + foreign key ("tournamentTeamId") references "TournamentTeam" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index tournament_team_check_in_tournament_team_id on "TournamentTeamCheckIn" ("tournamentTeamId"); +--> statement-breakpoint +create table "TournamentTeamMember" ( + "tournamentTeamId" integer not null, + "userId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "inGameName" text, + "role" text not null default 'REGULAR', + "isStayAsSub" integer not null default 0, + "isLooking" integer not null default 0, + "isSub" integer not null default 0, + foreign key ("tournamentTeamId") references "TournamentTeam" ("id") on delete cascade, + unique ("tournamentTeamId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_team_member_tournament_team_id on "TournamentTeamMember" ("tournamentTeamId"); +--> statement-breakpoint +create table "TournamentGroup" ( + "id" integer primary key, + "stageId" integer not null, + "number" integer not null, + foreign key ("stageId") references "TournamentStage" ("id") on delete cascade, + unique ("number", "stageId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_group_stage_id on "TournamentGroup" ("stageId"); +--> statement-breakpoint +create table "TournamentRound" ( + "id" integer primary key, + "stageId" integer not null, + "groupId" integer not null, + "number" integer not null, + "maps" text, + foreign key ("stageId") references "TournamentStage" ("id") on delete cascade, + foreign key ("groupId") references "TournamentGroup" ("id") on delete cascade, + unique ("number", "groupId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_round_stage_id on "TournamentRound" ("stageId"); +--> statement-breakpoint +create index tournament_round_group_id on "TournamentRound" ("groupId"); +--> statement-breakpoint +create table "TournamentMatchGameResult" ( + "id" integer primary key, + "matchId" integer not null, + "number" integer not null, + "stageId" integer not null, + "mode" text not null, + "source" text not null, + "winnerTeamId" integer not null, + "reporterId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "ko" integer, + foreign key ("matchId") references "TournamentMatch" ("id") on delete cascade, + foreign key ("winnerTeamId") references "TournamentTeam" ("id") on delete restrict, + foreign key ("reporterId") references "User" ("id") on delete restrict, + unique ("matchId", "number") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_match_game_result_match_id on "TournamentMatchGameResult" ("matchId"); +--> statement-breakpoint +create index tournament_match_game_result_winner_team_id on "TournamentMatchGameResult" ("winnerTeamId"); +--> statement-breakpoint +create table "TournamentMatchGameResultParticipant" ( + "matchGameResultId" integer not null, + "userId" integer not null, + "tournamentTeamId" integer, + foreign key ("matchGameResultId") references "TournamentMatchGameResult" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("matchGameResultId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_match_game_result_participant_match_game_result_id on "TournamentMatchGameResultParticipant" ("matchGameResultId"); +--> statement-breakpoint +create index tournament_match_game_result_participant_user_id on "TournamentMatchGameResultParticipant" ("userId"); +--> statement-breakpoint +create table "TrustRelationship" ( + "trustGiverUserId" integer not null, + "trustReceiverUserId" integer not null, + "lastUsedAt" integer default 0, + foreign key ("trustGiverUserId") references "User" ("id") on delete cascade, + foreign key ("trustReceiverUserId") references "User" ("id") on delete cascade, + unique ("trustGiverUserId", "trustReceiverUserId") + on conflict ignore +) strict; +--> statement-breakpoint +create index trust_relationship_trust_giver_user_id on "TrustRelationship" ("trustGiverUserId"); +--> statement-breakpoint +create index trust_relationship_trust_receiver_user_id on "TrustRelationship" ("trustReceiverUserId"); +--> statement-breakpoint +create table "Skill" ( + "id" integer primary key, + "mu" real not null, + "sigma" real not null, + "ordinal" real not null, + "userId" integer, + "identifier" text, + "matchesCount" integer not null, + "tournamentId" integer, + "groupMatchId" integer, + "season" integer not null, + "createdAt" integer, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("tournamentId") references "Tournament" ("id") on delete restrict, + unique ("userId", "tournamentId") + on conflict rollback +) strict; +--> statement-breakpoint +create index skill_user_id on "Skill" ("userId"); +--> statement-breakpoint +create index skill_tournament_id on "Skill" ("tournamentId"); +--> statement-breakpoint +create table "SkillTeamUser" ( + "userId" integer not null, + "skillId" integer not null, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("skillId") references "Skill" ("id") on delete cascade, + unique ("userId", "skillId") + on conflict rollback +) strict; +--> statement-breakpoint +create index skill_team_user_user_id on "SkillTeamUser" ("userId"); +--> statement-breakpoint +create index skill_team_user_skill_id on "SkillTeamUser" ("skillId"); +--> statement-breakpoint +create table "TournamentResult" ( + "tournamentId" integer not null, + "userId" integer not null, + "placement" integer not null, + "isHighlight" integer not null default 0, + "participantCount" integer not null, + "tournamentTeamId" integer not null, + "setResults" text not null default '[]', + "spDiff" real, + "div" text, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade, + foreign key ("tournamentTeamId") references "TournamentTeam" ("id") on delete cascade, + unique ("userId", "tournamentId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_result_user_id on "TournamentResult" ("userId"); +--> statement-breakpoint +create index tournament_result_tournament_id on "TournamentResult" ("tournamentId"); +--> statement-breakpoint +create table "Art" ( + "id" integer primary key, + "imgId" integer not null, + "authorId" integer not null, + "isShowcase" integer not null default 0, + "description" text, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("authorId") references "User" ("id") on delete restrict, + foreign key ("imgId") references "UnvalidatedUserSubmittedImage" ("id") on delete restrict +) strict; +--> statement-breakpoint +create index art_author_id on "Art" ("authorId"); +--> statement-breakpoint +create index art_img_id on "Art" ("imgId"); +--> statement-breakpoint +create table "ArtUserMetadata" ( + "artId" integer not null, + "userId" integer not null, + foreign key ("artId") references "Art" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index art_user_metadata_art_id on "ArtUserMetadata" ("artId"); +--> statement-breakpoint +create index art_user_metadata_user_id on "ArtUserMetadata" ("userId"); +--> statement-breakpoint +create table "ArtTag" ( + "id" integer primary key, + "name" text unique not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "authorId" integer not null, + foreign key ("authorId") references "User" ("id") on delete restrict +) strict; +--> statement-breakpoint +create table "TaggedArt" ( + "artId" integer not null, + "tagId" integer not null, + foreign key ("artId") references "Art" ("id") on delete cascade, + foreign key ("tagId") references "ArtTag" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index tagged_art_art_id on "TaggedArt" ("artId"); +--> statement-breakpoint +create index tagged_art_tag_id on "TaggedArt" ("tagId"); +--> statement-breakpoint +create index skill_identifier on "Skill" ("identifier"); +--> statement-breakpoint +create index skill_group_match_id on "Skill" ("groupMatchId"); +--> statement-breakpoint +create table "MapResult" ( + "mode" text not null, + "stageId" integer not null, + "userId" integer not null, + "wins" integer not null, + "losses" integer not null, + "season" integer not null, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("userId", "stageId", "mode", "season") + on conflict rollback +) strict; +--> statement-breakpoint +create index map_result_user_id on "MapResult" ("userId"); +--> statement-breakpoint +create table "PlayerResult" ( + "ownerUserId" integer not null, + "otherUserId" integer not null, + "mapWins" integer not null, + "mapLosses" integer not null, + "setWins" integer not null, + "setLosses" integer not null, + "type" text not null, + "season" integer not null, + foreign key ("ownerUserId") references "User" ("id") on delete cascade, + foreign key ("otherUserId") references "User" ("id") on delete cascade, + unique ("ownerUserId", "otherUserId", "type", "season") + on conflict rollback +) strict; +--> statement-breakpoint +create index player_result_owner_user_id on "PlayerResult" ("ownerUserId"); +--> statement-breakpoint +create index player_result_other_user_id on "PlayerResult" ("otherUserId"); +--> statement-breakpoint +create table "Group" ( + "id" integer primary key, + "teamId" integer, + "createdAt" integer default (strftime('%s', 'now')) not null, + "latestActionAt" integer default (strftime('%s', 'now')) not null, + "inviteCode" text not null, + "status" text not null, + "chatCode" text, + "matchmade" integer default 0 not null, + foreign key ("teamId") references "AllTeam" ("id") on delete restrict +) strict; +--> statement-breakpoint +create index group_team_id on "Group" ("teamId"); +--> statement-breakpoint +create table "GroupMember" ( + "groupId" integer not null, + "userId" integer not null, + "role" text not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "note" text, + foreign key ("userId") references "User" ("id") on delete restrict, + foreign key ("groupId") references "Group" ("id") on delete cascade, + unique ("userId", "groupId") + on conflict rollback +) strict; +--> statement-breakpoint +create index group_member_group_id on "GroupMember" ("groupId"); +--> statement-breakpoint +create index group_member_user_id on "GroupMember" ("userId"); +--> statement-breakpoint +create table "GroupLike" ( + "likerGroupId" integer not null, + "targetGroupId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "isRechallenge" integer not null default 0, + foreign key ("likerGroupId") references "Group" ("id") on delete cascade, + foreign key ("targetGroupId") references "Group" ("id") on delete cascade, + unique ("likerGroupId", "targetGroupId") + on conflict rollback +) strict; +--> statement-breakpoint +create index group_like_liker_group_id on "GroupLike" ("likerGroupId"); +--> statement-breakpoint +create index group_like_target_group_id on "GroupLike" ("targetGroupId"); +--> statement-breakpoint +create table "GroupMatchMap" ( + "id" integer primary key, + "matchId" integer not null, + "index" integer not null, + "mode" text not null, + "stageId" integer not null, + "source" text not null, + "winnerGroupId" integer, + "reportedAt" integer, + "reportedByUserId" integer references "User" ("id"), + foreign key ("matchId") references "GroupMatch" ("id") on delete cascade, + foreign key ("winnerGroupId") references "Group" ("id") on delete restrict, + unique ("matchId", "index") + on conflict rollback +) strict; +--> statement-breakpoint +create index group_match_map_match_id on "GroupMatchMap" ("matchId"); +--> statement-breakpoint +create index group_match_map_winner_group_id on "GroupMatchMap" ("winnerGroupId"); +--> statement-breakpoint +create table "LogInLink" ( + "code" text unique not null, + "expiresAt" integer not null, + "userId" integer not null, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index user_patron_tier on "User" ("patronTier"); +--> statement-breakpoint +create index calendar_event_result_player_user_id on "CalendarEventResultPlayer" ("userId"); +--> statement-breakpoint +create index calendar_event_result_player_team_id on "CalendarEventResultPlayer" ("teamId"); +--> statement-breakpoint +create table "PrivateUserNote" ( + "authorId" integer not null, + "targetId" integer not null, + "text" text, + "sentiment" text not null, + "updatedAt" integer default (strftime('%s', 'now')) not null, + foreign key ("authorId") references "User" ("id") on delete cascade, + foreign key ("targetId") references "User" ("id") on delete cascade, + unique ("authorId", "targetId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "TournamentStaff" ( + "tournamentId" integer not null, + "userId" integer not null, + "role" text not null, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("tournamentId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "UserFriendCode" ( + "friendCode" text not null, + "userId" integer not null, + "submitterUserId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("submitterUserId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index skill_season on "Skill" ("season"); +--> statement-breakpoint +create table "LFGPost" ( + "id" integer primary key, + "type" text not null, + "text" text not null, + "timezone" text not null, + "authorId" integer not null, + "teamId" integer, + "plusTierVisibility" integer, + "updatedAt" integer default (strftime('%s', 'now')) not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "languages" text, + foreign key ("authorId") references "User" ("id") on delete restrict, + foreign key ("teamId") references "AllTeam" ("id") on delete cascade, + unique ("authorId", "type") + on conflict rollback +) strict; +--> statement-breakpoint +create index lfg_post_author_id on "LFGPost" ("authorId"); +--> statement-breakpoint +create index lfg_post_team_id on "LFGPost" ("teamId"); +--> statement-breakpoint +create index skill_user_id_season on "Skill" ("userId", "season"); +--> statement-breakpoint +create index user_friend_code_user_id on "UserFriendCode" ("userId"); +--> statement-breakpoint +create table "TournamentOrganization" ( + "id" integer primary key, + "name" text not null, + "slug" text unique not null, + "description" text, + "socials" text, + "avatarImgId" integer, + "isEstablished" integer not null default 0, + foreign key ("avatarImgId") references "UnvalidatedUserSubmittedImage" ("id") on delete set null +) strict; +--> statement-breakpoint +create index tournament_organization_slug on "TournamentOrganization" ("slug"); +--> statement-breakpoint +create table "TournamentOrganizationMember" ( + "organizationId" integer not null, + "userId" integer not null, + "role" text not null, + "roleDisplayName" text, + foreign key ("organizationId") references "TournamentOrganization" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("organizationId", "userId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "TournamentOrganizationBadge" ( + "organizationId" integer not null, + "badgeId" integer not null, + foreign key ("organizationId") references "TournamentOrganization" ("id") on delete cascade, + foreign key ("badgeId") references "Badge" ("id") on delete cascade, + unique ("organizationId", "badgeId") + on conflict rollback +) strict; +--> statement-breakpoint +create table "TournamentOrganizationSeries" ( + "id" integer primary key, + "organizationId" integer not null, + "name" text not null, + "description" text, + "substringMatches" text not null, + "showLeaderboard" integer not null default 0, + "tierHistory" text, + foreign key ("organizationId") references "TournamentOrganization" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index tournament_organization_series_organization_id on "TournamentOrganizationSeries" ("organizationId"); +--> statement-breakpoint +create index calendar_event_organization_id on "CalendarEvent" ("organizationId"); +--> statement-breakpoint +create index tournament_result_tournament_team_id on "TournamentResult" ("tournamentTeamId"); +--> statement-breakpoint +create view "TeamMember" as +select + "AllTeamMember".* +from + "AllTeamMember" + left join "Team" on "Team"."id" = "AllTeamMember"."teamId" +where + "AllTeamMember"."leftAt" is null + and + -- if team id is null the team is deleted + "Team"."id" is not null + and "AllTeamMember"."isMainTeam" = 1; +--> statement-breakpoint +create view "TeamMemberWithSecondary" as +select + "AllTeamMember".* +from + "AllTeamMember" + left join "Team" on "Team"."id" = "AllTeamMember"."teamId" +where + "AllTeamMember"."leftAt" is null + and + -- if team id is null the team is deleted + "Team"."id" is not null; +--> statement-breakpoint +create index badge_author_id on "Badge" ("authorId"); +--> statement-breakpoint +create table "SeedingSkill" ( + "mu" real not null, + "sigma" real not null, + "ordinal" real not null, + "userId" integer not null, + "type" text not null, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("userId", "type") + on conflict replace +) strict; +--> statement-breakpoint +create table "TournamentBracketProgressionOverride" ( + "sourceBracketIdx" integer not null, + "destinationBracketIdx" integer not null, + "tournamentTeamId" integer not null, + "tournamentId" integer not null, + unique ("sourceBracketIdx", "tournamentTeamId") + on conflict replace, + foreign key ("tournamentTeamId") references "TournamentTeam" ("id") on delete cascade, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index tournament_bracket_progression_override_tournament_id on "TournamentBracketProgressionOverride" ("tournamentId"); +--> statement-breakpoint +create table "Notification" ( + "id" integer primary key, + "type" text not null, + "meta" text, + "pictureUrl" text, + "createdAt" integer default (strftime('%s', 'now')) not null +) strict; +--> statement-breakpoint +create index notification_type on "Notification" ("type"); +--> statement-breakpoint +create table "NotificationUser" ( + "notificationId" integer not null, + "userId" integer not null, + "seen" integer default 0 not null, + unique ("notificationId", "userId"), + foreign key ("notificationId") references "Notification" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index notification_user_id on "NotificationUser" ("userId"); +--> statement-breakpoint +create table "NotificationUserSubscription" ( + "id" integer primary key, + "userId" integer not null, + "subscription" text not null, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index notification_push_url_user_id on "NotificationUserSubscription" ("userId"); +--> statement-breakpoint +create table "ScrimPost" ( + "id" integer primary key, + "startsAt" integer not null, + "maxDiv" integer, + "minDiv" integer, + "visibility" text, + "text" text, + "chatCode" text not null, + "teamId" integer, + "createdAt" integer default (strftime('%s', 'now')) not null, + "updatedAt" integer default (strftime('%s', 'now')) not null, + "managedByAnyone" integer default 0 not null, + "canceledAt" integer, + "canceledByUserId" integer references "User" ("id") on delete restrict, + "cancelReason" text, + "isScheduledForFuture" integer default 1, + "rangeEndsAt" integer, + "maps" text, + "mapsTournamentId" integer references "Tournament" ("id") on delete cascade, + foreign key ("teamId") references "AllTeam" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index scrim_post_team_id on "ScrimPost" ("teamId"); +--> statement-breakpoint +create table "ScrimPostUser" ( + "scrimPostId" integer not null, + "userId" integer not null, + "isOwner" integer not null, + unique ("scrimPostId", "userId") + on conflict rollback, + foreign key ("scrimPostId") references "ScrimPost" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create table "ScrimPostRequest" ( + "id" integer primary key, + "scrimPostId" integer not null, + "teamId" integer, + "isAccepted" integer default 0 not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "message" text, + "startsAt" integer, + unique ("scrimPostId", "teamId") + on conflict rollback, + foreign key ("scrimPostId") references "ScrimPost" ("id") on delete cascade, + foreign key ("teamId") references "AllTeam" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index scrim_post_request_scrim_post_id on "ScrimPostRequest" ("scrimPostId"); +--> statement-breakpoint +create index scrim_post_request_team_id on "ScrimPostRequest" ("teamId"); +--> statement-breakpoint +create table "ScrimPostRequestUser" ( + "scrimPostRequestId" integer not null, + "userId" integer not null, + "isOwner" integer not null, + unique ("scrimPostRequestId", "userId") + on conflict rollback, + foreign key ("scrimPostRequestId") references "ScrimPostRequest" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index scrim_post_request_user_scrim_post_request_id on "ScrimPostRequestUser" ("scrimPostRequestId"); +--> statement-breakpoint +create index scrim_post_request_user_user_id on "ScrimPostRequestUser" ("userId"); +--> statement-breakpoint +create table "Association" ( + "id" integer primary key, + "name" text not null, + "inviteCode" text not null unique, + "createdAt" integer default (strftime('%s', 'now')) not null +) strict; +--> statement-breakpoint +create table "AssociationMember" ( + "userId" integer not null, + "associationId" integer not null, + "role" text not null, + unique ("userId", "associationId") + on conflict rollback, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("associationId") references "Association" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index association_member_user_id on "AssociationMember" ("userId"); +--> statement-breakpoint +create index association_member_association_id on "AssociationMember" ("associationId"); +--> statement-breakpoint +create table "BanLog" ( + "id" integer primary key, + "userId" integer not null, + "banned" integer, + "bannedReason" text, + "bannedByUserId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("userId") references "User" ("id") on delete restrict, + foreign key ("bannedByUserId") references "User" ("id") on delete restrict +); +--> statement-breakpoint +create index ban_log_user_id on "BanLog" ("userId"); +--> statement-breakpoint +create table "ModNote" ( + "id" integer primary key, + "userId" integer not null, + "authorId" integer not null, + "text" text not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "isDeleted" integer not null default 0, + foreign key ("userId") references "User" ("id") on delete restrict, + foreign key ("authorId") references "User" ("id") on delete restrict +); +--> statement-breakpoint +create index mod_note_user_id on "ModNote" ("userId"); +--> statement-breakpoint +create table "TournamentOrganizationBannedUser" ( + "organizationId" integer not null references "TournamentOrganization" ("id") on delete cascade, + "userId" integer not null references "User" ("id") on delete restrict, + "privateNote" text, + "updatedAt" integer default (strftime('%s', 'now')) not null, + "expiresAt" integer, + unique ("organizationId", "userId") + on conflict replace +); +--> statement-breakpoint +create index tournament_team_team_id on "TournamentTeam" ("teamId"); +--> statement-breakpoint +create unique index badge_owner_tournament_user_unique on "TournamentBadgeOwner" ("tournamentId", "userId"); +--> statement-breakpoint +create index idx_tmgrp_tournament_team_id on "TournamentMatchGameResultParticipant" ("tournamentTeamId"); +--> statement-breakpoint +create index "scrim_post_maps_tournament_id" on "ScrimPost" ("mapsTournamentId"); +--> statement-breakpoint +create index map_result_user_id_season on "MapResult" ("userId", "season"); +--> statement-breakpoint +create index player_result_owner_user_id_season on "PlayerResult" ("ownerUserId", "season"); +--> statement-breakpoint +create table "LiveStream" ( + "id" integer primary key, + "userId" integer unique, + "viewerCount" integer not null, + "thumbnailUrl" text not null, + "twitch" text, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index user_twitch on "User" ("twitch"); +--> statement-breakpoint +create index livestream_twitch on "LiveStream" ("twitch"); +--> statement-breakpoint +create table "ApiToken" ( + "id" integer primary key, + "token" text not null unique, + "userId" integer not null, + "type" text not null default 'read', + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create unique index api_token_user_id_type on "ApiToken" ("userId", "type"); +--> statement-breakpoint +create table "UserWidget" ( + "userId" integer not null, + "index" integer not null, + "widget" text not null, + primary key ("userId", "index"), + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index user_widget_user_id on "UserWidget" ("userId"); +--> statement-breakpoint +create table "Friendship" ( + "id" integer primary key, + "userOneId" integer not null, + "userTwoId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + unique ("userOneId", "userTwoId") + on conflict rollback, + foreign key ("userOneId") references "User" ("id") on delete cascade, + foreign key ("userTwoId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index friendship_user_one_id on "Friendship" ("userOneId"); +--> statement-breakpoint +create index friendship_user_two_id on "Friendship" ("userTwoId"); +--> statement-breakpoint +create table "FriendRequest" ( + "id" integer primary key, + "senderId" integer not null, + "receiverId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + unique ("senderId", "receiverId") + on conflict rollback, + foreign key ("senderId") references "User" ("id") on delete cascade, + foreign key ("receiverId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index friend_request_receiver_id on "FriendRequest" ("receiverId"); +--> statement-breakpoint +create index all_team_member_user_id on "AllTeamMember" ("userId"); +--> statement-breakpoint +create table "SavedCalendarEvent" ( + "id" integer primary key, + "userId" integer not null, + "calendarEventId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + unique ("userId", "calendarEventId") + on conflict rollback, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("calendarEventId") references "CalendarEvent" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index saved_calendar_event_user_id on "SavedCalendarEvent" ("userId"); +--> statement-breakpoint +create index saved_calendar_event_calendar_event_id on "SavedCalendarEvent" ("calendarEventId"); +--> statement-breakpoint +create table "SplatoonRotation" ( + "id" integer primary key, + "type" text not null, + "mode" text not null, + "stageId1" integer not null, + "stageId2" integer not null, + "startsAt" integer not null, + "endsAt" integer not null +) strict; +--> statement-breakpoint +create index tournament_team_member_user_id_is_looking on "TournamentTeamMember" ("userId", "isLooking"); +--> statement-breakpoint +create trigger sync_is_looking_on_team_update after +update of isLooking on "TournamentTeam" begin +update "TournamentTeamMember" +set + "isLooking" = NEW."isLooking" +where + "tournamentTeamId" = NEW."id"; + +end; +--> statement-breakpoint +create trigger sync_is_looking_on_member_insert after insert on "TournamentTeamMember" begin +update "TournamentTeamMember" +set + "isLooking" = ( + select + "isLooking" + from + "TournamentTeam" + where + "id" = NEW."tournamentTeamId" + ) +where + rowid = NEW.rowid; + +end; +--> statement-breakpoint +create table "TournamentLFGLike" ( + "likerTeamId" integer not null, + "targetTeamId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("likerTeamId") references "TournamentTeam" ("id") on delete cascade, + foreign key ("targetTeamId") references "TournamentTeam" ("id") on delete cascade, + unique ("likerTeamId", "targetTeamId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_lfg_like_liker_team_id on "TournamentLFGLike" ("likerTeamId"); +--> statement-breakpoint +create index tournament_lfg_like_target_team_id on "TournamentLFGLike" ("targetTeamId"); +--> statement-breakpoint +create table "TournamentStreamer" ( + "id" integer primary key autoincrement, + "userId" integer, + "tournamentId" integer not null, + "twitchAccount" text not null, + unique ("twitchAccount", "tournamentId") + on conflict ignore +) strict; +--> statement-breakpoint +create table "TournamentMatchPickBanEvent" ( + "type" text not null, + "stageId" integer, + "mode" text, + "matchId" integer not null, + "authorId" integer, + "number" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("authorId") references "User" ("id") on delete restrict, + foreign key ("matchId") references "TournamentMatch" ("id") on delete cascade, + unique ("matchId", "number") + on conflict rollback +) strict; +--> statement-breakpoint +create index pick_ban_event_author_id on "TournamentMatchPickBanEvent" ("authorId"); +--> statement-breakpoint +create index pick_ban_event_match_id on "TournamentMatchPickBanEvent" ("matchId"); +--> statement-breakpoint +create table "TournamentMatchVod" ( + "id" integer primary key autoincrement, + "matchId" integer not null references "TournamentMatch" ("id"), + "userId" integer references "User" ("id"), + "platform" text not null, + "account" text not null, + "platformVideoId" text not null, + "timestampSeconds" integer not null, + "viewCount" integer not null +) strict; +--> statement-breakpoint +create unique index "tournament_match_vod_match_id_account" on "TournamentMatchVod" ("matchId", "account"); +--> statement-breakpoint +create table "Build" ( + "id" integer primary key, + "ownerId" integer not null, + "title" text not null, + "description" text, + "modes" text, + "headGearSplId" integer, + "clothesGearSplId" integer, + "shoesGearSplId" integer, + "updatedAt" integer default (strftime('%s', 'now')) not null, + "abilities" text, + "abilitiesSignature" text, + "isPrivate" integer not null default 0, + foreign key ("ownerId") references "User" ("id") on delete restrict +) strict; +--> statement-breakpoint +create index build_owner_id on "Build" ("ownerId"); +--> statement-breakpoint +create unique index "tournament_team_check_in_team_bracket_unique" on "TournamentTeamCheckIn" ("tournamentTeamId", coalesce("bracketIdx", -1)); +--> statement-breakpoint +create table "GroupMatch" ( + "id" integer primary key, + "alphaGroupId" integer not null, + "bravoGroupId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "chatCode" text, + "memento" text, + "confirmedAt" integer, + "confirmedByUserId" integer references "User" ("id"), + "cancelRequestedByUserId" integer references "User" ("id"), + "cancelAcceptedByUserId" integer references "User" ("id"), + "noScreen" integer default 0 not null, + foreign key ("alphaGroupId") references "Group" ("id") on delete restrict, + foreign key ("bravoGroupId") references "Group" ("id") on delete restrict, + unique ("alphaGroupId") + on conflict rollback, + unique ("bravoGroupId") + on conflict rollback +) strict; +--> statement-breakpoint +create index group_match_alpha_group_id on "GroupMatch" ("alphaGroupId"); +--> statement-breakpoint +create index group_match_bravo_group_id on "GroupMatch" ("bravoGroupId"); +--> statement-breakpoint +create index group_match_created_at on "GroupMatch" ("createdAt"); +--> statement-breakpoint +create index group_match_confirmed_at on "GroupMatch" ("confirmedAt"); +--> statement-breakpoint +create index group_match_map_reported_at on "GroupMatchMap" ("reportedAt"); +--> statement-breakpoint +create table "GroupMatchContinueVote" ( + "id" integer primary key, + "groupId" integer not null, + "userId" integer not null, + "isContinuing" integer not null check ("isContinuing" in (0, 1)), + "votedAt" integer default (strftime('%s', 'now')) not null, + foreign key ("groupId") references "Group" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("groupId", "userId") +) strict; +--> statement-breakpoint +create index group_match_continue_vote_group_id on "GroupMatchContinueVote" ("groupId"); +--> statement-breakpoint +create view "PlusVotingResult" as +select + "votedId", + "tier", + avg("score") as "score", + "month", + "year", + exists ( + select + 1 + from + "PlusSuggestion" + where + "PlusSuggestion"."month" = "PlusVote"."month" + and "PlusSuggestion"."year" = "PlusVote"."year" + and "PlusSuggestion"."suggestedId" = "PlusVote"."votedId" + and "PlusSuggestion"."tier" = "PlusVote"."tier" + ) as "wasSuggested" +from + "PlusVote" +group by + "votedId", + "tier", + "month", + "year"; +--> statement-breakpoint +create view "BadgeOwner" as +select + "userId", + "badgeId", + "count" +from + "TournamentBadgeOwner" +union all +select + "id" as "userId", + case + when "patronTier" = 2 then 40 + else 41 + end as "badgeId", + 1 as "count" +from + "User" +where + "patronTier" > 1; +--> statement-breakpoint +create index tournament_badge_owner_user_id on "TournamentBadgeOwner" ("userId"); +--> statement-breakpoint +create table "ReportedWeapon" ( + "groupMatchId" integer, + "tournamentMatchId" integer, + "mapIndex" integer not null, + "weaponSplId" integer not null, + "userId" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("groupMatchId") references "GroupMatch" ("id") on delete cascade, + foreign key ("tournamentMatchId") references "TournamentMatch" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete restrict, + unique ("groupMatchId", "mapIndex", "userId") + on conflict rollback, + unique ("tournamentMatchId", "mapIndex", "userId") + on conflict rollback, + check ( + ("groupMatchId" is not null) <> ("tournamentMatchId" is not null) + ) +) strict; +--> statement-breakpoint +create index reported_weapon_group_match_id on "ReportedWeapon" ("groupMatchId"); +--> statement-breakpoint +create index reported_weapon_tournament_match_id on "ReportedWeapon" ("tournamentMatchId"); +--> statement-breakpoint +create index reported_weapon_user_id on "ReportedWeapon" ("userId"); +--> statement-breakpoint +create index reported_weapon_user_created_at_weapon on "ReportedWeapon" ("userId", "createdAt", "weaponSplId"); +--> statement-breakpoint +create table "BuildAbilitySum" ( + "buildId" integer not null, + "ability" text not null, + "abilityPoints" integer not null, + foreign key ("buildId") references "Build" ("id") on delete cascade, + unique ("buildId", "ability") + on conflict rollback +) strict; +--> statement-breakpoint +create table "BuildWeaponAbility" ( + "canonicalWeaponSplId" integer not null, + "buildId" integer not null, + "ability" text not null, + "abilityPoints" integer not null, + foreign key ("buildId") references "Build" ("id") on delete cascade, + unique ("canonicalWeaponSplId", "buildId", "ability") + on conflict rollback +) strict; +--> statement-breakpoint +create index build_ability_sum_ability_ap on "BuildAbilitySum" ("ability", "abilityPoints"); +--> statement-breakpoint +create index build_weapon_ability_weapon_ability_ap on "BuildWeaponAbility" ( + "canonicalWeaponSplId", + "ability", + "abilityPoints" +); +--> statement-breakpoint +create index build_abilities_signature on "Build" ("abilitiesSignature"); +--> statement-breakpoint +create unique index build_weapon_canonical_unique on "BuildWeapon" ("buildId", "canonicalWeaponSplId"); +--> statement-breakpoint +create index build_weapon_lookup on "BuildWeapon" ( + "canonicalWeaponSplId", + "sortValue", + "updatedAt" desc, + "buildId" +); +--> statement-breakpoint +create table "ScrimMapList" ( + "id" integer primary key autoincrement, + "scrimPostId" integer not null, + "side" text not null check ("side" in ('ALPHA', 'BRAVO')), + "source" text not null check ("source" in ('TOURNAMENT', 'POOL')), + "tournamentId" integer, + "serializedPool" text, + "updatedAt" integer not null, + foreign key ("scrimPostId") references "ScrimPost" ("id") on delete cascade, + foreign key ("tournamentId") references "Tournament" ("id"), + unique ("scrimPostId", "side") + on conflict rollback +) strict; +--> statement-breakpoint +create table "ScrimMap" ( + "id" integer primary key autoincrement, + "scrimPostId" integer not null, + "index" integer not null, + "mode" text not null, + "stageId" integer not null, + "winnerSide" text check ("winnerSide" in ('ALPHA', 'BRAVO')), + "reportedAt" integer, + "reportedByUserId" integer, + foreign key ("scrimPostId") references "ScrimPost" ("id") on delete cascade, + foreign key ("reportedByUserId") references "User" ("id"), + unique ("scrimPostId", "index") + on conflict rollback +) strict; +--> statement-breakpoint +create index scrim_map_scrim_post_id_index_idx on "ScrimMap" ("scrimPostId", "index"); +--> statement-breakpoint +create table "UserWeaponPool" ( + "userId" integer not null, + "sortOrder" integer not null, + "weaponSplId" integer not null, + "isFavorite" integer not null default 0, + foreign key ("userId") references "User" ("id") on delete cascade, + primary key ("userId", "sortOrder") +) strict; +--> statement-breakpoint +create table "TenStarWeapon" ( + "userId" integer not null, + "weaponSplId" integer not null, + foreign key ("userId") references "User" ("id") on delete cascade, + primary key ("userId", "weaponSplId") +) strict; +--> statement-breakpoint +create index xrank_placement_player_power on "XRankPlacement" ( + "playerId", + "power", + "mode", + "weaponSplId", + "name" +); +--> statement-breakpoint +create index tournament_badge_owner_badge_id on "TournamentBadgeOwner" ("badgeId"); +--> statement-breakpoint +create virtual table "UserSearch" using fts5 ( + "username", + "inGameName", + "discordUniqueName", + "customUrl", + content = 'User', + content_rowid = 'id', + tokenize = 'trigram' +); +--> statement-breakpoint +create trigger "user_search_after_insert" after insert on "User" begin +insert into + "UserSearch" ( + rowid, + "username", + "inGameName", + "discordUniqueName", + "customUrl" + ) +values + ( + new."id", + new."username", + new."inGameName", + new."discordUniqueName", + new."customUrl" + ); + +end; +--> statement-breakpoint +create trigger "user_search_after_delete" after delete on "User" begin +insert into + "UserSearch" ( + "UserSearch", + rowid, + "username", + "inGameName", + "discordUniqueName", + "customUrl" + ) +values + ( + 'delete', + old."id", + old."username", + old."inGameName", + old."discordUniqueName", + old."customUrl" + ); + +end; +--> statement-breakpoint +create trigger "user_search_after_update" after +update of "customName", +"discordName", +"inGameName", +"discordUniqueName", +"customUrl" on "User" begin +insert into + "UserSearch" ( + "UserSearch", + rowid, + "username", + "inGameName", + "discordUniqueName", + "customUrl" + ) +values + ( + 'delete', + old."id", + old."username", + old."inGameName", + old."discordUniqueName", + old."customUrl" + ); + +insert into + "UserSearch" ( + rowid, + "username", + "inGameName", + "discordUniqueName", + "customUrl" + ) +values + ( + new."id", + new."username", + new."inGameName", + new."discordUniqueName", + new."customUrl" + ); + +end; +--> statement-breakpoint +create table "TournamentTeamHistory" ( + "id" integer primary key autoincrement, + "tournamentTeamId" integer not null, + "tournamentId" integer not null, + "name" text not null, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index tournament_team_history_tournament_id_idx on "TournamentTeamHistory" ("tournamentId"); +--> statement-breakpoint +create table "ExternalStream" ( + "id" integer primary key autoincrement, + "name" text not null, + "url" text not null, + "avatarImgId" integer, + "startsAt" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("avatarImgId") references "UnvalidatedUserSubmittedImage" ("id") on delete set null +) strict; +--> statement-breakpoint +create table "SplatoonPlayer" ( + "id" integer primary key, + "userId" integer unique, + "splId" text unique not null, + "peakXp" text, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create index splatoon_player_user_id on "SplatoonPlayer" ("userId"); +--> statement-breakpoint +create index all_team_avatar_img_id on "AllTeam" ("avatarImgId"); +--> statement-breakpoint +create index all_team_banner_img_id on "AllTeam" ("bannerImgId"); +--> statement-breakpoint +create index calendar_event_avatar_img_id on "CalendarEvent" ("avatarImgId"); +--> statement-breakpoint +create index plus_vote_year_month on "PlusVote" ("year", "month", "votedId", "tier", "score"); +--> statement-breakpoint +create index reported_weapon_tournament_created_at on "ReportedWeapon" ( + "createdAt", + "userId", + "weaponSplId", + "tournamentMatchId" +) +where + "tournamentMatchId" is not null; +--> statement-breakpoint +create index reported_weapon_group_match_user_weapon on "ReportedWeapon" ("groupMatchId", "userId", "weaponSplId"); +--> statement-breakpoint +create index skill_season_identifier_leaderboard on "Skill" ("season", "identifier", "ordinal", "matchesCount"); +--> statement-breakpoint +create index skill_season_user_id_leaderboard on "Skill" ( + "season", + "userId", + "groupMatchId", + "ordinal", + "matchesCount" +); +--> statement-breakpoint +create index xrank_placement_power on "XRankPlacement" ("power" desc); +--> statement-breakpoint +create index xrank_placement_mode_power on "XRankPlacement" ("mode", "power" desc); +--> statement-breakpoint +create index xrank_placement_weapon_power on "XRankPlacement" ("weaponSplId", "power" desc); +--> statement-breakpoint +create index calendar_event_result_team_event_id on "CalendarEventResultTeam" ("eventId"); +--> statement-breakpoint +create index user_map_mode_preferences on "User" ("id", "mapModePreferences") +where + "mapModePreferences" is not null; +--> statement-breakpoint +create index group_status_active on "Group" ("status") +where + "status" != 'INACTIVE'; +--> statement-breakpoint +create index art_created_at on "Art" ("createdAt" desc); +--> statement-breakpoint +create table "UserReport" ( + "id" integer primary key autoincrement, + "reportedUserId" integer not null, + "reporterUserId" integer not null, + "category" text not null, + "description" text not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + "matchId" integer references "GroupMatch" ("id") on delete set null, + foreign key ("reportedUserId") references "User" ("id") on delete cascade, + foreign key ("reporterUserId") references "User" ("id") on delete cascade, + unique ("reportedUserId", "reporterUserId") +) strict; +--> statement-breakpoint +create index user_report_reported_user_id_idx on "UserReport" ("reportedUserId"); +--> statement-breakpoint +create table "TournamentMatch" ( + "id" integer primary key, + "roundId" integer not null, + "stageId" integer not null, + "groupId" integer not null, + "number" integer not null, + "opponentOne" text, + "opponentTwo" text, + "winnerSide" text check ("winnerSide" in ('opponent1', 'opponent2')), + "chatCode" text, + "startedAt" integer, + foreign key ("roundId") references "TournamentRound" ("id") on delete cascade, + foreign key ("stageId") references "TournamentStage" ("id") on delete cascade, + foreign key ("groupId") references "TournamentGroup" ("id") on delete cascade, + unique ("number", "roundId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_match_round_id on "TournamentMatch" ("roundId"); +--> statement-breakpoint +create index tournament_match_stage_id on "TournamentMatch" ("stageId"); +--> statement-breakpoint +create index tournament_match_group_id on "TournamentMatch" ("groupId"); +--> statement-breakpoint +create index idx_tournament_match_opponent_one_id on "TournamentMatch" ("opponentOne" ->> '$.id'); +--> statement-breakpoint +create index idx_tournament_match_opponent_two_id on "TournamentMatch" ("opponentTwo" ->> '$.id'); +--> statement-breakpoint +create index calendar_event_date_event_id_starts_at on "CalendarEventDate" ("eventId", "startsAt" desc); +--> statement-breakpoint +create index scrim_post_starts_at on "ScrimPost" ("startsAt"); +--> statement-breakpoint +create table "TournamentAuditLog" ( + "id" integer primary key autoincrement, + "tournamentId" integer not null, + "type" text not null, + "actorUserId" integer not null, + "subjectUserId" integer, + "tournamentTeamHistoryId" integer, + "metadata" text, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade, + foreign key ("actorUserId") references "User" ("id"), + foreign key ("subjectUserId") references "User" ("id"), + foreign key ("tournamentTeamHistoryId") references "TournamentTeamHistory" ("id") +) strict; +--> statement-breakpoint +create index tournament_audit_log_tournament_id_created_at_idx on "TournamentAuditLog" ("tournamentId", "createdAt"); +--> statement-breakpoint +create index tournament_audit_log_tournament_id_team_history_id_type_created_at_idx on "TournamentAuditLog" ( + "tournamentId", + "tournamentTeamHistoryId", + "type", + "createdAt" +); +--> statement-breakpoint +create table "TournamentStage" ( + "id" integer primary key, + "tournamentId" integer not null, + "name" text not null, + "type" text not null, + "settings" text not null, + "number" integer not null, + "createdAt" integer default (strftime('%s', 'now')) not null, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade, + unique ("number", "tournamentId") + on conflict rollback +) strict; +--> statement-breakpoint +create index tournament_stage_tournament_id on "TournamentStage" ("tournamentId"); +--> statement-breakpoint +create table "Trophy" ( + "id" integer primary key, + "name" text not null, + "model" text not null, + "code" text unique, + "organizationId" integer, + "creatorId" integer, + "managerId" integer, + foreign key ("organizationId") references "TournamentOrganization" ("id") on delete set null, + foreign key ("creatorId") references "User" ("id") on delete set null, + foreign key ("managerId") references "User" ("id") on delete set null +) strict; +--> statement-breakpoint +create table "TrophyOwner" ( + "trophyId" integer not null, + "userId" integer not null, + "tournamentId" integer not null, + "tier" integer, + foreign key ("trophyId") references "Trophy" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + foreign key ("tournamentId") references "Tournament" ("id") on delete cascade +) strict; +--> statement-breakpoint +create unique index "trophy_owner_tournament_user_unique" on "TrophyOwner" ("tournamentId", "userId", "trophyId"); +--> statement-breakpoint +create index "trophy_owner_user_id" on "TrophyOwner" ("userId"); +--> statement-breakpoint +create index "trophy_owner_trophy_id" on "TrophyOwner" ("trophyId", "userId"); +--> statement-breakpoint +create table "SpecialTrophyOwner" ( + "trophyId" integer not null, + "userId" integer not null, + "createdAt" integer not null, + primary key ("trophyId", "userId"), + foreign key ("trophyId") references "Trophy" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade +) strict; +--> statement-breakpoint +create table "PendingTrophy" ( + "id" integer primary key, + "name" text not null, + "model" text not null, + "description" text not null, + "organizationId" integer, + "submitterUserId" integer not null, + "createdAt" integer not null, + "declineReason" text, + "declinedAt" integer, + "declinedByUserId" integer, + "targetTrophyId" integer, + "managerId" integer, + foreign key ("organizationId") references "TournamentOrganization" ("id") on delete set null, + foreign key ("submitterUserId") references "User" ("id") on delete cascade, + foreign key ("declinedByUserId") references "User" ("id") on delete set null, + foreign key ("targetTrophyId") references "Trophy" ("id") on delete cascade, + foreign key ("managerId") references "User" ("id") on delete set null +) strict; +--> statement-breakpoint +create index "pending_trophy_submitter_idx" on "PendingTrophy" ("submitterUserId"); +--> statement-breakpoint +create table "PendingTrophyApproval" ( + "pendingTrophyId" integer not null, + "userId" integer not null, + "createdAt" integer not null, + foreign key ("pendingTrophyId") references "PendingTrophy" ("id") on delete cascade, + foreign key ("userId") references "User" ("id") on delete cascade, + unique ("pendingTrophyId", "userId") +) strict; +--> statement-breakpoint +create index "calendar_event_trophy_id" on "CalendarEvent" ("trophyId"); diff --git a/migrations/20260803000000-initial.ts b/migrations/20260803000000-initial.ts new file mode 100644 index 000000000..0396f64c6 --- /dev/null +++ b/migrations/20260803000000-initial.ts @@ -0,0 +1,77 @@ +import fs from "node:fs"; +import { fileURLToPath } from "node:url"; +import { type Kysely, sql } from "kysely"; + +const SCHEMA_PATH = fileURLToPath( + new URL("./20260803000000-initial.sql", import.meta.url), +); + +const STATEMENT_SEPARATOR = "--> statement-breakpoint"; + +const LAST_COLLAPSED_MIGRATION = "164-drop-tournament-sub.js"; + +/** + * Creates the schema as it stood when the 165 hand written migrations that came + * before it were collapsed into this one. Only ever bootstraps an empty database: + * production and any copy of it already has these tables, so there this migration + * only drops the bookkeeping table of the migration runner it replaces and records + * itself as run. + */ +export async function up(db: Kysely): Promise { + await assertNotBehindCollapsePoint(db); + + // left behind by ley, which tracked the migrations collapsed into this one + await sql`DROP TABLE IF EXISTS "migrations"`.execute(db); + + if (await hasSchema(db)) return; + + await db.transaction().execute(async (trx) => { + for (const statement of schemaStatements()) { + await sql.raw(statement).execute(trx); + } + }); +} + +/** + * A database still carrying ley's bookkeeping table is only safe to adopt as is if + * ley ran every migration collapsed into this one. Otherwise it would silently be + * left short of tables and columns this migration assumes are already there, which + * surfaces much later as confusing "no such table" errors at query time. + */ +async function assertNotBehindCollapsePoint(db: Kysely) { + const { rows: bookkeeping } = await sql<{ name: string }>` + SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'migrations' + `.execute(db); + + if (bookkeeping.length === 0) return; + + const { rows: applied } = await sql<{ name: string }>` + SELECT name FROM "migrations" WHERE name = ${LAST_COLLAPSED_MIGRATION} + `.execute(db); + + if (applied.length > 0) return; + + throw new Error( + `Database has not run "${LAST_COLLAPSED_MIGRATION}", the last of the migrations collapsed into 20260803000000-initial, so it can't be migrated any further. Replace it with an up to date copy of production.`, + ); +} + +async function hasSchema(db: Kysely) { + const { rows } = await sql<{ name: string }>` + SELECT name FROM sqlite_master + WHERE type = 'table' + AND name NOT LIKE 'sqlite_%' + AND name NOT IN ('kysely_migration', 'kysely_migration_lock') + LIMIT 1 + `.execute(db); + + return rows.length > 0; +} + +function schemaStatements() { + return fs + .readFileSync(SCHEMA_PATH, "utf8") + .split(STATEMENT_SEPARATOR) + .map((statement) => statement.trim()) + .filter((statement) => statement.length > 0); +} diff --git a/migrations/20260803155926-group-match-cancel-report.ts b/migrations/20260803155926-group-match-cancel-report.ts new file mode 100644 index 000000000..5c6e381b0 --- /dev/null +++ b/migrations/20260803155926-group-match-cancel-report.ts @@ -0,0 +1,55 @@ +import { type Kysely, sql } from "kysely"; + +/** Lets players report why a SendouQ match was cancelled and who caused it */ +export async function up(db: Kysely): Promise { + // kysely does not wrap sqlite migrations in a transaction, so do it here + await db.transaction().execute(async (trx) => { + await trx.schema + .createTable("GroupMatchCancelReport") + .addColumn("id", "integer", (col) => col.primaryKey().autoIncrement()) + .addColumn("groupMatchId", "integer", (col) => + col.notNull().references("GroupMatch.id").onDelete("cascade"), + ) + .addColumn("groupId", "integer", (col) => + col.notNull().references("Group.id").onDelete("cascade"), + ) + .addColumn("authorUserId", "integer", (col) => + col.notNull().references("User.id").onDelete("cascade"), + ) + .addColumn("reason", "text", (col) => col.notNull()) + .addColumn("createdAt", "integer", (col) => + col.notNull().defaultTo(sql`(strftime('%s', 'now'))`), + ) + .addUniqueConstraint( + "group_match_cancel_report_group_match_id_group_id", + ["groupMatchId", "groupId"], + ) + // every table in this schema is strict + .modifyEnd(sql`strict`) + .execute(); + + await trx.schema + .createTable("GroupMatchCancelReportPlayer") + .addColumn("cancelReportId", "integer", (col) => + col + .notNull() + .references("GroupMatchCancelReport.id") + .onDelete("cascade"), + ) + .addColumn("userId", "integer", (col) => + col.notNull().references("User.id").onDelete("cascade"), + ) + .addUniqueConstraint( + "group_match_cancel_report_player_cancel_report_id_user_id", + ["cancelReportId", "userId"], + ) + .modifyEnd(sql`strict`) + .execute(); + + await trx.schema + .createIndex("group_match_cancel_report_player_user_id_idx") + .on("GroupMatchCancelReportPlayer") + .column("userId") + .execute(); + }); +} diff --git a/package.json b/package.json index 5054b53ae..02ff8f411 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,8 @@ "dev:sentry": "NODE_OPTIONS='--import ./instrument.server.mjs' pnpm dev", "dev:prod": "cross-env DB_PATH=db-prod.sqlite3 VITE_PROD_MODE=true react-router dev --host", "start": "pnpm run migrate up && NODE_ENV=production NODE_OPTIONS='--import ./instrument.server.mjs' react-router-serve ./build/server/index.js", - "migrate": "ley", + "migrate": "node --experimental-strip-types scripts/migrate.ts", + "migrate:new": "node --experimental-strip-types scripts/create-migration.ts", "migrate:prod": "cross-env DB_PATH=db-prod.sqlite3 pnpm run migrate up", "check-translation-jsons": "node --experimental-strip-types scripts/check-translation-jsons.ts", "check-translation-jsons:no-write": "node --experimental-strip-types scripts/check-translation-jsons.ts --no-write", @@ -54,7 +55,6 @@ "@sentry/react-router": "10.68.0", "@tldraw/tldraw": "3.12.1", "@zumer/snapdom": "2.23.1", - "better-sqlite3": "13.0.1", "chart.js": "4.5.1", "clsx": "2.1.1", "compressorjs": "1.3.0", @@ -103,7 +103,6 @@ "@biomejs/biome": "2.5.5", "@playwright/test": "1.62.0", "@react-router/dev": "8.3.0", - "@types/better-sqlite3": "7.6.13", "@types/node": "26.1.1", "@types/nprogress": "0.2.3", "@types/react": "19.2.17", @@ -115,7 +114,6 @@ "cross-env": "10.1.0", "i18next-locales-sync": "2.1.1", "knip": "6.29.0", - "ley": "0.8.1", "sql-formatter": "15.8.2", "typescript": "7.0.2", "vite": "8.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 68067e8e3..7df3ac983 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -57,9 +57,6 @@ importers: '@zumer/snapdom': specifier: 2.23.1 version: 2.23.1 - better-sqlite3: - specifier: 13.0.1 - version: 13.0.1 chart.js: specifier: 4.5.1 version: 4.5.1 @@ -199,9 +196,6 @@ importers: '@react-router/dev': specifier: 8.3.0 version: 8.3.0(@react-router/serve@8.1.0(patch_hash=4d79b209948d4237f1ca3a5cca417c6d11519d8b1ab7084c75c46a39e3ac27d6)(react-router@8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(typescript@7.0.2))(react-router@8.3.0(react-dom@19.2.8(react@19.2.8))(react@19.2.8))(typescript@7.0.2)(vite@8.1.5(@types/node@26.1.1)(jiti@2.7.0)(yaml@2.9.0)) - '@types/better-sqlite3': - specifier: 7.6.13 - version: 7.6.13 '@types/node': specifier: 26.1.1 version: 26.1.1 @@ -235,9 +229,6 @@ importers: knip: specifier: 6.29.0 version: 6.29.0 - ley: - specifier: 0.8.1 - version: 0.8.1 sql-formatter: specifier: 15.8.2 version: 15.8.2 @@ -2630,9 +2621,6 @@ packages: '@tybys/wasm-util@0.10.3': resolution: {integrity: sha512-F3fo1MYrRJYL3zER0OUOmkutjr1Vp23m7OsSgp7nq4SP6OqX6C/56XFIPAl5bt3zaBRjmW7SGz3u/6LwFpYcOg==} - '@types/better-sqlite3@7.6.13': - resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} - '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -2920,10 +2908,6 @@ packages: resolution: {integrity: sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==} engines: {node: '>= 0.8'} - better-sqlite3@13.0.1: - resolution: {integrity: sha512-LYpmOXdkpQYf4wmlxkdzW01XGlOXNIbjLg45yNkh0FQ4814VbK9PdOFmhZpYbej+EZtR/i3FDdhEG98HqZdgnA==} - engines: {node: '>=22'} - blueimp-canvas-to-blob@3.29.0: resolution: {integrity: sha512-0pcSSGxC0QxT+yVkivxIqW0Y4VlO2XSDPofBAqoJ1qJxgH9eiUDLv50Rixij2cDuEfx4M6DpD9UGZpRhT5Q8qg==} @@ -3479,10 +3463,6 @@ packages: resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} engines: {node: '>=0.10.0'} - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - knip@6.29.0: resolution: {integrity: sha512-A3kXqSBky1tWBAqiU9srdtu0Larhzkuyor0aD/gg+ToiqyBncCCs2Q60sLsxmcKhV0OsKss9LV0hMPpwLv711Q==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3492,11 +3472,6 @@ packages: resolution: {integrity: sha512-LrQfPUeTW7MXbMvT62moEMnpMTuj9TO3lqjCeLKjM975PJ4Alrl/43f2tlDX7xOsNptKgH4LSNGwIbXwEkLg4g==} engines: {node: '>=22.0.0'} - ley@0.8.1: - resolution: {integrity: sha512-8Nd5uzie4PxiEJcQNv5YL1IQCMzye/0sE8VPB4KczJkyd44NfDyK/7Vbmp9eHYt+dJ4hxaXy+gF4DORSxYGArg==} - engines: {node: '>= 8'} - hasBin: true - lightningcss-android-arm64@1.33.0: resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} @@ -3680,10 +3655,6 @@ packages: resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - mk-dirs@3.0.0: - resolution: {integrity: sha512-FEZDdUFb88hgdnsfAPa4VxcPVOd+8GyZ2jsI965im5bjBlBYhrvXuTqLka/UHa6YdUNN/kZBsVgofhZ3322AJw==} - engines: {node: '>=6'} - module-details-from-path@1.0.4: resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} @@ -3694,10 +3665,6 @@ packages: resolution: {integrity: sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==} engines: {node: '>= 0.8.0'} - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - mrmime@2.0.1: resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} engines: {node: '>=10'} @@ -3734,10 +3701,6 @@ packages: resolution: {integrity: sha512-kOCT/1MCPAxY5iUV3wytNFUMUolzuwd/VF/1KCx7kf6CutrOsTie+84zTGTpgQycjvfLdBBdvBvFLqFD2c0wkQ==} engines: {node: '>=18'} - node-addon-api@8.9.0: - resolution: {integrity: sha512-ekZMeaaIzSQTSpr7X2X3iJM7lTzgnx8ahAG9pJfT/7+14mlEM8ZYQ9cgCDvSSRbReFK0oHli3WrZdCiRsgAT9Q==} - engines: {node: ^18 || ^20 || >= 21} - node-cron@4.6.0: resolution: {integrity: sha512-Si/bzYiKRHOB8/a99T2+SDGN582ONDMSTlJr5oCkT6GtnqPjZ2s10eoQRYkW9ZHwjVxONL+W8Fb+qR0AHMQsdg==} engines: {node: '>=20'} @@ -4185,10 +4148,6 @@ packages: runes2@1.1.4: resolution: {integrity: sha512-LNPnEDPOOU4ehF71m5JoQyzT2yxwD6ZreFJ7MxZUAoMKNMY1XrAo60H1CUoX5ncSm0rIuKlqn9JZNRrRkNou2g==} - sade@1.8.1: - resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} - engines: {node: '>=6'} - safe-buffer@5.1.2: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} @@ -4376,10 +4335,6 @@ packages: toposort@2.0.2: resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} - totalist@2.0.0: - resolution: {integrity: sha512-+Y17F0YzxfACxTyjfhnJQEe7afPA0GSpYlFkl2VFMxYP7jshQf9gXV7cH47EfToBumFThfKBvfAcoUn6fdNeRQ==} - engines: {node: '>=6'} - totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -7267,10 +7222,6 @@ snapshots: tslib: 2.8.1 optional: true - '@types/better-sqlite3@7.6.13': - dependencies: - '@types/node': 26.1.1 - '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 @@ -7535,10 +7486,6 @@ snapshots: dependencies: safe-buffer: 5.1.2 - better-sqlite3@13.0.1: - dependencies: - node-addon-api: 8.9.0 - blueimp-canvas-to-blob@3.29.0: {} bn.js@4.12.3: {} @@ -8051,8 +7998,6 @@ snapshots: kind-of@6.0.3: {} - kleur@4.1.5: {} - knip@6.29.0: dependencies: fdir: 6.5.0(picomatch@4.0.5) @@ -8071,13 +8016,6 @@ snapshots: kysely@0.29.0(patch_hash=a3e94339939b1be5b70610601e96fff19ed5678aab525de24b52dfc5212c686a): {} - ley@0.8.1: - dependencies: - kleur: 4.1.5 - mk-dirs: 3.0.0 - sade: 1.8.1 - totalist: 2.0.0 - lightningcss-android-arm64@1.33.0: optional: true @@ -8204,8 +8142,6 @@ snapshots: minipass@7.1.3: {} - mk-dirs@3.0.0: {} - module-details-from-path@1.0.4: {} moo@0.5.3: {} @@ -8220,8 +8156,6 @@ snapshots: transitivePeerDependencies: - supports-color - mri@1.2.0: {} - mrmime@2.0.1: {} ms@2.0.0: {} @@ -8247,8 +8181,6 @@ snapshots: optionalDependencies: '@rollup/rollup-linux-x64-gnu': 4.60.0 - node-addon-api@8.9.0: {} - node-cron@4.6.0: {} node-fetch@2.7.0: @@ -8759,10 +8691,6 @@ snapshots: runes2@1.1.4: {} - sade@1.8.1: - dependencies: - mri: 1.2.0 - safe-buffer@5.1.2: {} safe-buffer@5.2.1: {} @@ -8977,8 +8905,6 @@ snapshots: toposort@2.0.2: {} - totalist@2.0.0: {} - totalist@3.0.1: {} tr46@0.0.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 40cc90d76..691adcd5c 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,7 +1,6 @@ allowBuilds: '@sentry/cli': true aws-sdk: false - better-sqlite3: true core-js: false esbuild: true patchedDependencies: diff --git a/scripts/benchmark-db/cases.ts b/scripts/benchmark-db/cases.ts index 90338ae71..fbeb410c3 100644 --- a/scripts/benchmark-db/cases.ts +++ b/scripts/benchmark-db/cases.ts @@ -462,9 +462,9 @@ export function buildCases(fx: Fixtures): { // GroupMatchContinueVoteRepository add( - "GroupMatchContinueVoteRepository.findForGroups", + "GroupMatchContinueVoteRepository.findAllByGroupIds", fx.heavyGroupIds, - (groupIds) => GroupMatchContinueVoteRepository.findForGroups(groupIds), + (groupIds) => GroupMatchContinueVoteRepository.findAllByGroupIds(groupIds), ); // PlayerStatRepository diff --git a/scripts/benchmark-db/fixtures.ts b/scripts/benchmark-db/fixtures.ts index c39e82aad..300f0e959 100644 --- a/scripts/benchmark-db/fixtures.ts +++ b/scripts/benchmark-db/fixtures.ts @@ -1,6 +1,7 @@ import { sub } from "date-fns"; import { db } from "~/db/sql"; import type { Tables } from "~/db/tables"; +import type { SkillTeamIdentifier } from "~/features/mmr/mmr-utils"; import type { MainWeaponId, ModeShort, @@ -21,7 +22,7 @@ export interface Fixtures { skillBatch: { season: number; userIds: number[]; - identifiers: string[]; + identifiers: SkillTeamIdentifier[]; } | null; heavyGroupMatchId: number | null; heavyGroupIds: [number, number] | null; @@ -330,7 +331,9 @@ async function resolveSkillBatch() { return { season: seasonRow.season, userIds: userRows.map((row) => row.userId as number), - identifiers: identifierRows.map((row) => row.identifier as string), + identifiers: identifierRows.map( + (row) => row.identifier as SkillTeamIdentifier, + ), }; } @@ -655,8 +658,8 @@ async function resolveHeavyOrg() { .executeTakeFirst(); if (!latestEvent) return null; - const latestEventDate = databaseTimestampToDate(latestEvent.startTime); - const windowStart = latestEvent.startTime - 90 * 24 * 60 * 60; + const latestEventDate = databaseTimestampToDate(latestEvent.startsAt); + const windowStart = latestEvent.startsAt - 90 * 24 * 60 * 60; return { id: orgRow.id, @@ -666,7 +669,7 @@ async function resolveHeavyOrg() { eventMonth: latestEventDate.getUTCMonth(), eventYear: latestEventDate.getUTCFullYear(), windowStart, - windowEnd: latestEvent.startTime, + windowEnd: latestEvent.startsAt, }; } diff --git a/scripts/create-migration.ts b/scripts/create-migration.ts new file mode 100644 index 000000000..5d07d28de --- /dev/null +++ b/scripts/create-migration.ts @@ -0,0 +1,68 @@ +import fs from "node:fs"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const MIGRATION_FOLDER = fileURLToPath( + new URL("../migrations", import.meta.url), +); + +const TEMPLATE = `import type { Kysely } from "kysely"; + +/** TODO: describe what this migration changes */ +export async function up(db: Kysely): Promise { + // kysely does not wrap sqlite migrations in a transaction, so do it here + await db.transaction().execute(async (trx) => { + await trx.schema.alterTable("TODO").addColumn("TODO", "text").execute(); + }); +} +`; + +function main() { + const description = toKebabCase(process.argv.slice(2).join(" ")); + if (!description) { + throw new Error( + 'Missing migration description e.g. pnpm run migrate:new "add user pronouns"', + ); + } + + const fileName = `${timestamp(new Date())}-${description}.ts`; + const filePath = path.join(MIGRATION_FOLDER, fileName); + + if (fs.existsSync(filePath)) { + throw new Error(`${fileName} already exists`); + } + + fs.writeFileSync(filePath, TEMPLATE); + + // biome-ignore lint/suspicious/noConsole: CLI script output + console.log(`Created migrations/${fileName}`); +} + +/** Sortable UTC stamp, so two branches can never claim the same slot. */ +function timestamp(date: Date) { + const pad = (value: number) => String(value).padStart(2, "0"); + + return [ + date.getUTCFullYear(), + pad(date.getUTCMonth() + 1), + pad(date.getUTCDate()), + pad(date.getUTCHours()), + pad(date.getUTCMinutes()), + pad(date.getUTCSeconds()), + ].join(""); +} + +function toKebabCase(input: string) { + return input + .toLowerCase() + .replace(/[^a-z0-9]+/g, "-") + .replace(/^-+|-+$/g, ""); +} + +try { + main(); +} catch (error) { + // biome-ignore lint/suspicious/noConsole: CLI script output + console.error((error as Error).message); + process.exit(1); +} diff --git a/scripts/ensure-test-db.ts b/scripts/ensure-test-db.ts index 67bd9451d..6328584a6 100644 --- a/scripts/ensure-test-db.ts +++ b/scripts/ensure-test-db.ts @@ -1,8 +1,8 @@ import { execSync } from "node:child_process"; import fs from "node:fs"; import path from "node:path"; +import { DatabaseSync } from "node:sqlite"; import { fileURLToPath } from "node:url"; -import Database from "better-sqlite3"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -13,6 +13,13 @@ const TEST_DB_PATH = path.join(ROOT_DIR, "db-test.sqlite3"); export function setup() { ensureMigratedDb(TEST_DB_PATH); + + // Test workers only ever read this file, to copy its schema into their own + // in-memory database. Taking it out of WAL drops the -wal/-shm sidecars, so + // those concurrent opens need no write access and cannot contend. + const db = new DatabaseSync(TEST_DB_PATH); + db.exec("PRAGMA journal_mode = DELETE"); + db.close(); } /** @@ -48,21 +55,27 @@ export function ensureMigratedDb(dbPath: string) { function migrationFilesOnDisk() { return new Set( - fs.readdirSync(MIGRATIONS_DIR).filter((file) => file.endsWith(".js")), + fs + .readdirSync(MIGRATIONS_DIR) + .filter((file) => file.endsWith(".ts")) + // kysely tracks migrations by file name without the extension + .map((file) => file.slice(0, -".ts".length)), ); } function appliedMigrations(dbPath: string) { - const db = new Database(dbPath, { readonly: true }); + const db = new DatabaseSync(dbPath, { readOnly: true }); try { const hasMigrationsTable = db .prepare( - "select 1 from sqlite_master where type = 'table' and name = 'migrations'", + "select 1 from sqlite_master where type = 'table' and name = 'kysely_migration'", ) .get(); if (!hasMigrationsTable) return null; - const rows = db.prepare("select name from migrations").all() as Array<{ + const rows = db + .prepare("select name from kysely_migration") + .all() as Array<{ name: string; }>; return rows.map((row) => row.name); diff --git a/scripts/migrate.ts b/scripts/migrate.ts new file mode 100644 index 000000000..0f950be69 --- /dev/null +++ b/scripts/migrate.ts @@ -0,0 +1,79 @@ +import fs from "node:fs/promises"; +import path from "node:path"; +import { DatabaseSync } from "node:sqlite"; +import { fileURLToPath, pathToFileURL } from "node:url"; +import { Kysely } from "kysely"; +import { FileMigrationProvider, Migrator } from "kysely/migration"; +import { NodeSqliteDialect } from "../app/db/node-sqlite-dialect.ts"; + +const MIGRATION_FOLDER = fileURLToPath( + new URL("../migrations", import.meta.url), +); + +try { + process.loadEnvFile(); +} catch { + // .env is optional; in production DB_PATH comes from the host environment +} + +async function main() { + const command = process.argv[2] ?? "up"; + if (command !== "up") { + throw new Error( + `Unknown command "${command}". Only "up" is supported; migrations are never rolled back.`, + ); + } + + const dbPath = process.env.DB_PATH; + if (!dbPath) { + throw new Error("DB_PATH is not set"); + } + + const database = new DatabaseSync(dbPath); + database.exec("PRAGMA journal_mode = WAL"); + database.exec("PRAGMA foreign_keys = ON"); + database.exec("PRAGMA busy_timeout = 5000"); + + const db = new Kysely({ + dialect: new NodeSqliteDialect({ database }), + }); + + const migrator = new Migrator({ + db, + provider: new FileMigrationProvider({ + fs, + path, + migrationFolder: MIGRATION_FOLDER, + import: (filePath) => import(pathToFileURL(filePath).href), + }), + }); + + const { error, results } = await migrator.migrateToLatest(); + + for (const result of results ?? []) { + if (result.status === "Success") { + log(`↑ ${result.migrationName}`); + } else if (result.status === "Error") { + log(`✗ ${result.migrationName}`); + } + } + + await db.destroy(); + + if (error) throw error; + + if (!results?.length) { + log(`No pending migrations for ${dbPath}`); + } +} + +function log(message: string) { + // biome-ignore lint/suspicious/noConsole: CLI script output + console.log(message); +} + +main().catch((error) => { + // biome-ignore lint/suspicious/noConsole: CLI script output + console.error(error); + process.exit(1); +}); diff --git a/scripts/tsconfig.json b/scripts/tsconfig.json index 4719c9c7b..e27a3bca8 100644 --- a/scripts/tsconfig.json +++ b/scripts/tsconfig.json @@ -1,5 +1,8 @@ { "extends": "../tsconfig.json", "include": ["./**/*.ts", "../types/**/*.d.ts"], - "exclude": [] + "exclude": [], + "compilerOptions": { + "allowImportingTsExtensions": true + } } diff --git a/vite.config.ts b/vite.config.ts index 7cdcbeecb..0b77ca267 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -104,7 +104,6 @@ export default defineConfig((config) => { "@internationalized/date", "@tldraw/tldraw", "@zumer/snapdom", - "better-sqlite3", "chart.js", "compressorjs", "date-fns/locale/da",