yggdrasil/migrations/002_posts.sql
xfy 179897ba6f fix(migrations): make all migrations idempotent; distinguish applied vs error
- 006: ADD COLUMN 补 IF NOT EXISTS
- 002: 5 个索引(status_published/slug_unique/post_tags_post/post_tags_tag/cover)补 IF NOT EXISTS
- migrate.sh: 区分「已应用」与「真出错」,真错误时打印输出并中止,不再静默吞掉(M6)

已验证:第二次运行全部 OK(幂等),不再出现重复对象错误。
2026-06-18 13:34:07 +08:00

41 lines
1.4 KiB
SQL

CREATE TABLE IF NOT EXISTS posts (
id SERIAL PRIMARY KEY,
author_id INT NOT NULL REFERENCES users(id) ON DELETE RESTRICT,
title VARCHAR(200) NOT NULL,
slug VARCHAR(200) NOT NULL,
summary VARCHAR(500),
content_md TEXT NOT NULL,
content_html TEXT,
cover_image VARCHAR(500),
status TEXT NOT NULL DEFAULT 'draft',
published_at TIMESTAMPTZ,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
deleted_at TIMESTAMPTZ,
CONSTRAINT posts_status_check CHECK (status IN ('draft', 'published'))
);
CREATE INDEX IF NOT EXISTS idx_posts_status_published ON posts(status, published_at DESC) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX IF NOT EXISTS idx_posts_slug_unique ON posts(slug) WHERE deleted_at IS NULL;
CREATE TABLE IF NOT EXISTS tags (
id SERIAL PRIMARY KEY,
name VARCHAR(50) UNIQUE NOT NULL
);
CREATE TABLE IF NOT EXISTS post_tags (
post_id INT NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
tag_id INT NOT NULL REFERENCES tags(id) ON DELETE CASCADE,
PRIMARY KEY (post_id, tag_id)
);
CREATE INDEX IF NOT EXISTS idx_post_tags_post ON post_tags(post_id);
CREATE INDEX IF NOT EXISTS idx_post_tags_tag ON post_tags(tag_id);
-- 为封面图添加索引
CREATE INDEX IF NOT EXISTS idx_posts_cover ON posts(cover_image) WHERE cover_image IS NOT NULL;