Skip to content

Commit 06b5001

Browse files
ddonclaude
andcommitted
Simplify V77/V78 migrations — remove over-engineered column detection
V77: replace information_schema role_uuid detection + duplicated PL/pgSQL loops with a simple DELETE+UPDATE using role_id (always present as the original column). V78: remove separate column_exists? check — ensure_uuid_column is fully idempotent (ADD COLUMN IF NOT EXISTS, WHERE uuid IS NULL), so pre-checking is unnecessary. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b5901e2 commit 06b5001

2 files changed

Lines changed: 22 additions & 72 deletions

File tree

lib/phoenix_kit/migrations/postgres/v77.ex

Lines changed: 12 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -57,47 +57,21 @@ defmodule PhoenixKit.Migrations.Postgres.V77 do
5757

5858
# Renames role permission module_key. If target already exists for the same role,
5959
# deletes the source row to avoid unique constraint violations.
60-
# Dynamically detects whether uuid/role_uuid columns exist (V56 may have skipped them)
61-
# and falls back to id/role_id when they don't.
62-
defp rename_role_permission(table, from_key, to_key, prefix) do
63-
schema = prefix || "public"
64-
60+
# Uses role_id (always present, original column) for duplicate detection.
61+
defp rename_role_permission(table, from_key, to_key, _prefix) do
6562
execute("""
6663
DO $$
67-
DECLARE
68-
has_role_uuid BOOLEAN;
69-
r RECORD;
7064
BEGIN
71-
SELECT EXISTS (
72-
SELECT 1 FROM information_schema.columns
73-
WHERE table_schema = '#{schema}'
74-
AND table_name = 'phoenix_kit_role_permissions'
75-
AND column_name = 'role_uuid'
76-
) INTO has_role_uuid;
77-
78-
IF has_role_uuid THEN
79-
FOR r IN SELECT uuid, role_uuid FROM #{table} WHERE module_key = '#{from_key}' LOOP
80-
IF EXISTS (
81-
SELECT 1 FROM #{table}
82-
WHERE module_key = '#{to_key}' AND role_uuid = r.role_uuid
83-
) THEN
84-
DELETE FROM #{table} WHERE uuid = r.uuid;
85-
ELSE
86-
UPDATE #{table} SET module_key = '#{to_key}' WHERE uuid = r.uuid;
87-
END IF;
88-
END LOOP;
89-
ELSE
90-
FOR r IN SELECT id, role_id FROM #{table} WHERE module_key = '#{from_key}' LOOP
91-
IF EXISTS (
92-
SELECT 1 FROM #{table}
93-
WHERE module_key = '#{to_key}' AND role_id = r.role_id
94-
) THEN
95-
DELETE FROM #{table} WHERE id = r.id;
96-
ELSE
97-
UPDATE #{table} SET module_key = '#{to_key}' WHERE id = r.id;
98-
END IF;
99-
END LOOP;
100-
END IF;
65+
-- Delete source rows where target already exists for the same role
66+
DELETE FROM #{table} src
67+
WHERE src.module_key = '#{from_key}'
68+
AND EXISTS (
69+
SELECT 1 FROM #{table} tgt
70+
WHERE tgt.module_key = '#{to_key}' AND tgt.role_id = src.role_id
71+
);
72+
73+
-- Rename remaining rows
74+
UPDATE #{table} SET module_key = '#{to_key}' WHERE module_key = '#{from_key}';
10175
END $$;
10276
""")
10377
end

lib/phoenix_kit/migrations/postgres/v78.ex

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,9 @@ defmodule PhoenixKit.Migrations.Postgres.V78 do
3737
)
3838

3939
if table_exists?(:phoenix_kit_ai_prompts, prefix) do
40-
# V56 may have skipped adding the uuid column to ai_prompts if the table
41-
# didn't exist at V56 time. Ensure it exists before creating the FK.
42-
unless column_exists?(:phoenix_kit_ai_prompts, :uuid, prefix) do
43-
ensure_uuid_column_and_index(:phoenix_kit_ai_prompts, prefix)
44-
end
40+
# V56 skips tables that don't exist yet, so ai_prompts may lack a uuid
41+
# column if the AI module was enabled after V56 ran. Ensure it exists.
42+
ensure_uuid_column(:phoenix_kit_ai_prompts, prefix)
4543

4644
execute """
4745
DO $$
@@ -119,45 +117,23 @@ defmodule PhoenixKit.Migrations.Postgres.V78 do
119117
exists
120118
end
121119

122-
defp column_exists?(table_name, column_name, prefix) do
123-
query = """
124-
SELECT EXISTS (
125-
SELECT FROM information_schema.columns
126-
WHERE table_schema = '#{prefix}'
127-
AND table_name = '#{table_name}'
128-
AND column_name = '#{column_name}'
129-
)
130-
"""
131-
132-
%{rows: [[exists]]} = PhoenixKit.RepoHelper.repo().query!(query)
133-
exists
134-
end
135-
136-
# Replicates V56's idempotent pattern for adding a uuid column with
137-
# backfill, NOT NULL constraint, and unique index.
138-
defp ensure_uuid_column_and_index(table_name, prefix) do
120+
# Idempotently adds uuid column + backfill + NOT NULL + unique index.
121+
# All statements use IF NOT EXISTS / IF NULL guards, safe to run on tables
122+
# that already have the column.
123+
defp ensure_uuid_column(table_name, prefix) do
139124
full_table = "#{prefix_str(prefix)}#{table_name}"
140-
index_name = "#{table_name}_uuid_index"
141125

142126
execute("""
143127
ALTER TABLE #{full_table}
144128
ADD COLUMN IF NOT EXISTS uuid UUID DEFAULT uuid_generate_v7()
145129
""")
146130

147-
execute("""
148-
UPDATE #{full_table}
149-
SET uuid = uuid_generate_v7()
150-
WHERE uuid IS NULL
151-
""")
131+
execute("UPDATE #{full_table} SET uuid = uuid_generate_v7() WHERE uuid IS NULL")
152132

153-
execute("""
154-
ALTER TABLE #{full_table}
155-
ALTER COLUMN uuid SET NOT NULL
156-
""")
133+
execute("ALTER TABLE #{full_table} ALTER COLUMN uuid SET NOT NULL")
157134

158135
execute("""
159-
CREATE UNIQUE INDEX IF NOT EXISTS #{index_name}
160-
ON #{full_table}(uuid)
136+
CREATE UNIQUE INDEX IF NOT EXISTS #{table_name}_uuid_index ON #{full_table}(uuid)
161137
""")
162138
end
163139

0 commit comments

Comments
 (0)