"""add glue layer tables (container_relations + menu_nodes) Revision ID: i9g7d3e5f6 Revises: h8f6c2d4e5a9 Create Date: 2026-02-11 """ from alembic import op import sqlalchemy as sa revision = 'i9g7d3e5f6' down_revision = 'h8f6c2d4e5a9' branch_labels = None depends_on = None def upgrade() -> None: # --- container_relations --- op.create_table( 'container_relations', sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), sa.Column('parent_type', sa.String(32), nullable=False), sa.Column('parent_id', sa.Integer(), nullable=False), sa.Column('child_type', sa.String(32), nullable=False), sa.Column('child_id', sa.Integer(), nullable=False), sa.Column('sort_order', sa.Integer(), nullable=False, server_default='0'), sa.Column('label', sa.String(255), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True), sa.PrimaryKeyConstraint('id'), sa.UniqueConstraint( 'parent_type', 'parent_id', 'child_type', 'child_id', name='uq_container_relations_parent_child', ), ) op.create_index('ix_container_relations_parent', 'container_relations', ['parent_type', 'parent_id']) op.create_index('ix_container_relations_child', 'container_relations', ['child_type', 'child_id']) # --- menu_nodes --- op.create_table( 'menu_nodes', sa.Column('id', sa.Integer(), autoincrement=True, nullable=False), sa.Column('container_type', sa.String(32), nullable=False), sa.Column('container_id', sa.Integer(), nullable=False), sa.Column('parent_id', sa.Integer(), nullable=True), sa.Column('sort_order', sa.Integer(), nullable=False, server_default='0'), sa.Column('depth', sa.Integer(), nullable=False, server_default='0'), sa.Column('label', sa.String(255), nullable=False), sa.Column('slug', sa.String(255), nullable=True), sa.Column('href', sa.String(1024), nullable=True), sa.Column('icon', sa.String(64), nullable=True), sa.Column('feature_image', sa.Text(), nullable=True), sa.Column('created_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('updated_at', sa.DateTime(timezone=True), server_default=sa.text('now()'), nullable=False), sa.Column('deleted_at', sa.DateTime(timezone=True), nullable=True), sa.PrimaryKeyConstraint('id'), sa.ForeignKeyConstraint(['parent_id'], ['menu_nodes.id'], ondelete='SET NULL'), ) op.create_index('ix_menu_nodes_container', 'menu_nodes', ['container_type', 'container_id']) op.create_index('ix_menu_nodes_parent_id', 'menu_nodes', ['parent_id']) # --- Backfill container_relations from existing container-pattern tables --- op.execute(""" INSERT INTO container_relations (parent_type, parent_id, child_type, child_id, sort_order) SELECT 'page', container_id, 'calendar', id, 0 FROM calendars WHERE deleted_at IS NULL AND container_type = 'page' """) op.execute(""" INSERT INTO container_relations (parent_type, parent_id, child_type, child_id, sort_order) SELECT 'page', container_id, 'market', id, 0 FROM market_places WHERE deleted_at IS NULL AND container_type = 'page' """) op.execute(""" INSERT INTO container_relations (parent_type, parent_id, child_type, child_id, sort_order) SELECT 'page', container_id, 'page_config', id, 0 FROM page_configs WHERE deleted_at IS NULL AND container_type = 'page' """) # --- Backfill menu_nodes from existing menu_items + posts --- op.execute(""" INSERT INTO menu_nodes (container_type, container_id, label, slug, feature_image, sort_order) SELECT 'page', mi.post_id, p.title, p.slug, p.feature_image, mi.sort_order FROM menu_items mi JOIN posts p ON mi.post_id = p.id WHERE mi.deleted_at IS NULL """) def downgrade() -> None: op.drop_index('ix_menu_nodes_parent_id', table_name='menu_nodes') op.drop_index('ix_menu_nodes_container', table_name='menu_nodes') op.drop_table('menu_nodes') op.drop_index('ix_container_relations_child', table_name='container_relations') op.drop_index('ix_container_relations_parent', table_name='container_relations') op.drop_table('container_relations')