fix(data): serialize portfolio mutations before rows
This commit is contained in:
@@ -52,6 +52,46 @@ CREATE TABLE portfolio_game_masters (
|
||||
CREATE INDEX ix_portfolio_game_masters_player
|
||||
ON portfolio_game_masters (player_id, portfolio_game_id);
|
||||
|
||||
CREATE FUNCTION lock_portfolio_publication_mutation()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
BEGIN
|
||||
PERFORM pg_advisory_xact_lock(20260530, 108);
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$;
|
||||
|
||||
CREATE TRIGGER trg_portfolio_games_lock_publication_mutation
|
||||
BEFORE INSERT OR DELETE OR UPDATE OF is_public ON portfolio_games
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION lock_portfolio_publication_mutation();
|
||||
|
||||
CREATE TRIGGER trg_portfolio_game_sessions_lock_publication_mutation
|
||||
BEFORE INSERT OR DELETE OR UPDATE ON portfolio_game_sessions
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION lock_portfolio_publication_mutation();
|
||||
|
||||
CREATE TRIGGER trg_portfolio_game_masters_lock_publication_mutation
|
||||
BEFORE INSERT OR DELETE OR UPDATE ON portfolio_game_masters
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION lock_portfolio_publication_mutation();
|
||||
|
||||
CREATE TRIGGER trg_sessions_lock_portfolio_publication_mutation
|
||||
BEFORE DELETE OR UPDATE OF scheduled_at ON sessions
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION lock_portfolio_publication_mutation();
|
||||
|
||||
CREATE TRIGGER trg_game_groups_lock_portfolio_publication_mutation_before_delete
|
||||
BEFORE DELETE ON game_groups
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION lock_portfolio_publication_mutation();
|
||||
|
||||
CREATE TRIGGER trg_players_lock_portfolio_publication_mutation_before_delete
|
||||
BEFORE DELETE ON players
|
||||
FOR EACH STATEMENT
|
||||
EXECUTE FUNCTION lock_portfolio_publication_mutation();
|
||||
|
||||
CREATE FUNCTION validate_public_portfolio_game_required_links()
|
||||
RETURNS TRIGGER
|
||||
LANGUAGE plpgsql
|
||||
|
||||
@@ -45,6 +45,9 @@ public sealed class DiscordDeleteSessionHandler(
|
||||
}
|
||||
|
||||
await using var transaction = await connection.BeginTransactionAsync(cancellationToken);
|
||||
await connection.ExecuteAsync(
|
||||
"SELECT pg_advisory_xact_lock(20260530, 108)",
|
||||
transaction: transaction);
|
||||
_ = await connection.QuerySingleOrDefaultAsync<Guid?>(
|
||||
"""
|
||||
SELECT s.id
|
||||
|
||||
@@ -31,7 +31,12 @@ public sealed class DeleteSessionHandler(
|
||||
await using var connection = await dataSource.OpenConnectionAsync(ct);
|
||||
await using var transaction = await connection.BeginTransactionAsync(ct);
|
||||
|
||||
// 1. Lock the session before any linked portfolio card and verify group manager.
|
||||
// 1. Use the database mutation order before locking the session or linked portfolio cards.
|
||||
await connection.ExecuteAsync(
|
||||
"SELECT pg_advisory_xact_lock(20260530, 108)",
|
||||
transaction: transaction);
|
||||
|
||||
// 2. Lock the session before any linked portfolio card and verify group manager.
|
||||
var session = await connection.QuerySingleOrDefaultAsync<DeleteSessionInfoDto>(
|
||||
"""
|
||||
SELECT s.title AS Title,
|
||||
@@ -63,7 +68,7 @@ public sealed class DeleteSessionHandler(
|
||||
return new DeleteSessionResult(false, "Только owner или co-GM может удалять сессию.", null, null, null, false, 0);
|
||||
}
|
||||
|
||||
// 2. Unpublish a linked portfolio card before its required session link cascades away.
|
||||
// 3. Unpublish a linked portfolio card before its required session link cascades away.
|
||||
await connection.ExecuteAsync(
|
||||
"""
|
||||
UPDATE portfolio_games pg
|
||||
@@ -77,7 +82,7 @@ public sealed class DeleteSessionHandler(
|
||||
new { command.SessionId },
|
||||
transaction);
|
||||
|
||||
// 3. Delete session
|
||||
// 4. Delete session
|
||||
await connection.ExecuteAsync("DELETE FROM sessions WHERE id = @Id", new { Id = command.SessionId }, transaction);
|
||||
|
||||
var remainingInTopic = session.ThreadId.HasValue
|
||||
|
||||
Reference in New Issue
Block a user