Files
xiaoxia-saas/alembic/versions/001_initial_schema.py
T
Xiaoxia AI b43cdcadc5 feat: add Alembic database migrations
- alembic.ini: Alembic configuration
- alembic/env.py: migration environment with Base import
- alembic/versions/001_initial_schema.py: initial schema migration (projects, asset_libraries, assets, ingest_jobs)
- alembic/README.md: migration usage guide
- all 7 integration tests still passing
2026-06-15 15:33:01 +08:00

91 lines
3.8 KiB
Python

"""Initial schema
Revision ID: 001
Revises:
Create Date: 2026-06-15
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
# revision identifiers, used by Alembic.
revision: str = '001'
down_revision: Union[str, None] = None
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# Create projects table
op.create_table(
'projects',
sa.Column('id', sa.String(32), nullable=False),
sa.Column('workspace_id', sa.String(32), nullable=False),
sa.Column('name', sa.String(100), nullable=False),
sa.Column('description', sa.Text(), nullable=False, server_default=''),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_projects_workspace_id'), 'projects', ['workspace_id'], unique=False)
# Create asset_libraries table
op.create_table(
'asset_libraries',
sa.Column('id', sa.String(32), nullable=False),
sa.Column('workspace_id', sa.String(32), nullable=False),
sa.Column('project_id', sa.String(32), nullable=False),
sa.Column('name', sa.String(100), nullable=False),
sa.Column('kind', sa.String(20), nullable=False),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_asset_libraries_workspace_id'), 'asset_libraries', ['workspace_id'], unique=False)
op.create_index(op.f('ix_asset_libraries_project_id'), 'asset_libraries', ['project_id'], unique=False)
# Create assets table
op.create_table(
'assets',
sa.Column('id', sa.String(32), nullable=False),
sa.Column('workspace_id', sa.String(32), nullable=False),
sa.Column('project_id', sa.String(32), nullable=False),
sa.Column('library_id', sa.String(32), nullable=False),
sa.Column('name', sa.String(100), nullable=False),
sa.Column('storage_key', sa.String(255), nullable=False),
sa.Column('mime_type', sa.String(100), nullable=False),
sa.Column('metadata_json', sa.Text(), nullable=False, server_default='{}'),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_assets_workspace_id'), 'assets', ['workspace_id'], unique=False)
op.create_index(op.f('ix_assets_project_id'), 'assets', ['project_id'], unique=False)
op.create_index(op.f('ix_assets_library_id'), 'assets', ['library_id'], unique=False)
# Create ingest_jobs table
op.create_table(
'ingest_jobs',
sa.Column('id', sa.String(32), nullable=False),
sa.Column('workspace_id', sa.String(32), nullable=False),
sa.Column('project_id', sa.String(32), nullable=False),
sa.Column('library_id', sa.String(32), nullable=False),
sa.Column('storage_key', sa.String(255), nullable=False),
sa.Column('status', sa.String(20), nullable=False, server_default='pending'),
sa.Column('error_message', sa.Text(), nullable=False, server_default=''),
sa.Column('result_asset_id', sa.String(32), nullable=False, server_default=''),
sa.Column('created_at', sa.DateTime(), nullable=False),
sa.Column('updated_at', sa.DateTime(), nullable=False),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_ingest_jobs_workspace_id'), 'ingest_jobs', ['workspace_id'], unique=False)
op.create_index(op.f('ix_ingest_jobs_project_id'), 'ingest_jobs', ['project_id'], unique=False)
op.create_index(op.f('ix_ingest_jobs_library_id'), 'ingest_jobs', ['library_id'], unique=False)
def downgrade() -> None:
op.drop_table('ingest_jobs')
op.drop_table('assets')
op.drop_table('asset_libraries')
op.drop_table('projects')