Files
gochat/backend/migrations/000079_make_captain_bindings_unique.up.sql
T

107 lines
3.8 KiB
SQL

ALTER TABLE agent_bots ADD COLUMN IF NOT EXISTS captain_assistant_id BIGINT;
-- This data repair and its unique indexes must see a stable snapshot. These
-- locks block concurrent writes while allowing reads, so run this migration
-- in a maintenance window sized for the deduplication.
LOCK TABLE agent_bots, agent_bot_inboxes, captain_inboxes, conversations,
agent_bot_presence_events, bot_rules, bot_trigger_configs
IN SHARE ROW EXCLUSIVE MODE;
UPDATE agent_bots
SET captain_assistant_id = (config ->> 'assistant_id')::BIGINT
WHERE bot_type = 'captain'
AND captain_assistant_id IS NULL
AND config ->> 'assistant_id' ~ '^[0-9]+$';
UPDATE conversations conversation
SET assignee_agent_bot_id = canonical.keep_id
FROM (
SELECT account_id, captain_assistant_id, MIN(id) AS keep_id,
ARRAY_AGG(id) AS duplicate_ids
FROM agent_bots
WHERE captain_assistant_id IS NOT NULL
GROUP BY account_id, captain_assistant_id
HAVING COUNT(*) > 1
) canonical
WHERE conversation.assignee_agent_bot_id = ANY(canonical.duplicate_ids)
AND conversation.assignee_agent_bot_id <> canonical.keep_id;
UPDATE agent_bot_inboxes binding
SET agent_bot_id = canonical.keep_id
FROM (
SELECT account_id, captain_assistant_id, MIN(id) AS keep_id,
ARRAY_AGG(id) AS duplicate_ids
FROM agent_bots
WHERE captain_assistant_id IS NOT NULL
GROUP BY account_id, captain_assistant_id
HAVING COUNT(*) > 1
) canonical
WHERE binding.agent_bot_id = ANY(canonical.duplicate_ids)
AND binding.agent_bot_id <> canonical.keep_id;
UPDATE agent_bot_presence_events event
SET agent_bot_id = canonical.keep_id
FROM (
SELECT account_id, captain_assistant_id, MIN(id) AS keep_id,
ARRAY_AGG(id) AS duplicate_ids
FROM agent_bots
WHERE captain_assistant_id IS NOT NULL
GROUP BY account_id, captain_assistant_id
HAVING COUNT(*) > 1
) canonical
WHERE event.agent_bot_id = ANY(canonical.duplicate_ids)
AND event.agent_bot_id <> canonical.keep_id;
UPDATE bot_rules rule
SET agent_bot_id = canonical.keep_id
FROM (
SELECT account_id, captain_assistant_id, MIN(id) AS keep_id,
ARRAY_AGG(id) AS duplicate_ids
FROM agent_bots
WHERE captain_assistant_id IS NOT NULL
GROUP BY account_id, captain_assistant_id
HAVING COUNT(*) > 1
) canonical
WHERE rule.agent_bot_id = ANY(canonical.duplicate_ids)
AND rule.agent_bot_id <> canonical.keep_id;
UPDATE bot_trigger_configs config
SET agent_bot_id = canonical.keep_id
FROM (
SELECT account_id, captain_assistant_id, MIN(id) AS keep_id,
ARRAY_AGG(id) AS duplicate_ids
FROM agent_bots
WHERE captain_assistant_id IS NOT NULL
GROUP BY account_id, captain_assistant_id
HAVING COUNT(*) > 1
) canonical
WHERE config.agent_bot_id = ANY(canonical.duplicate_ids)
AND config.agent_bot_id <> canonical.keep_id;
DELETE FROM agent_bot_inboxes duplicate
USING agent_bot_inboxes canonical
WHERE duplicate.id > canonical.id
AND duplicate.agent_bot_id = canonical.agent_bot_id
AND duplicate.inbox_id = canonical.inbox_id;
DELETE FROM agent_bots duplicate
USING agent_bots canonical
WHERE duplicate.id > canonical.id
AND duplicate.account_id IS NOT DISTINCT FROM canonical.account_id
AND duplicate.captain_assistant_id = canonical.captain_assistant_id
AND duplicate.captain_assistant_id IS NOT NULL;
DELETE FROM captain_inboxes duplicate
USING captain_inboxes canonical
WHERE duplicate.id > canonical.id
AND duplicate.inbox_id = canonical.inbox_id
AND duplicate.deleted_at IS NULL
AND canonical.deleted_at IS NULL;
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_bots_captain_assistant
ON agent_bots(account_id, captain_assistant_id);
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_bot_inboxes_bot_inbox
ON agent_bot_inboxes(agent_bot_id, inbox_id);
CREATE UNIQUE INDEX IF NOT EXISTS idx_captain_inboxes_active_inbox
ON captain_inboxes(inbox_id) WHERE deleted_at IS NULL;