fix(data): harden portfolio publication concurrency
This commit is contained in:
@@ -52,47 +52,64 @@ CREATE TABLE portfolio_game_masters (
|
||||
CREATE INDEX ix_portfolio_game_masters_player
|
||||
ON portfolio_game_masters (player_id, portfolio_game_id);
|
||||
|
||||
CREATE FUNCTION unpublish_portfolio_game_without_required_links()
|
||||
CREATE FUNCTION validate_public_portfolio_game_required_links()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
target_portfolio_game_id UUID;
|
||||
BEGIN
|
||||
PERFORM 1
|
||||
FROM portfolio_games
|
||||
WHERE id = OLD.portfolio_game_id
|
||||
FOR UPDATE;
|
||||
IF TG_TABLE_NAME = 'portfolio_games' THEN
|
||||
target_portfolio_game_id := NEW.id;
|
||||
ELSE
|
||||
target_portfolio_game_id := OLD.portfolio_game_id;
|
||||
END IF;
|
||||
|
||||
UPDATE portfolio_games
|
||||
SET is_public = false,
|
||||
updated_at = now()
|
||||
WHERE id = OLD.portfolio_game_id
|
||||
AND is_public = true
|
||||
AND (
|
||||
NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM portfolio_game_sessions
|
||||
WHERE portfolio_game_id = OLD.portfolio_game_id
|
||||
IF EXISTS (
|
||||
SELECT 1
|
||||
FROM portfolio_games pg
|
||||
WHERE pg.id = target_portfolio_game_id
|
||||
AND pg.is_public = true
|
||||
AND (
|
||||
NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM portfolio_game_sessions pgs
|
||||
WHERE pgs.portfolio_game_id = target_portfolio_game_id
|
||||
)
|
||||
OR NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM portfolio_game_masters pgm
|
||||
WHERE pgm.portfolio_game_id = target_portfolio_game_id
|
||||
)
|
||||
)
|
||||
OR NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM portfolio_game_masters
|
||||
WHERE portfolio_game_id = OLD.portfolio_game_id
|
||||
)
|
||||
);
|
||||
) THEN
|
||||
RAISE EXCEPTION
|
||||
'published portfolio game % must have at least one linked session and at least one linked master',
|
||||
target_portfolio_game_id
|
||||
USING ERRCODE = '23514';
|
||||
END IF;
|
||||
|
||||
RETURN OLD;
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER trg_portfolio_game_sessions_unpublish_after_delete
|
||||
AFTER DELETE ON portfolio_game_sessions
|
||||
CREATE CONSTRAINT TRIGGER trg_portfolio_games_validate_required_links
|
||||
AFTER INSERT OR UPDATE OF is_public ON portfolio_games
|
||||
DEFERRABLE INITIALLY DEFERRED
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION unpublish_portfolio_game_without_required_links();
|
||||
EXECUTE FUNCTION validate_public_portfolio_game_required_links();
|
||||
|
||||
CREATE TRIGGER trg_portfolio_game_masters_unpublish_after_delete
|
||||
AFTER DELETE ON portfolio_game_masters
|
||||
CREATE CONSTRAINT TRIGGER trg_portfolio_game_sessions_validate_required_links
|
||||
AFTER DELETE OR UPDATE OF portfolio_game_id ON portfolio_game_sessions
|
||||
DEFERRABLE INITIALLY DEFERRED
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION unpublish_portfolio_game_without_required_links();
|
||||
EXECUTE FUNCTION validate_public_portfolio_game_required_links();
|
||||
|
||||
CREATE CONSTRAINT TRIGGER trg_portfolio_game_masters_validate_required_links
|
||||
AFTER DELETE OR UPDATE OF portfolio_game_id ON portfolio_game_masters
|
||||
DEFERRABLE INITIALLY DEFERRED
|
||||
FOR EACH ROW
|
||||
EXECUTE FUNCTION validate_public_portfolio_game_required_links();
|
||||
|
||||
CREATE TABLE portfolio_game_reviews (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
|
||||
Reference in New Issue
Block a user