diff --git a/alembic/versions/001_initial_schema.py b/alembic/versions/001_initial_schema.py index db2021f..462ee59 100644 --- a/alembic/versions/001_initial_schema.py +++ b/alembic/versions/001_initial_schema.py @@ -21,18 +21,25 @@ depends_on: Union[str, Sequence[str], None] = None def upgrade() -> None: - # ── Enum types ──────────────────────────────────────────────────────── - billing_tier = postgresql.ENUM( - "free", "pro", "power", "team", name="billing_tier", create_type=False - ) - plugin_status = postgresql.ENUM( - "pending_review", "approved", "rejected", name="plugin_status", create_type=False - ) - review_decision = postgresql.ENUM( - "approved", "rejected", name="review_decision", create_type=False - ) - for enum in (billing_tier, plugin_status, review_decision): - enum.create(op.get_bind(), checkfirst=True) + # ── Enum types — idempotent creation via exception handling ─────────── + op.execute(""" + DO $$ BEGIN + CREATE TYPE billing_tier AS ENUM ('free', 'pro', 'power', 'team'); + EXCEPTION WHEN duplicate_object THEN NULL; + END $$; + """) + op.execute(""" + DO $$ BEGIN + CREATE TYPE plugin_status AS ENUM ('pending_review', 'approved', 'rejected'); + EXCEPTION WHEN duplicate_object THEN NULL; + END $$; + """) + op.execute(""" + DO $$ BEGIN + CREATE TYPE review_decision AS ENUM ('approved', 'rejected'); + EXCEPTION WHEN duplicate_object THEN NULL; + END $$; + """) # ── users ───────────────────────────────────────────────────────────── op.create_table( @@ -40,7 +47,7 @@ def upgrade() -> None: sa.Column("id", postgresql.UUID(as_uuid=False), nullable=False), sa.Column("email", sa.String(255), nullable=False), sa.Column("password_hash", sa.String(255), nullable=False), - sa.Column("tier", sa.Enum("free", "pro", "power", "team", name="billing_tier", create_type=False), nullable=False, server_default="free"), + sa.Column("tier", postgresql.ENUM("free", "pro", "power", "team", name="billing_tier", create_type=False), nullable=False, server_default="free"), sa.Column("stripe_customer_id", sa.String(255), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("updated_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), @@ -70,7 +77,7 @@ def upgrade() -> None: sa.Column("id", postgresql.UUID(as_uuid=False), nullable=False), sa.Column("user_id", postgresql.UUID(as_uuid=False), nullable=False), sa.Column("stripe_subscription_id", sa.String(255), nullable=True), - sa.Column("tier", sa.Enum("free", "pro", "power", "team", name="billing_tier", create_type=False), nullable=False, server_default="free"), + sa.Column("tier", postgresql.ENUM("free", "pro", "power", "team", name="billing_tier", create_type=False), nullable=False, server_default="free"), sa.Column("status", sa.String(50), nullable=False, server_default="free"), sa.Column("current_period_end", sa.DateTime(timezone=True), nullable=True), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), @@ -125,7 +132,7 @@ def upgrade() -> None: sa.Column("category", sa.String(100), nullable=False, server_default=""), sa.Column("price_cents", sa.Integer, nullable=False, server_default="0"), sa.Column("permissions", sa.Text, nullable=False, server_default="[]"), - sa.Column("status", sa.Enum("pending_review", "approved", "rejected", name="plugin_status", create_type=False), nullable=False, server_default="pending_review"), + sa.Column("status", postgresql.ENUM("pending_review", "approved", "rejected", name="plugin_status", create_type=False), nullable=False, server_default="pending_review"), sa.Column("s3_package_key", sa.String(500), nullable=True), sa.Column("install_count", sa.Integer, nullable=False, server_default="0"), sa.Column("avg_rating", sa.Float, nullable=False, server_default="0.0"), @@ -157,7 +164,7 @@ def upgrade() -> None: sa.Column("id", postgresql.UUID(as_uuid=False), nullable=False), sa.Column("plugin_id", sa.String(255), nullable=False), sa.Column("reviewer_id", postgresql.UUID(as_uuid=False), nullable=True), - sa.Column("decision", sa.Enum("approved", "rejected", name="review_decision", create_type=False), nullable=False), + sa.Column("decision", postgresql.ENUM("approved", "rejected", name="review_decision", create_type=False), nullable=False), sa.Column("notes", sa.Text, nullable=True), sa.Column("reviewed_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")), sa.Column("created_at", sa.DateTime(timezone=True), nullable=False, server_default=sa.text("now()")),