Packages

phoenix_kit

1.7.222
1.7.224 1.7.223 1.7.222 1.7.221 1.7.220 1.7.219 1.7.218 1.7.217 1.7.216 1.7.215 1.7.214 1.7.213 1.7.212 1.7.211 1.7.210 1.7.209 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 v157.ex
Raw

lib/phoenix_kit/migrations/postgres/v157.ex

defmodule PhoenixKit.Migrations.Postgres.V157 do
@moduledoc """
V157: Widen `phoenix_kit_annotations_kind_check` for the new
`"image"` kind.
PR #660 exposed Etcher 0.9's `:image` tool in the media viewer's
toolbar (`media_canvas_viewer.html.heex`) without widening the CHECK
constraint (or the schema's `@kinds`) to match — the same regression
V130's moduledoc warns about for `"marker"`. Without this, inserting
an image annotation is rejected by the DB and silently fails to
persist across a reload.
Idempotent: each `ADD CONSTRAINT` is preceded by `DROP CONSTRAINT
IF EXISTS` on the same prefixed table.
## down/1 is conditional, by necessity
Rolling back re-adds the *narrower* CHECK, and Postgres validates
every existing row when a CHECK is added. So the rollback is only
possible while no `kind = 'image'` annotation exists — once a user has
drawn one, the old constraint is not a truthful description of the
data and there is no correct way for a schema migration to assert it.
`down/1` therefore checks first and raises a message naming the row
count and the two ways forward, rather than letting the `ALTER` fail
with an opaque `23514` mid-rollback. The alternatives were both worse:
deleting or rewriting user annotations is data loss a rollback has no
business performing, and `NOT VALID` would leave a constraint that
lies about the rows already in the table.
"""
use Ecto.Migration
# The DROP IF EXISTS immediately before each ADD makes the re-add
# unconditional and safe. A `pg_constraint` existence guard would be
# wrong here: `conname` is unique per namespace, not globally, so on a
# multi-prefix install it would match another prefix's identically
# named constraint and skip the add — leaving this prefix's table with
# no kind check at all.
def up(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
execute(
"ALTER TABLE #{p}phoenix_kit_annotations DROP CONSTRAINT IF EXISTS phoenix_kit_annotations_kind_check"
)
execute("""
ALTER TABLE #{p}phoenix_kit_annotations
ADD CONSTRAINT phoenix_kit_annotations_kind_check
CHECK (kind IN ('rectangle', 'circle', 'polygon', 'freehand', 'callout', 'text', 'dimension', 'line', 'marker', 'image'))
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '157'")
end
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
# Runs before anything is queued, so no flush/1 is needed and no
# half-applied DDL can be left behind when this raises.
guard_no_image_annotations!(p)
execute(
"ALTER TABLE #{p}phoenix_kit_annotations DROP CONSTRAINT IF EXISTS phoenix_kit_annotations_kind_check"
)
execute("""
ALTER TABLE #{p}phoenix_kit_annotations
ADD CONSTRAINT phoenix_kit_annotations_kind_check
CHECK (kind IN ('rectangle', 'circle', 'polygon', 'freehand', 'callout', 'text', 'dimension', 'line', 'marker'))
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '156'")
end
defp guard_no_image_annotations!(p) do
%{rows: [[count]]} =
repo().query!("SELECT count(*) FROM #{p}phoenix_kit_annotations WHERE kind = 'image'")
if count > 0 do
raise """
Cannot roll back V157: #{count} annotation(s) with kind = 'image' exist \
in #{p}phoenix_kit_annotations.
V157 widened phoenix_kit_annotations_kind_check to allow 'image'. Rolling \
back re-adds the narrower CHECK, which Postgres validates against every \
existing row — so these rows would make the ALTER fail regardless.
To proceed, either:
1. Remove or convert them first, e.g.
DELETE FROM #{p}phoenix_kit_annotations WHERE kind = 'image';
(or UPDATE ... SET kind = 'callout' to keep the geometry), then \
re-run the rollback; or
2. Stay on V157 — the widened CHECK is a superset of V156's and is \
harmless to a host that no longer draws image annotations.
"""
end
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end