From 17a6a6eadac3cb0a2ce7077a321204cc7b4d3c67 Mon Sep 17 00:00:00 2001 From: Thomas Citharel Date: Thu, 22 Apr 2021 17:48:43 +0200 Subject: [PATCH] Add an unique index on addresses url Signed-off-by: Thomas Citharel --- lib/mobilizon/addresses/address.ex | 1 + .../20210422140923_cleanup_addresses.exs | 75 +++++++++++++++++++ .../20210422155913_add_index_to_addresses.exs | 11 +++ 3 files changed, 87 insertions(+) create mode 100644 priv/repo/migrations/20210422140923_cleanup_addresses.exs create mode 100644 priv/repo/migrations/20210422155913_add_index_to_addresses.exs diff --git a/lib/mobilizon/addresses/address.ex b/lib/mobilizon/addresses/address.ex index c2d71bb20..7485ee7a9 100644 --- a/lib/mobilizon/addresses/address.ex +++ b/lib/mobilizon/addresses/address.ex @@ -63,6 +63,7 @@ defmodule Mobilizon.Addresses.Address do |> cast(attrs, @attrs) |> set_url() |> validate_required(@required_attrs) + |> unique_constraint(:url, name: :addresses_url_index) end @spec set_url(Ecto.Changeset.t()) :: Ecto.Changeset.t() diff --git a/priv/repo/migrations/20210422140923_cleanup_addresses.exs b/priv/repo/migrations/20210422140923_cleanup_addresses.exs new file mode 100644 index 000000000..695122595 --- /dev/null +++ b/priv/repo/migrations/20210422140923_cleanup_addresses.exs @@ -0,0 +1,75 @@ +defmodule Mobilizon.Storage.Repo.Migrations.CleanupAddresses do + use Ecto.Migration + + def up do + # Make sure we don't have any duplicate addresses + rows = fetch_bad_rows() + Enum.each(rows, &process_row/1) + + flush() + end + + def down do + # No way down + end + + defp fetch_bad_rows() do + %Postgrex.Result{rows: rows} = + Ecto.Adapters.SQL.query!( + Mobilizon.Storage.Repo, + "SELECT * FROM ( + SELECT id, url, + ROW_NUMBER() OVER(PARTITION BY url ORDER BY id asc) AS Row + FROM addresses + ) dups + WHERE dups.Row > 1;" + ) + + rows + end + + defp process_row([id, url, _row]) do + first_id = find_first_address_id(url) + + if id != first_id do + repair_events(id, first_id) + repair_actors(id, first_id) + delete_row(id) + end + end + + defp find_first_address_id(url) do + %Postgrex.Result{rows: [[id]]} = + Ecto.Adapters.SQL.query!( + Mobilizon.Storage.Repo, + "SELECT id FROM addresses WHERE url = $1 order by id asc limit 1", + [url] + ) + + id + end + + defp repair_events(id, first_id) do + Ecto.Adapters.SQL.query!( + Mobilizon.Storage.Repo, + "UPDATE events SET physical_address_id = $1 WHERE physical_address_id = $2", + [first_id, id] + ) + end + + defp repair_actors(id, first_id) do + Ecto.Adapters.SQL.query!( + Mobilizon.Storage.Repo, + "UPDATE actors SET physical_address_id = $1 WHERE physical_address_id = $2", + [first_id, id] + ) + end + + defp delete_row(id) do + Ecto.Adapters.SQL.query!( + Mobilizon.Storage.Repo, + "DELETE FROM addresses WHERE id = $1", + [id] + ) + end +end diff --git a/priv/repo/migrations/20210422155913_add_index_to_addresses.exs b/priv/repo/migrations/20210422155913_add_index_to_addresses.exs new file mode 100644 index 000000000..1a08a28fd --- /dev/null +++ b/priv/repo/migrations/20210422155913_add_index_to_addresses.exs @@ -0,0 +1,11 @@ +defmodule Mobilizon.Storage.Repo.Migrations.AddIndexToAddresses do + use Ecto.Migration + + def up do + create_if_not_exists(unique_index("addresses", [:url])) + end + + def down do + drop_if_exists(index("addresses", [:url])) + end +end