Packages

phoenix_kit

1.7.183
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit migrations postgres v123.ex
Raw

lib/phoenix_kit/migrations/postgres/v123.ex

defmodule PhoenixKit.Migrations.Postgres.V123 do
@moduledoc """
V123: Catalogue folders — a dedicated nesting layer for organizing
catalogues on the admin catalogue index.
Creates `phoenix_kit_cat_folders` (self-nesting via `parent_uuid`) and
adds a nullable `folder_uuid` FK to `phoenix_kit_cat_catalogues` so a
catalogue can live inside a folder (NULL = unfiled / root). These folders
are their own thing — unrelated to the media-folder system
(`phoenix_kit_media_folders`) — and never appear in the media browser.
Each folder carries `position` (manual order within its parent), `status`
(soft-delete sentinel, parity with catalogues/categories), and a `data`
JSONB blob for future metadata. `parent_uuid` is `ON DELETE :nilify_all`
so a hard-deleted parent orphan-promotes its children to root rather than
cascading; `phoenix_kit_cat_catalogues.folder_uuid` is `ON DELETE SET NULL`
for the same reason (removing a folder unfiles its catalogues, never
deletes them).
Also drops the global unique index on `phoenix_kit_cat_items.sku`
(created in V87): item SKUs are **not** unique by design — the same SKU
can legitimately appear on multiple items, even within one catalogue —
so the partial unique index (`WHERE sku IS NOT NULL`) was an
over-constraint that raised on duplicate SKUs. `down/1` restores it.
All operations are idempotent (`create_if_not_exists` / `IF NOT EXISTS`
guards) so re-running on a partially-applied schema is a no-op.
"""
use Ecto.Migration
def up(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
schema = if prefix == "public", do: "public", else: prefix
create_if_not_exists table(:phoenix_kit_cat_folders,
primary_key: false,
prefix: prefix
) do
add(:uuid, :uuid, primary_key: true, default: fragment("uuid_generate_v7()"))
add(:name, :string, null: false)
add(
:parent_uuid,
references(:phoenix_kit_cat_folders,
column: :uuid,
type: :uuid,
on_delete: :nilify_all,
prefix: prefix
)
)
add(:position, :integer, null: false, default: 0)
add(:status, :string, null: false, default: "active")
add(:data, :map, null: false, default: %{})
timestamps(type: :utc_datetime)
end
# Composite index also serves parent_uuid-only lookups (leftmost
# prefix), including the self-FK.
create_if_not_exists(
index(:phoenix_kit_cat_folders, [:parent_uuid, :position], prefix: prefix)
)
create_if_not_exists(index(:phoenix_kit_cat_folders, [:status], prefix: prefix))
# Nullable folder_uuid on catalogues (idempotent — column + FK may
# already exist). NULL = unfiled (root); ON DELETE SET NULL so removing
# a folder unfiles its catalogues rather than deleting them.
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = '#{schema}'
AND table_name = 'phoenix_kit_cat_catalogues'
AND column_name = 'folder_uuid'
) THEN
ALTER TABLE #{p}phoenix_kit_cat_catalogues
ADD COLUMN folder_uuid UUID
REFERENCES #{p}phoenix_kit_cat_folders(uuid) ON DELETE SET NULL;
END IF;
END $$;
""")
create_if_not_exists(index(:phoenix_kit_cat_catalogues, [:folder_uuid], prefix: prefix))
# Item SKUs are not unique by design — drop V87's global partial unique
# index (default name `phoenix_kit_cat_items_sku_index`) so duplicate
# SKUs are accepted.
drop_if_exists(index(:phoenix_kit_cat_items, [:sku], prefix: prefix))
execute("COMMENT ON TABLE #{p}phoenix_kit IS '123'")
end
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
# Restore V87's partial unique index on cat_items.sku. (Will raise if
# duplicate SKUs were created while V123 was applied — expected when
# rolling back a constraint relaxation onto now-violating data.)
create_if_not_exists(
unique_index(:phoenix_kit_cat_items, [:sku], where: "sku IS NOT NULL", prefix: prefix)
)
drop_if_exists(index(:phoenix_kit_cat_catalogues, [:folder_uuid], prefix: prefix))
alter table(:phoenix_kit_cat_catalogues, prefix: prefix) do
remove_if_exists(:folder_uuid, :uuid)
end
drop_if_exists(table(:phoenix_kit_cat_folders, prefix: prefix))
execute("COMMENT ON TABLE #{p}phoenix_kit IS '122'")
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end