Packages
phoenix_kit
1.7.207
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
Current section
Files
lib/phoenix_kit/migrations/postgres/v116.ex
defmodule PhoenixKit.Migrations.Postgres.V116 do
@moduledoc """
V116: Parent reference on entity_data.
Adds a nullable self-referential `parent_uuid` column on
`phoenix_kit_entity_data`, letting each data row point at another row
of the same entity as its parent. The feature is a system field on
every entity_data row — it is always present, optional to fill, and
never removable by the user (it does not appear in
`entities.fields_definition`). Existing rows stay `parent_uuid = NULL`
and become roots; no backfill needed.
The column is nullable (roots have no parent) with **no `ON DELETE`**
cascade: parent/child linkage and same-entity scope are managed by
the `PhoenixKitEntities.EntityData` context, which runs subtree
checks inside a transaction. A DB-level cascade would bypass the
soft-delete machinery and the activity log.
Same-entity enforcement (a row's parent must share its `entity_uuid`)
is a context-layer responsibility — the self-FK has no view of
`entity_uuid`, so the changeset + context perform the lookup before
saving.
A plain b-tree index on `(parent_uuid)` covers the "list children"
query used when rendering the WordPress-style indented tree. Existing
indexes on `(entity_uuid)` and `(entity_uuid, position)` still cover
per-entity listing and manual ordering.
"""
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
if table_exists?(:phoenix_kit_entity_data, prefix) do
# Raw SQL — the Ecto.Migration `references/2` macro targets the
# `:id` column by default, but `phoenix_kit_entity_data`'s PK is
# `uuid`. Match V103's column-add shape exactly.
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = '#{schema}'
AND table_name = 'phoenix_kit_entity_data'
AND column_name = 'parent_uuid'
) THEN
ALTER TABLE #{p}phoenix_kit_entity_data
ADD COLUMN parent_uuid UUID
REFERENCES #{p}phoenix_kit_entity_data(uuid);
END IF;
END $$;
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_entity_data_parent_index
ON #{p}phoenix_kit_entity_data (parent_uuid)
""")
end
execute("COMMENT ON TABLE #{p}phoenix_kit IS '116'")
end
@doc """
Rolls V116 back by dropping the parent index and column.
**Lossy rollback:** the tree collapses — every row becomes a root and
all parent linkage is lost. Back up before rolling back in production.
"""
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
if table_exists?(:phoenix_kit_entity_data, prefix) do
execute("DROP INDEX IF EXISTS #{p}phoenix_kit_entity_data_parent_index")
execute("ALTER TABLE #{p}phoenix_kit_entity_data DROP COLUMN IF EXISTS parent_uuid")
end
execute("COMMENT ON TABLE #{p}phoenix_kit IS '115'")
end
defp table_exists?(table_name, prefix) do
query = """
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = '#{prefix}'
AND table_name = '#{table_name}'
)
"""
%{rows: [[exists]]} = PhoenixKit.RepoHelper.repo().query!(query)
exists
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end