From a3a6cbbec6e611ff3c778c0f730bb436c085413b Mon Sep 17 00:00:00 2001 From: hzhang Date: Sat, 16 May 2026 22:58:54 +0100 Subject: [PATCH] chore: standalone idempotent prod SQL migration (apikey alias + authorship) Co-Authored-By: Claude Opus 4.7 (1M context) --- .../2026-05-16_apikey_alias_authorship.sql | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 db/migrations/2026-05-16_apikey_alias_authorship.sql diff --git a/db/migrations/2026-05-16_apikey_alias_authorship.sql b/db/migrations/2026-05-16_apikey_alias_authorship.sql new file mode 100644 index 0000000..03edad7 --- /dev/null +++ b/db/migrations/2026-05-16_apikey_alias_authorship.sql @@ -0,0 +1,79 @@ +-- ============================================================================ +-- Production migration: apikey.alias (unique) + markdown/patch authorship +-- ============================================================================ +-- Idempotent. Safe to run multiple times. Target: MySQL 8 (no native +-- ADD COLUMN IF NOT EXISTS, so columns are guarded via information_schema +-- + a prepared statement). Mirrors the app's db.run_migrations(); running +-- both is harmless. +-- +-- Apply against the application schema, e.g.: +-- docker exec -i mysql sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" hangmanlab' \ +-- < 2026-05-16_apikey_alias_authorship.sql +-- ============================================================================ + +SET @schema := DATABASE(); + +-- ---- helper macro is not available in plain SQL; repeat the guarded block -- + +-- apikey.alias -------------------------------------------------------------- +SET @c := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema=@schema AND table_name='apikey' AND column_name='alias'); +SET @ddl := IF(@c=0, + 'ALTER TABLE apikey ADD COLUMN alias VARCHAR(255) NULL', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +-- backfill: existing keys get alias = their (unique) key string +UPDATE apikey SET alias = `key` WHERE alias IS NULL; + +-- apikey unique constraint on alias ----------------------------------------- +SET @i := (SELECT COUNT(*) FROM information_schema.statistics + WHERE table_schema=@schema AND table_name='apikey' AND index_name='uq_apikey_alias'); +SET @ddl := IF(@i=0, + 'ALTER TABLE apikey ADD CONSTRAINT uq_apikey_alias UNIQUE (alias)', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; + +-- markdown.updated_at ------------------------------------------------------- +SET @c := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema=@schema AND table_name='markdown' AND column_name='updated_at'); +SET @ddl := IF(@c=0, + 'ALTER TABLE markdown ADD COLUMN updated_at DATETIME NULL', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +UPDATE markdown SET updated_at = created_at WHERE updated_at IS NULL; + +-- markdown.author ----------------------------------------------------------- +SET @c := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema=@schema AND table_name='markdown' AND column_name='author'); +SET @ddl := IF(@c=0, + 'ALTER TABLE markdown ADD COLUMN author VARCHAR(255) NULL', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +UPDATE markdown SET author = 'admin' WHERE author IS NULL; + +-- markdown.last_modified_by ------------------------------------------------- +SET @c := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema=@schema AND table_name='markdown' AND column_name='last_modified_by'); +SET @ddl := IF(@c=0, + 'ALTER TABLE markdown ADD COLUMN last_modified_by VARCHAR(255) NULL', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +UPDATE markdown SET last_modified_by = 'admin' WHERE last_modified_by IS NULL; + +-- markdown_patch.author ----------------------------------------------------- +SET @c := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema=@schema AND table_name='markdown_patch' AND column_name='author'); +SET @ddl := IF(@c=0, + 'ALTER TABLE markdown_patch ADD COLUMN author VARCHAR(255) NULL', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +UPDATE markdown_patch SET author = 'admin' WHERE author IS NULL; + +-- markdown_patch.last_modified_by ------------------------------------------- +SET @c := (SELECT COUNT(*) FROM information_schema.columns + WHERE table_schema=@schema AND table_name='markdown_patch' AND column_name='last_modified_by'); +SET @ddl := IF(@c=0, + 'ALTER TABLE markdown_patch ADD COLUMN last_modified_by VARCHAR(255) NULL', + 'DO 0'); +PREPARE st FROM @ddl; EXECUTE st; DEALLOCATE PREPARE st; +UPDATE markdown_patch SET last_modified_by = 'admin' WHERE last_modified_by IS NULL;