# had to disable these to be able to restore `following` index concurrently
# https://hexdocs.pm/ecto_sql/Ecto.Migration.html#index/3-adding-dropping-indexes-concurrently
- @disable_ddl_transaction true
- @disable_migration_lock true
def change do
create_if_not_exists table(:following_relationships) do
create_if_not_exists(index(:following_relationships, :follower_id))
create_if_not_exists(unique_index(:following_relationships, [:follower_id, :following_id]))
-
- execute(import_following_from_users(), "")
- execute(import_following_from_activities(), restore_following_column())
-
- drop(index(:users, [:following], concurrently: true, using: :gin))
-
- alter table(:users) do
- remove(:following, {:array, :string}, default: [])
- end
- end
-
- defp import_following_from_users do
- """
- INSERT INTO following_relationships (follower_id, following_id, state, inserted_at, updated_at)
- SELECT
- relations.follower_id,
- following.id,
- 'accept',
- now(),
- now()
- FROM (
- SELECT
- users.id AS follower_id,
- unnest(users.following) AS following_ap_id
- FROM
- users
- WHERE
- users.following != '{}'
- AND users.local = false OR users.local = true AND users.email IS NOT NULL -- Exclude `internal/fetch` and `relay`
- ) AS relations
- JOIN users AS "following" ON "following".follower_address = relations.following_ap_id
-
- WHERE relations.follower_id != following.id
- ON CONFLICT DO NOTHING
- """
- end
-
- defp import_following_from_activities do
- """
- INSERT INTO
- following_relationships (
- follower_id,
- following_id,
- state,
- inserted_at,
- updated_at
- )
- SELECT
- followers.id,
- following.id,
- activities.data ->> 'state',
- (activities.data ->> 'published') :: timestamp,
- now()
- FROM
- activities
- JOIN users AS followers ON (activities.actor = followers.ap_id)
- JOIN users AS following ON (activities.data ->> 'object' = following.ap_id)
- WHERE
- activities.data ->> 'type' = 'Follow'
- AND activities.data ->> 'state' IN ('accept', 'pending', 'reject')
- ORDER BY activities.updated_at DESC
- ON CONFLICT DO NOTHING
- """
- end
-
- defp restore_following_column do
- """
- UPDATE
- users
- SET
- following = following_query.following_array,
- updated_at = now()
- FROM (
- SELECT
- follwer.id AS follower_id,
- CASE follwer.local
- WHEN TRUE THEN
- array_prepend(follwer.follower_address, array_agg(following.follower_address))
- ELSE
- array_agg(following.follower_address)
- END AS following_array
- FROM
- following_relationships
- JOIN users AS follwer ON follwer.id = following_relationships.follower_id
- JOIN users AS FOLLOWING ON following.id = following_relationships.following_id
- GROUP BY
- follwer.id) AS following_query
- WHERE
- following_query.follower_id = users.id
- """
end
end
--- /dev/null
+defmodule Pleroma.Repo.Migrations.MigrateFollowingRelationships do
+ use Ecto.Migration
+
+ def change do
+ execute(import_following_from_users(), "")
+ execute(import_following_from_activities(), restore_following_column())
+ end
+
+ defp import_following_from_users do
+ """
+ INSERT INTO following_relationships (follower_id, following_id, state, inserted_at, updated_at)
+ SELECT
+ relations.follower_id,
+ following.id,
+ 'accept',
+ now(),
+ now()
+ FROM (
+ SELECT
+ users.id AS follower_id,
+ unnest(users.following) AS following_ap_id
+ FROM
+ users
+ WHERE
+ users.following != '{}'
+ AND users.local = false OR users.local = true AND users.email IS NOT NULL -- Exclude `internal/fetch` and `relay`
+ ) AS relations
+ JOIN users AS "following" ON "following".follower_address = relations.following_ap_id
+
+ WHERE relations.follower_id != following.id
+ ON CONFLICT DO NOTHING
+ """
+ end
+
+ defp import_following_from_activities do
+ """
+ INSERT INTO
+ following_relationships (
+ follower_id,
+ following_id,
+ state,
+ inserted_at,
+ updated_at
+ )
+ SELECT
+ followers.id,
+ following.id,
+ activities.data ->> 'state',
+ (activities.data ->> 'published') :: timestamp,
+ now()
+ FROM
+ activities
+ JOIN users AS followers ON (activities.actor = followers.ap_id)
+ JOIN users AS following ON (activities.data ->> 'object' = following.ap_id)
+ WHERE
+ activities.data ->> 'type' = 'Follow'
+ AND activities.data ->> 'state' IN ('accept', 'pending', 'reject')
+ ORDER BY activities.updated_at DESC
+ ON CONFLICT DO NOTHING
+ """
+ end
+
+ defp restore_following_column do
+ """
+ UPDATE
+ users
+ SET
+ following = following_query.following_array,
+ updated_at = now()
+ FROM (
+ SELECT
+ follwer.id AS follower_id,
+ CASE follwer.local
+ WHEN TRUE THEN
+ array_prepend(follwer.follower_address, array_agg(following.follower_address))
+ ELSE
+ array_agg(following.follower_address)
+ END AS following_array
+ FROM
+ following_relationships
+ JOIN users AS follwer ON follwer.id = following_relationships.follower_id
+ JOIN users AS FOLLOWING ON following.id = following_relationships.following_id
+ GROUP BY
+ follwer.id) AS following_query
+ WHERE
+ following_query.follower_id = users.id
+ """
+ end
+end