defmodule Mv.Repo.Migrations.MakeMemberUserFksDeferrable do
  @moduledoc """
  Makes the members/users foreign keys DEFERRABLE INITIALLY DEFERRED.

  Concurrent `create_member` transactions take FK `FOR KEY SHARE` (MultiXact)
  locks on these foreign keys at statement time and can form a cross-transaction
  lock cycle, producing a PostgreSQL `deadlock_detected` (40P01). Deferring the
  FK checks to commit time breaks the cycle.

  Constraint deferrability is not tracked by AshPostgres resource snapshots, so
  this is a hand-written migration with raw `execute/2`. Do not regenerate it
  via `mix ash_postgres.generate_migrations`.
  """
  use Ecto.Migration

  def change do
    execute(
      "ALTER TABLE users ALTER CONSTRAINT users_member_id_fkey DEFERRABLE INITIALLY DEFERRED",
      "ALTER TABLE users ALTER CONSTRAINT users_member_id_fkey NOT DEFERRABLE"
    )

    execute(
      "ALTER TABLE users ALTER CONSTRAINT users_role_id_fkey DEFERRABLE INITIALLY DEFERRED",
      "ALTER TABLE users ALTER CONSTRAINT users_role_id_fkey NOT DEFERRABLE"
    )

    execute(
      "ALTER TABLE members ALTER CONSTRAINT members_membership_fee_type_id_fkey DEFERRABLE INITIALLY DEFERRED",
      "ALTER TABLE members ALTER CONSTRAINT members_membership_fee_type_id_fkey NOT DEFERRABLE"
    )
  end
end
