Files
creator-hub/internal/environment/migrations/044_numeric_primary_keys.sql
T
rogee 65d0801290 feat(schema): 044 数字主键——全表 bigint IDENTITY、文本标识降级 UNIQUE、FK 重指
- 迁移 044:9 张表换 bigint IDENTITY 主键,account_id/exit_id/competitor_id/work_id/comment_id/job_id/rule_id 降级 UNIQUE;
  引用表 FK 重指 bigint;checkpoint 删派生文本 id;creator_settings 布尔 PK 换 bigint identity + 单行表达式唯一索引;
  social_account.profile_id 死列删除
- seed 派生改 SQL:CreateBoundEnv 用 jsonb_set(account.id+1000),deriveSeed 删除;Fingerprint.Validate 允许 Seed=0(派生态)
- 三域 store SQL 列名适配;appendAudit/审计过滤经 JOIN 读回文本标识;UPDATE..RETURNING..FROM 拆两段式
- 对外 API 契约不变:模型/JSON/URL 全部保持文本 ID
- account 域补 PG 生命周期集成测试(列表/凭据解析/暂停吊销恢复/审计过滤/删除链路),覆盖率 22.4%→73.9%
2026-09-28 22:30:14 +08:00

241 lines
15 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
-- 044 数字主键重构:每张业务表 id bigint GENERATED ALWAYS AS IDENTITY 主键,
-- 文本业务标识降级 UNIQUE 并按语义改名;FK 全部重指 bigint id;
-- 应用层对外契约不变(API/JSON 仍用文本标识),seed 改由 bigint id + 1000 派生。
-- 依据:docs/plans/2026-09-29-schema-consolidation-and-numeric-id.md 第 3 节。
-- ============ 1) 被引用表:加 bigint 代理主键列(PG 17 IDENTITY 自动回填存量行;rename 在第 4 节)============
ALTER TABLE social_account ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE network_exit ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE gateway ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE browser_env ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_competitor ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_work ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_comment ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_competitor_share_job ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_lead_rule ADD COLUMN surrogate_id bigint GENERATED ALWAYS AS IDENTITY;
-- ============ 2) 引用表:加 bigint FK 列并按文本标识回填 ============
ALTER TABLE browser_env
ADD COLUMN gateway_row_id bigint, ADD COLUMN account_row_id bigint, ADD COLUMN exit_row_id bigint;
UPDATE browser_env b SET gateway_row_id = g.surrogate_id FROM gateway g WHERE g.name = b.gateway_name;
UPDATE browser_env b SET account_row_id = s.surrogate_id FROM social_account s WHERE s.id::text = b.account_id;
UPDATE browser_env b SET exit_row_id = n.surrogate_id FROM network_exit n WHERE n.id::text = b.network_exit_id;
ALTER TABLE audit_event
ADD COLUMN account_row_id bigint, ADD COLUMN browser_env_row_id bigint, ADD COLUMN exit_row_id bigint;
-- audit_event 是 append-only(触发器拦截 UPDATE),回填期间临时摘除。
DROP TRIGGER IF EXISTS audit_event_append_only ON audit_event;
UPDATE audit_event a SET account_row_id = s.surrogate_id FROM social_account s WHERE s.id::text = a.account_id;
UPDATE audit_event a SET browser_env_row_id = b.surrogate_id FROM browser_env b WHERE b.alias = a.browser_env_alias;
UPDATE audit_event a SET exit_row_id = n.surrogate_id FROM network_exit n WHERE n.id::text = a.network_exit_id;
ALTER TABLE creator_account_profile ADD COLUMN account_row_id bigint;
UPDATE creator_account_profile p SET account_row_id = s.surrogate_id FROM social_account s WHERE s.id::text = p.account_id;
ALTER TABLE creator_account_password ADD COLUMN account_row_id bigint;
UPDATE creator_account_password p SET account_row_id = s.surrogate_id FROM social_account s WHERE s.id::text = p.account_id;
ALTER TABLE creator_account_metric ADD COLUMN account_row_id bigint;
UPDATE creator_account_metric m SET account_row_id = s.surrogate_id FROM social_account s WHERE s.id::text = m.account_id;
ALTER TABLE creator_competitor_share_job ADD COLUMN competitor_row_id bigint;
UPDATE creator_competitor_share_job j SET competitor_row_id = c.surrogate_id FROM creator_competitor c WHERE c.id::text = j.competitor_id;
ALTER TABLE creator_work_metric ADD COLUMN work_row_id bigint;
UPDATE creator_work_metric m SET work_row_id = w.surrogate_id FROM creator_work w WHERE w.id::text = m.work_id;
ALTER TABLE creator_comment ADD COLUMN work_row_id bigint;
UPDATE creator_comment c SET work_row_id = w.surrogate_id FROM creator_work w WHERE w.id::text = c.work_id;
ALTER TABLE creator_comment_rule_result ADD COLUMN comment_row_id bigint, ADD COLUMN rule_row_id bigint;
UPDATE creator_comment_rule_result r SET comment_row_id = c.surrogate_id FROM creator_comment c WHERE c.id::text = r.comment_id;
UPDATE creator_comment_rule_result r SET rule_row_id = l.surrogate_id FROM creator_lead_rule l WHERE l.id::text = r.rule_id;
ALTER TABLE creator_work_cover ADD COLUMN work_row_id bigint;
UPDATE creator_work_cover c SET work_row_id = w.surrogate_id FROM creator_work w WHERE w.id::text = c.work_id;
-- ============ 3) 删除全部旧文本 FK(解除对旧文本主键的依赖)============
ALTER TABLE browser_env
DROP CONSTRAINT IF EXISTS browser_env_gateway_name_fkey,
DROP CONSTRAINT IF EXISTS browser_env_account_id_fkey,
DROP CONSTRAINT IF EXISTS browser_env_network_exit_id_fkey;
ALTER TABLE audit_event
DROP CONSTRAINT IF EXISTS audit_event_account_id_fkey,
DROP CONSTRAINT IF EXISTS audit_event_browser_env_alias_fkey,
DROP CONSTRAINT IF EXISTS audit_event_network_exit_id_fkey;
ALTER TABLE creator_account_profile DROP CONSTRAINT IF EXISTS creator_account_profile_account_id_fkey;
ALTER TABLE creator_account_password DROP CONSTRAINT IF EXISTS creator_account_password_account_id_fkey;
ALTER TABLE creator_account_metric DROP CONSTRAINT IF EXISTS creator_account_metric_account_id_fkey;
ALTER TABLE creator_competitor_share_job DROP CONSTRAINT IF EXISTS creator_competitor_share_job_competitor_id_fkey;
ALTER TABLE creator_work_metric DROP CONSTRAINT IF EXISTS creator_work_metric_work_id_fkey;
ALTER TABLE creator_comment DROP CONSTRAINT IF EXISTS creator_comment_work_id_fkey;
ALTER TABLE creator_comment_rule_result
DROP CONSTRAINT IF EXISTS creator_comment_rule_result_comment_id_fkey,
DROP CONSTRAINT IF EXISTS creator_comment_rule_result_rule_id_fkey;
ALTER TABLE creator_work_cover DROP CONSTRAINT IF EXISTS creator_work_cover_work_id_fkey;
-- ============ 4) 文本列名为 id 的表:先降级改名,再加 bigint 主键(PG 17 IDENTITY 自动回填存量行)============
ALTER TABLE social_account DROP CONSTRAINT social_account_pkey;
ALTER TABLE social_account RENAME COLUMN id TO account_id;
ALTER TABLE social_account RENAME COLUMN surrogate_id TO id;
ALTER TABLE social_account ADD PRIMARY KEY (id);
ALTER TABLE social_account ADD CONSTRAINT social_account_account_id_unique UNIQUE (account_id);
ALTER TABLE network_exit DROP CONSTRAINT network_exit_pkey;
ALTER TABLE network_exit RENAME COLUMN id TO exit_id;
ALTER TABLE network_exit RENAME COLUMN surrogate_id TO id;
ALTER TABLE network_exit ADD PRIMARY KEY (id);
ALTER TABLE network_exit ADD CONSTRAINT network_exit_exit_id_unique UNIQUE (exit_id);
ALTER TABLE creator_competitor DROP CONSTRAINT creator_competitor_pkey;
ALTER TABLE creator_competitor RENAME COLUMN id TO competitor_id;
ALTER TABLE creator_competitor RENAME COLUMN surrogate_id TO id;
ALTER TABLE creator_competitor ADD PRIMARY KEY (id);
ALTER TABLE creator_competitor ADD CONSTRAINT creator_competitor_competitor_id_unique UNIQUE (competitor_id);
ALTER TABLE creator_work DROP CONSTRAINT creator_work_pkey;
ALTER TABLE creator_work RENAME COLUMN id TO work_id;
ALTER TABLE creator_work RENAME COLUMN surrogate_id TO id;
ALTER TABLE creator_work ADD PRIMARY KEY (id);
ALTER TABLE creator_work ADD CONSTRAINT creator_work_work_id_unique UNIQUE (work_id);
ALTER TABLE creator_comment DROP CONSTRAINT creator_comment_pkey;
ALTER TABLE creator_comment RENAME COLUMN id TO comment_id;
ALTER TABLE creator_comment RENAME COLUMN surrogate_id TO id;
ALTER TABLE creator_comment ADD PRIMARY KEY (id);
ALTER TABLE creator_comment ADD CONSTRAINT creator_comment_comment_id_unique UNIQUE (comment_id);
ALTER TABLE creator_competitor_share_job DROP CONSTRAINT creator_competitor_share_job_pkey;
ALTER TABLE creator_competitor_share_job RENAME COLUMN id TO job_id;
ALTER TABLE creator_competitor_share_job RENAME COLUMN surrogate_id TO id;
ALTER TABLE creator_competitor_share_job ADD PRIMARY KEY (id);
ALTER TABLE creator_competitor_share_job ADD CONSTRAINT creator_competitor_share_job_job_id_unique UNIQUE (job_id);
ALTER TABLE creator_lead_rule DROP CONSTRAINT creator_lead_rule_pkey;
ALTER TABLE creator_lead_rule RENAME COLUMN id TO rule_id;
ALTER TABLE creator_lead_rule RENAME COLUMN surrogate_id TO id;
ALTER TABLE creator_lead_rule ADD PRIMARY KEY (id);
ALTER TABLE creator_lead_rule ADD CONSTRAINT creator_lead_rule_rule_id_unique UNIQUE (rule_id);
-- ============ 5) 文本主键为语义列的表:加 bigint 主键,文本列降级 UNIQUE ============
ALTER TABLE gateway DROP CONSTRAINT gateway_pkey;
ALTER TABLE gateway RENAME COLUMN surrogate_id TO id;
ALTER TABLE gateway ADD PRIMARY KEY (id);
ALTER TABLE gateway ADD CONSTRAINT gateway_name_unique UNIQUE (name);
ALTER TABLE browser_env DROP CONSTRAINT browser_env_pkey;
ALTER TABLE browser_env RENAME COLUMN surrogate_id TO id;
ALTER TABLE browser_env ADD PRIMARY KEY (id);
-- alias 原本就是 NOT NULL,降级为 UNIQUE(账号即环境下 alias = 账号文本 ID)。
ALTER TABLE browser_env ADD CONSTRAINT browser_env_alias_unique UNIQUE (alias);
-- ============ 6) 引用表换列:删文本 FK 列(连带旧 FK/PK/UNIQUE/索引),新列更名 + 补约束 ============
ALTER TABLE browser_env
DROP COLUMN gateway_name, DROP COLUMN account_id, DROP COLUMN network_exit_id;
ALTER TABLE browser_env RENAME COLUMN gateway_row_id TO gateway_id;
ALTER TABLE browser_env RENAME COLUMN account_row_id TO account_id;
ALTER TABLE browser_env RENAME COLUMN exit_row_id TO exit_id;
ALTER TABLE browser_env
ALTER COLUMN gateway_id SET NOT NULL,
ALTER COLUMN account_id SET NOT NULL,
ADD CONSTRAINT browser_env_account_id_unique UNIQUE (account_id),
ADD CONSTRAINT browser_env_account_id_fkey FOREIGN KEY (account_id) REFERENCES social_account(id) ON DELETE CASCADE,
ADD CONSTRAINT browser_env_gateway_id_fkey FOREIGN KEY (gateway_id) REFERENCES gateway(id),
ADD CONSTRAINT browser_env_exit_id_fkey FOREIGN KEY (exit_id) REFERENCES network_exit(id);
ALTER TABLE audit_event
DROP COLUMN account_id, DROP COLUMN browser_env_alias, DROP COLUMN network_exit_id;
ALTER TABLE audit_event RENAME COLUMN account_row_id TO account_id;
ALTER TABLE audit_event RENAME COLUMN browser_env_row_id TO browser_env_id;
ALTER TABLE audit_event RENAME COLUMN exit_row_id TO exit_id;
ALTER TABLE audit_event
ADD CONSTRAINT audit_event_account_id_fkey FOREIGN KEY (account_id) REFERENCES social_account(id),
ADD CONSTRAINT audit_event_browser_env_id_fkey FOREIGN KEY (browser_env_id) REFERENCES browser_env(id),
ADD CONSTRAINT audit_event_exit_id_fkey FOREIGN KEY (exit_id) REFERENCES network_exit(id);
CREATE TRIGGER audit_event_append_only
BEFORE UPDATE OR DELETE ON audit_event
FOR EACH ROW EXECUTE FUNCTION reject_audit_event_mutation();
-- social_account.profile_id 是 creator_account_profile 的悬空文本镜像(1:1 已由对方 account_id 表达),删除。
ALTER TABLE social_account DROP COLUMN profile_id;
ALTER TABLE creator_account_profile
DROP CONSTRAINT creator_account_profile_pkey, DROP COLUMN account_id;
ALTER TABLE creator_account_profile RENAME COLUMN account_row_id TO account_id;
ALTER TABLE creator_account_profile
ALTER COLUMN account_id SET NOT NULL,
ADD PRIMARY KEY (account_id),
ADD CONSTRAINT creator_account_profile_account_id_fkey FOREIGN KEY (account_id) REFERENCES social_account(id) ON DELETE CASCADE;
ALTER TABLE creator_account_password
DROP CONSTRAINT creator_account_password_pkey, DROP COLUMN account_id;
ALTER TABLE creator_account_password RENAME COLUMN account_row_id TO account_id;
ALTER TABLE creator_account_password
ALTER COLUMN account_id SET NOT NULL,
ADD PRIMARY KEY (account_id),
ADD CONSTRAINT creator_account_password_account_id_fkey FOREIGN KEY (account_id) REFERENCES social_account(id) ON DELETE CASCADE;
DROP INDEX IF EXISTS creator_account_metric_account_idx;
ALTER TABLE creator_account_metric DROP COLUMN account_id;
ALTER TABLE creator_account_metric RENAME COLUMN account_row_id TO account_id;
ALTER TABLE creator_account_metric
ADD CONSTRAINT creator_account_metric_account_collected_unique UNIQUE (account_id, collected_at),
ADD CONSTRAINT creator_account_metric_account_id_fkey FOREIGN KEY (account_id) REFERENCES social_account(id) ON DELETE CASCADE;
CREATE INDEX IF NOT EXISTS creator_account_metric_account_collected_idx ON creator_account_metric (account_id, collected_at);
ALTER TABLE creator_competitor_share_job DROP COLUMN competitor_id;
ALTER TABLE creator_competitor_share_job RENAME COLUMN competitor_row_id TO competitor_id;
ALTER TABLE creator_competitor_share_job
ADD CONSTRAINT creator_competitor_share_job_competitor_id_fkey
FOREIGN KEY (competitor_id) REFERENCES creator_competitor(id) ON DELETE SET NULL;
ALTER TABLE creator_work_metric DROP COLUMN work_id;
ALTER TABLE creator_work_metric RENAME COLUMN work_row_id TO work_id;
ALTER TABLE creator_work_metric
ALTER COLUMN work_id SET NOT NULL,
ADD CONSTRAINT creator_work_metric_work_collected_unique UNIQUE (work_id, collected_at),
ADD CONSTRAINT creator_work_metric_work_id_fkey FOREIGN KEY (work_id) REFERENCES creator_work(id) ON DELETE CASCADE;
ALTER TABLE creator_comment DROP COLUMN work_id;
ALTER TABLE creator_comment RENAME COLUMN work_row_id TO work_id;
ALTER TABLE creator_comment
ALTER COLUMN work_id SET NOT NULL,
ADD CONSTRAINT creator_comment_work_id_fkey FOREIGN KEY (work_id) REFERENCES creator_work(id) ON DELETE CASCADE;
CREATE INDEX IF NOT EXISTS creator_comment_work_idx ON creator_comment (work_id, published_at DESC);
ALTER TABLE creator_comment_rule_result
DROP CONSTRAINT creator_comment_rule_result_pkey,
DROP COLUMN comment_id, DROP COLUMN rule_id;
ALTER TABLE creator_comment_rule_result RENAME COLUMN comment_row_id TO comment_id;
ALTER TABLE creator_comment_rule_result RENAME COLUMN rule_row_id TO rule_id;
ALTER TABLE creator_comment_rule_result
ALTER COLUMN comment_id SET NOT NULL,
ALTER COLUMN rule_id SET NOT NULL,
ADD PRIMARY KEY (comment_id, rule_id),
ADD CONSTRAINT creator_comment_rule_result_comment_id_fkey FOREIGN KEY (comment_id) REFERENCES creator_comment(id) ON DELETE CASCADE,
ADD CONSTRAINT creator_comment_rule_result_rule_id_fkey FOREIGN KEY (rule_id) REFERENCES creator_lead_rule(id) ON DELETE CASCADE;
ALTER TABLE creator_work_cover
DROP CONSTRAINT creator_work_cover_pkey, DROP COLUMN work_id;
ALTER TABLE creator_work_cover RENAME COLUMN work_row_id TO work_id;
ALTER TABLE creator_work_cover
ALTER COLUMN work_id SET NOT NULL,
ADD PRIMARY KEY (work_id, variant),
ADD CONSTRAINT creator_work_cover_work_id_fkey FOREIGN KEY (work_id) REFERENCES creator_work(id) ON DELETE CASCADE;
-- ============ 7) creator_collection_checkpoint:文本 id 是派生值(source:sourceID:kind),无独立语义,删除;
-- 换 bigint 主键,唯一业务键保持 (source_type, source_id, collection_kind) ============
ALTER TABLE creator_collection_checkpoint
DROP CONSTRAINT creator_collection_checkpoint_pkey, DROP COLUMN id;
ALTER TABLE creator_collection_checkpoint ADD COLUMN id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_collection_checkpoint ADD PRIMARY KEY (id);
-- ============ 8) creator_settings:布尔单例行主键换 bigint identity,表达式唯一索引锁定单行 ============
ALTER TABLE creator_settings
DROP CONSTRAINT creator_settings_pkey, DROP COLUMN id;
ALTER TABLE creator_settings ADD COLUMN id bigint GENERATED ALWAYS AS IDENTITY;
ALTER TABLE creator_settings ADD PRIMARY KEY (id);
CREATE UNIQUE INDEX creator_settings_singleton_idx ON creator_settings ((true));