- 迁移 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%
241 lines
15 KiB
SQL
241 lines
15 KiB
SQL
-- 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));
|