AppFlowy-Cloud/migrations/20230906102651_collab.sql

162 lines
6.5 KiB
PL/PgSQL

-- af_collab contains all the collabs.
CREATE TABLE IF NOT EXISTS af_collab(
oid TEXT PRIMARY KEY,
owner_uid BIGINT NOT NULL,
workspace_id UUID NOT NULL REFERENCES af_workspace(workspace_id) ON DELETE CASCADE,
-- 0: Private, 1: Shared
access_level INTEGER NOT NULL DEFAULT 0,
deleted_at TIMESTAMP WITH TIME ZONE DEFAULT NULL,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
CREATE UNIQUE INDEX idx_af_collab_oid ON af_collab (oid);
-- collab update table.
CREATE TABLE IF NOT EXISTS af_collab_update (
oid TEXT REFERENCES af_collab(oid) ON DELETE CASCADE,
blob BYTEA NOT NULL,
len INTEGER,
partition_key INTEGER NOT NULL,
md5 TEXT DEFAULT '',
did TEXT DEFAULT '',
encrypt INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
workspace_id UUID NOT NULL REFERENCES af_workspace(workspace_id) ON DELETE CASCADE,
PRIMARY KEY (oid, partition_key)
) PARTITION BY LIST (partition_key);
CREATE TABLE af_collab_update_document PARTITION OF af_collab_update FOR
VALUES IN (0);
CREATE TABLE af_collab_update_database PARTITION OF af_collab_update FOR
VALUES IN (1);
CREATE TABLE af_collab_update_w_database PARTITION OF af_collab_update FOR
VALUES IN (2);
CREATE TABLE af_collab_update_folder PARTITION OF af_collab_update FOR
VALUES IN (3);
CREATE TABLE af_collab_update_database_row PARTITION OF af_collab_update FOR
VALUES IN (4);
CREATE TABLE af_collab_update_user_awareness PARTITION OF af_collab_update FOR
VALUES IN (5);
-- This trigger is fired before an insert operation on the af_collab_update table. It checks if a corresponding collab
-- exists in the af_collab table. If not, it creates one with the oid, uid, and current timestamp. It might cause a
-- performance issue if the af_collab_update table is updated very frequently, especially if the af_collab table is large
-- and if the oid column isn't indexed
CREATE OR REPLACE FUNCTION insert_into_af_collab_if_not_exists() RETURNS TRIGGER AS $$ BEGIN IF NOT EXISTS (
SELECT 1
FROM af_collab
WHERE oid = NEW.oid
) THEN
INSERT INTO af_collab (oid, owner_uid, workspace_id, created_at)
VALUES (
NEW.oid,
NEW.uid,
NEW.workspace_id,
CURRENT_TIMESTAMP
);
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_into_af_collab_trigger BEFORE
INSERT ON af_collab_update FOR EACH ROW EXECUTE FUNCTION insert_into_af_collab_if_not_exists();
CREATE TABLE af_collab_member (
uid BIGINT REFERENCES af_user(uid) ON DELETE CASCADE,
oid TEXT REFERENCES af_collab(oid) ON DELETE CASCADE,
role_id INTEGER REFERENCES af_roles(id),
PRIMARY KEY(uid, oid)
);
-- This trigger is fired after an insert operation on the af_collab table. It automatically adds the collab's owner
-- to the af_collab_member table with the role 'Owner'.
CREATE OR REPLACE FUNCTION insert_into_af_collab_member() RETURNS TRIGGER AS $$ BEGIN
INSERT INTO af_collab_member (oid, uid, role_id)
VALUES (
NEW.oid,
NEW.owner_uid,
(
SELECT id
FROM af_roles
WHERE name = 'Owner'
)
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER insert_into_af_collab_member_trigger
AFTER
INSERT ON af_collab FOR EACH ROW EXECUTE FUNCTION insert_into_af_collab_member();
-- collab statistics. It will be used to store the edit_count of the collab.
CREATE TABLE IF NOT EXISTS af_collab_statistics (
oid TEXT PRIMARY KEY,
edit_count BIGINT NOT NULL DEFAULT 0
);
-- This trigger is fired after an insert operation on the af_collab_update table. It increments the edit_count of the
-- corresponding collab in the af_collab_statistics table. If the collab doesn't exist in the af_collab_statistics table,
-- it creates one with edit_count set to 1.
CREATE OR REPLACE FUNCTION increment_af_collab_edit_count() RETURNS TRIGGER AS $$BEGIN IF EXISTS(
SELECT 1
FROM af_collab_statistics
WHERE oid = NEW.oid
) THEN
UPDATE af_collab_statistics
SET edit_count = edit_count + 1
WHERE oid = NEW.oid;
ELSE
INSERT INTO af_collab_statistics (oid, edit_count)
VALUES (NEW.oid, 1);
END IF;
RETURN NEW;
END;
$$LANGUAGE plpgsql;
CREATE TRIGGER af_collab_update_edit_count_trigger
AFTER
INSERT ON af_collab_update FOR EACH ROW EXECUTE FUNCTION increment_af_collab_edit_count();
-- collab snapshot. It will be used to store the snapshots of the collab.
CREATE TABLE IF NOT EXISTS af_collab_snapshot (
sid BIGSERIAL PRIMARY KEY,
oid TEXT NOT NULL,
name TEXT DEFAULT '',
blob BYTEA NOT NULL,
len INTEGER NOT NULL,
edit_count BIGINT NOT NULL DEFAULT 0,
encrypt INTEGER DEFAULT 0,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);
-- This trigger is fired after an insert operation on the af_collab_snapshot table. It automatically sets the edit_count
-- of the new snapshot to the current edit_count of the collab in the af_collab_statistics table.
CREATE OR REPLACE FUNCTION af_collab_snapshot_update_edit_count() RETURNS TRIGGER AS $$ BEGIN NEW.edit_count := COALESCE(
(
SELECT af_collab_statistics.edit_count
FROM af_collab_statistics
WHERE af_collab_statistics.oid = NEW.oid
),
-- If the row in af_collab_statistics with given oid is found, set edit_count to 0
0
);
RETURN NEW;
END;
$$LANGUAGE plpgsql;
CREATE TRIGGER af_collab_snapshot_update_edit_count_trigger BEFORE
INSERT ON af_collab_snapshot FOR EACH ROW EXECUTE FUNCTION af_collab_snapshot_update_edit_count();
-- collab state view. It will be used to get the current state of the collab.
CREATE VIEW af_collab_state AS
SELECT a.oid,
a.created_at AS snapshot_created_at,
a.edit_count AS snapshot_edit_count,
b.edit_count AS current_edit_count
FROM af_collab_snapshot AS a
JOIN af_collab_statistics AS b ON a.oid = b.oid;
-- Insert a workspace member if the user with given uid is the owner of the workspace
CREATE OR REPLACE FUNCTION insert_af_workspace_member_if_owner(
p_uid BIGINT,
p_role_id INT,
p_workspace_id UUID
) RETURNS VOID AS $$ BEGIN -- If user is the owner, proceed with the insert operation
INSERT INTO af_workspace_member (uid, role_id, workspace_id)
SELECT p_uid,
p_role_id,
p_workspace_id
FROM af_workspace
WHERE workspace_id = p_workspace_id
AND owner_uid = p_uid;
-- Check if the insert operation was successful. If not, user is not the owner of the workspace.
IF NOT FOUND THEN RAISE EXCEPTION 'Unsupported operation: User is not the owner of the workspace.';
END IF;
END;
$$ LANGUAGE plpgsql;