1 # Pleroma: A lightweight social networking server
2 # Copyright © 2017-2022 Pleroma Authors <https://pleroma.social/>
3 # SPDX-License-Identifier: AGPL-3.0-only
5 defmodule Pleroma.Repo.Migrations.UpdateCounterCacheTable do
8 @function_name "update_status_visibility_counter_cache"
9 @trigger_name "status_visibility_counter_cache_trigger"
12 execute("drop trigger if exists #{@trigger_name} on activities")
13 execute("drop function if exists #{@function_name}()")
14 drop_if_exists(unique_index(:counter_cache, [:name]))
15 drop_if_exists(table(:counter_cache))
17 create_if_not_exists table(:counter_cache) do
18 add(:instance, :string, null: false)
19 add(:direct, :bigint, null: false, default: 0)
20 add(:private, :bigint, null: false, default: 0)
21 add(:unlisted, :bigint, null: false, default: 0)
22 add(:public, :bigint, null: false, default: 0)
25 create_if_not_exists(unique_index(:counter_cache, [:instance]))
28 CREATE OR REPLACE FUNCTION #{@function_name}()
32 hostname character varying(255);
33 visibility_new character varying(64);
34 visibility_old character varying(64);
35 actor character varying(255);
37 IF TG_OP = 'DELETE' THEN
42 hostname := split_part(actor, '/', 3);
43 IF TG_OP = 'INSERT' THEN
44 visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
45 IF NEW.data->>'type' = 'Create'
46 AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
47 EXECUTE format('INSERT INTO "counter_cache" ("instance", %1$I) VALUES ($1, 1)
48 ON CONFLICT ("instance") DO
49 UPDATE SET %1$I = "counter_cache".%1$I + 1', visibility_new)
53 ELSIF TG_OP = 'UPDATE' THEN
54 visibility_new := activity_visibility(NEW.actor, NEW.recipients, NEW.data);
55 visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
56 IF (NEW.data->>'type' = 'Create')
57 AND (OLD.data->>'type' = 'Create')
58 AND visibility_new != visibility_old
59 AND visibility_new IN ('public', 'unlisted', 'private', 'direct') THEN
60 EXECUTE format('UPDATE "counter_cache" SET
61 %1$I = greatest("counter_cache".%1$I - 1, 0),
62 %2$I = "counter_cache".%2$I + 1
63 WHERE "instance" = $1', visibility_old, visibility_new)
67 ELSIF TG_OP = 'DELETE' THEN
68 IF OLD.data->>'type' = 'Create' THEN
69 visibility_old := activity_visibility(OLD.actor, OLD.recipients, OLD.data);
70 EXECUTE format('UPDATE "counter_cache" SET
71 %1$I = greatest("counter_cache".%1$I - 1, 0)
72 WHERE "instance" = $1', visibility_old)
83 execute("DROP TRIGGER IF EXISTS #{@trigger_name} ON activities")
86 CREATE TRIGGER #{@trigger_name}
89 OR UPDATE of recipients, data
93 EXECUTE PROCEDURE #{@function_name}();
99 execute("DROP TRIGGER IF EXISTS #{@trigger_name} ON activities")
100 execute("DROP FUNCTION IF EXISTS #{@function_name}()")
101 drop_if_exists(unique_index(:counter_cache, [:instance]))
102 drop_if_exists(table(:counter_cache))
104 create_if_not_exists table(:counter_cache) do
105 add(:name, :string, null: false)
106 add(:count, :bigint, null: false, default: 0)
109 create_if_not_exists(unique_index(:counter_cache, [:name]))
112 CREATE OR REPLACE FUNCTION #{@function_name}()
117 IF TG_OP = 'INSERT' THEN
118 IF NEW.data->>'type' = 'Create' THEN
119 EXECUTE 'INSERT INTO counter_cache (name, count) VALUES (''status_visibility_' || activity_visibility(NEW.actor, NEW.recipients, NEW.data) || ''', 1) ON CONFLICT (name) DO UPDATE SET count = counter_cache.count + 1';
122 ELSIF TG_OP = 'UPDATE' THEN
123 IF (NEW.data->>'type' = 'Create') and (OLD.data->>'type' = 'Create') and activity_visibility(NEW.actor, NEW.recipients, NEW.data) != activity_visibility(OLD.actor, OLD.recipients, OLD.data) THEN
124 EXECUTE 'INSERT INTO counter_cache (name, count) VALUES (''status_visibility_' || activity_visibility(NEW.actor, NEW.recipients, NEW.data) || ''', 1) ON CONFLICT (name) DO UPDATE SET count = counter_cache.count + 1';
125 EXECUTE 'update counter_cache SET count = counter_cache.count - 1 where count > 0 and name = ''status_visibility_' || activity_visibility(OLD.actor, OLD.recipients, OLD.data) || ''';';
128 ELSIF TG_OP = 'DELETE' THEN
129 IF OLD.data->>'type' = 'Create' THEN
130 EXECUTE 'update counter_cache SET count = counter_cache.count - 1 where count > 0 and name = ''status_visibility_' || activity_visibility(OLD.actor, OLD.recipients, OLD.data) || ''';';
141 CREATE TRIGGER #{@trigger_name} BEFORE INSERT OR UPDATE of recipients, data OR DELETE ON activities
143 EXECUTE PROCEDURE #{@function_name}();