diff --git a/lib/phoenix_kit/migrations/postgres/v77.ex b/lib/phoenix_kit/migrations/postgres/v77.ex index 614d002e..9dc83a70 100644 --- a/lib/phoenix_kit/migrations/postgres/v77.ex +++ b/lib/phoenix_kit/migrations/postgres/v77.ex @@ -35,7 +35,7 @@ defmodule PhoenixKit.Migrations.Postgres.V77 do rename_setting(table, "tickets_allow_reopen", "customer_service_allow_reopen") rename_setting(table, "auto_granted_perm:tickets", "auto_granted_perm:customer_service") - rename_role_permission(perms_table, "tickets", "customer_service") + rename_role_permission(perms_table, "tickets", "customer_service", prefix) execute("COMMENT ON TABLE #{prefix_str(prefix)}phoenix_kit IS '77'") end @@ -57,22 +57,47 @@ defmodule PhoenixKit.Migrations.Postgres.V77 do # Renames role permission module_key. If target already exists for the same role, # deletes the source row to avoid unique constraint violations. - defp rename_role_permission(table, from_key, to_key) do + # Dynamically detects whether uuid/role_uuid columns exist (V56 may have skipped them) + # and falls back to id/role_id when they don't. + defp rename_role_permission(table, from_key, to_key, prefix) do + schema = prefix || "public" + execute(""" DO $$ DECLARE + has_role_uuid BOOLEAN; r RECORD; BEGIN - FOR r IN SELECT uuid, role_uuid FROM #{table} WHERE module_key = '#{from_key}' LOOP - IF EXISTS ( - SELECT 1 FROM #{table} - WHERE module_key = '#{to_key}' AND role_uuid = r.role_uuid - ) THEN - DELETE FROM #{table} WHERE uuid = r.uuid; - ELSE - UPDATE #{table} SET module_key = '#{to_key}' WHERE uuid = r.uuid; - END IF; - END LOOP; + SELECT EXISTS ( + SELECT 1 FROM information_schema.columns + WHERE table_schema = '#{schema}' + AND table_name = 'phoenix_kit_role_permissions' + AND column_name = 'role_uuid' + ) INTO has_role_uuid; + + IF has_role_uuid THEN + FOR r IN SELECT uuid, role_uuid FROM #{table} WHERE module_key = '#{from_key}' LOOP + IF EXISTS ( + SELECT 1 FROM #{table} + WHERE module_key = '#{to_key}' AND role_uuid = r.role_uuid + ) THEN + DELETE FROM #{table} WHERE uuid = r.uuid; + ELSE + UPDATE #{table} SET module_key = '#{to_key}' WHERE uuid = r.uuid; + END IF; + END LOOP; + ELSE + FOR r IN SELECT id, role_id FROM #{table} WHERE module_key = '#{from_key}' LOOP + IF EXISTS ( + SELECT 1 FROM #{table} + WHERE module_key = '#{to_key}' AND role_id = r.role_id + ) THEN + DELETE FROM #{table} WHERE id = r.id; + ELSE + UPDATE #{table} SET module_key = '#{to_key}' WHERE id = r.id; + END IF; + END LOOP; + END IF; END $$; """) end @@ -81,7 +106,7 @@ defmodule PhoenixKit.Migrations.Postgres.V77 do table = "#{prefix_str(prefix)}phoenix_kit_settings" perms_table = "#{prefix_str(prefix)}phoenix_kit_role_permissions" - rename_role_permission(perms_table, "customer_service", "tickets") + rename_role_permission(perms_table, "customer_service", "tickets", prefix) rename_setting(table, "auto_granted_perm:customer_service", "auto_granted_perm:tickets") rename_setting(table, "customer_service_allow_reopen", "tickets_allow_reopen") rename_setting(table, "customer_service_attachments_enabled", "tickets_attachments_enabled") diff --git a/lib/phoenix_kit/migrations/postgres/v78.ex b/lib/phoenix_kit/migrations/postgres/v78.ex index d91fbebd..80d085dd 100644 --- a/lib/phoenix_kit/migrations/postgres/v78.ex +++ b/lib/phoenix_kit/migrations/postgres/v78.ex @@ -37,6 +37,12 @@ defmodule PhoenixKit.Migrations.Postgres.V78 do ) if table_exists?(:phoenix_kit_ai_prompts, prefix) do + # V56 may have skipped adding the uuid column to ai_prompts if the table + # didn't exist at V56 time. Ensure it exists before creating the FK. + unless column_exists?(:phoenix_kit_ai_prompts, :uuid, prefix) do + ensure_uuid_column_and_index(:phoenix_kit_ai_prompts, prefix) + end + execute """ DO $$ BEGIN @@ -113,6 +119,48 @@ defmodule PhoenixKit.Migrations.Postgres.V78 do exists end + defp column_exists?(table_name, column_name, prefix) do + query = """ + SELECT EXISTS ( + SELECT FROM information_schema.columns + WHERE table_schema = '#{prefix}' + AND table_name = '#{table_name}' + AND column_name = '#{column_name}' + ) + """ + + %{rows: [[exists]]} = PhoenixKit.RepoHelper.repo().query!(query) + exists + end + + # Replicates V56's idempotent pattern for adding a uuid column with + # backfill, NOT NULL constraint, and unique index. + defp ensure_uuid_column_and_index(table_name, prefix) do + full_table = "#{prefix_str(prefix)}#{table_name}" + index_name = "#{table_name}_uuid_index" + + execute(""" + ALTER TABLE #{full_table} + ADD COLUMN IF NOT EXISTS uuid UUID DEFAULT uuid_generate_v7() + """) + + execute(""" + UPDATE #{full_table} + SET uuid = uuid_generate_v7() + WHERE uuid IS NULL + """) + + execute(""" + ALTER TABLE #{full_table} + ALTER COLUMN uuid SET NOT NULL + """) + + execute(""" + CREATE UNIQUE INDEX IF NOT EXISTS #{index_name} + ON #{full_table}(uuid) + """) + end + defp prefix_str("public"), do: "public." defp prefix_str(prefix), do: "#{prefix}." end