83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
"""initial schema (squashed)
|
||
|
||
单一迁移:pgvector + 当前全部 ORM 表(含 conversations.deleted_at 软删除);并补充 models 未声明的
|
||
story_image_intents.asset_id → assets 外键,以及每个 story 仅一条 primary intent 的唯一索引。
|
||
chapters 含 story 物化字段:markdown_compose_dirty、markdown_composed_at、reading_segments_json
|
||
(阅读片段快照,随 ORM 一并 create_all)。
|
||
|
||
已并入原 0002(stories-first:无 chapter_sections / memoir_images.section_id)与原 0003(segments.tts_audio_urls)
|
||
的语义:仅对「全新库」由 create_all 建出;**已有库不会 ALTER**。
|
||
老库缺列见 0019_align_legacy_schema(segments.audio_duration_seconds、tts_audio_urls,
|
||
conversations.deleted_at,conversation_messages.tts_audio_urls 等)。
|
||
conversation_messages 表由 ORM 在 0001 create_all 中创建(新库);老库若缺表须单独处理。
|
||
story_image_intents 无 source_span(主图回填在正文末尾,意图仅存 caption / prompt_brief 等)。
|
||
|
||
新库 / 删库重来:`alembic upgrade head`。
|
||
|
||
Revision ID: 0001_initial
|
||
Revises:
|
||
"""
|
||
|
||
from typing import Sequence, Union
|
||
|
||
from alembic import op
|
||
from sqlalchemy import text
|
||
|
||
revision: str = "0001_initial"
|
||
down_revision: Union[str, None] = None
|
||
branch_labels: Union[str, Sequence[str], None] = None
|
||
depends_on: Union[str, Sequence[str], None] = None
|
||
|
||
|
||
def _import_all_models() -> None:
|
||
from app.features.asset import models as _asset_models # noqa: F401
|
||
from app.features.auth import models as _auth_models # noqa: F401
|
||
from app.features.conversation import models as _conv_models # noqa: F401
|
||
from app.features.memory import models as _memory_models # noqa: F401
|
||
from app.features.memoir import models as _memoir_models # noqa: F401
|
||
from app.features.payment import models as _payment_models # noqa: F401
|
||
from app.features.story import models as _story_models # noqa: F401
|
||
from app.features.user import models as _user_models # noqa: F401
|
||
|
||
|
||
def upgrade() -> None:
|
||
conn = op.get_bind()
|
||
conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector"))
|
||
|
||
from app.core.db import Base
|
||
|
||
_import_all_models()
|
||
Base.metadata.create_all(bind=conn)
|
||
|
||
op.create_foreign_key(
|
||
"fk_story_image_intents_asset_id_assets",
|
||
"story_image_intents",
|
||
"assets",
|
||
["asset_id"],
|
||
["id"],
|
||
ondelete="SET NULL",
|
||
)
|
||
op.execute(
|
||
"""
|
||
CREATE UNIQUE INDEX IF NOT EXISTS uq_story_primary_image_intent
|
||
ON story_image_intents (story_id)
|
||
WHERE intent_role = 'primary'
|
||
"""
|
||
)
|
||
|
||
|
||
def downgrade() -> None:
|
||
conn = op.get_bind()
|
||
from app.core.db import Base
|
||
|
||
op.execute("DROP INDEX IF EXISTS uq_story_primary_image_intent")
|
||
op.drop_constraint(
|
||
"fk_story_image_intents_asset_id_assets",
|
||
"story_image_intents",
|
||
type_="foreignkey",
|
||
)
|
||
|
||
_import_all_models()
|
||
Base.metadata.drop_all(bind=conn)
|
||
conn.execute(text("DROP EXTENSION IF EXISTS vector"))
|