"""Add metadata columns to roles table""" from __future__ import annotations import sqlalchemy as sa from alembic import op # revision identifiers, used by Alembic. revision = "20251112_00_add_roles_metadata_columns" down_revision = "20251111_01" branch_labels = None depends_on = None ROLE_BACKFILL = ( ("admin", "Administrator", "Full platform access with user management rights."), ( "project_manager", "Project Manager", "Manage projects, scenarios, and associated data.", ), ("analyst", "Analyst", "Review dashboards and scenario outputs."), ( "viewer", "Viewer", "Read-only access to assigned projects and reports.", ), ) def upgrade() -> None: op.add_column( "roles", sa.Column("display_name", sa.String(length=128), nullable=True), ) op.add_column( "roles", sa.Column("description", sa.Text(), nullable=True), ) op.add_column( "roles", sa.Column( "created_at", sa.DateTime(timezone=True), nullable=True, server_default=sa.text("timezone('UTC', now())"), ), ) op.add_column( "roles", sa.Column( "updated_at", sa.DateTime(timezone=True), nullable=True, server_default=sa.text("timezone('UTC', now())"), ), ) connection = op.get_bind() for name, display_name, description in ROLE_BACKFILL: connection.execute( sa.text( """ UPDATE roles SET display_name = :display_name, description = COALESCE(description, :description) WHERE name = :name AND display_name IS NULL """ ), { "name": name, "display_name": display_name, "description": description, }, ) connection.execute( sa.text( """ UPDATE roles SET display_name = INITCAP(REPLACE(name, '_', ' ')) WHERE display_name IS NULL """ ) ) connection.execute( sa.text( """ UPDATE roles SET created_at = timezone('UTC', now()) WHERE created_at IS NULL """ ) ) connection.execute( sa.text( """ UPDATE roles SET updated_at = timezone('UTC', now()) WHERE updated_at IS NULL """ ) ) op.alter_column( "roles", "display_name", existing_type=sa.String(length=128), nullable=False, ) op.alter_column( "roles", "created_at", existing_type=sa.DateTime(timezone=True), nullable=False, server_default=sa.text("timezone('UTC', now())"), ) op.alter_column( "roles", "updated_at", existing_type=sa.DateTime(timezone=True), nullable=False, server_default=sa.text("timezone('UTC', now())"), ) def downgrade() -> None: op.drop_column("roles", "updated_at") op.drop_column("roles", "created_at") op.drop_column("roles", "description") op.drop_column("roles", "display_name")