snapshot of https://github.com/marmelab/atomic-crm.git (main, 2026-09-18; blobs > 131072B omitted)
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
Some checks failed
✅ Check / 🔬 ESLint (push) Failing after 21s
✅ Check / 🏷️ Typecheck (push) Failing after 11s
✅ Check / 🔎 Test (push) Failing after 11s
✅ Check / e2e-test (push) Failing after 11s
✅ Check / 🔨 Build (push) Failing after 11s
🚀 Deploy / 🚀 Deploy (doc) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (demo) (push) Failing after 12s
🚀 Deploy / 🚀 Deploy (supabase) (push) Failing after 18s
This commit is contained in:
153
supabase/migrations/20251204172855_merge_contacts_function.sql
Normal file
153
supabase/migrations/20251204172855_merge_contacts_function.sql
Normal file
@@ -0,0 +1,153 @@
|
||||
-- Create function to merge contacts server-side with transaction support
|
||||
CREATE OR REPLACE FUNCTION merge_contacts(loser_id bigint, winner_id bigint)
|
||||
RETURNS bigint
|
||||
LANGUAGE plpgsql
|
||||
SECURITY INVOKER
|
||||
AS $$
|
||||
DECLARE
|
||||
winner_contact contacts%ROWTYPE;
|
||||
loser_contact contacts%ROWTYPE;
|
||||
deal_record RECORD;
|
||||
merged_emails jsonb;
|
||||
merged_phones jsonb;
|
||||
merged_tags bigint[];
|
||||
winner_emails jsonb;
|
||||
loser_emails jsonb;
|
||||
winner_phones jsonb;
|
||||
loser_phones jsonb;
|
||||
email_map jsonb;
|
||||
phone_map jsonb;
|
||||
BEGIN
|
||||
-- Fetch both contacts
|
||||
SELECT * INTO winner_contact FROM contacts WHERE id = winner_id;
|
||||
SELECT * INTO loser_contact FROM contacts WHERE id = loser_id;
|
||||
|
||||
IF winner_contact IS NULL OR loser_contact IS NULL THEN
|
||||
RAISE EXCEPTION 'Contact not found';
|
||||
END IF;
|
||||
|
||||
-- 1. Reassign tasks from loser to winner
|
||||
UPDATE tasks SET contact_id = winner_id WHERE contact_id = loser_id;
|
||||
|
||||
-- 2. Reassign contact notes from loser to winner
|
||||
UPDATE "contactNotes" SET contact_id = winner_id WHERE contact_id = loser_id;
|
||||
|
||||
-- 3. Update deals - replace loser with winner in contact_ids array
|
||||
FOR deal_record IN
|
||||
SELECT id, contact_ids
|
||||
FROM deals
|
||||
WHERE contact_ids @> ARRAY[loser_id]
|
||||
LOOP
|
||||
UPDATE deals
|
||||
SET contact_ids = (
|
||||
SELECT ARRAY(
|
||||
SELECT DISTINCT unnest(
|
||||
array_remove(deal_record.contact_ids, loser_id) || ARRAY[winner_id]
|
||||
)
|
||||
)
|
||||
)
|
||||
WHERE id = deal_record.id;
|
||||
END LOOP;
|
||||
|
||||
-- 4. Merge contact data
|
||||
|
||||
-- Get email arrays
|
||||
winner_emails := COALESCE(winner_contact.email_jsonb, '[]'::jsonb);
|
||||
loser_emails := COALESCE(loser_contact.email_jsonb, '[]'::jsonb);
|
||||
|
||||
-- Merge emails with deduplication by email address
|
||||
-- Build a map of email -> email object, then convert back to array
|
||||
email_map := '{}'::jsonb;
|
||||
|
||||
-- Add winner emails to map
|
||||
IF jsonb_array_length(winner_emails) > 0 THEN
|
||||
FOR i IN 0..jsonb_array_length(winner_emails)-1 LOOP
|
||||
email_map := email_map || jsonb_build_object(
|
||||
winner_emails->i->>'email',
|
||||
winner_emails->i
|
||||
);
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
-- Add loser emails to map (won't overwrite existing keys)
|
||||
IF jsonb_array_length(loser_emails) > 0 THEN
|
||||
FOR i IN 0..jsonb_array_length(loser_emails)-1 LOOP
|
||||
IF NOT email_map ? (loser_emails->i->>'email') THEN
|
||||
email_map := email_map || jsonb_build_object(
|
||||
loser_emails->i->>'email',
|
||||
loser_emails->i
|
||||
);
|
||||
END IF;
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
-- Convert map back to array
|
||||
merged_emails := (SELECT jsonb_agg(value) FROM jsonb_each(email_map));
|
||||
merged_emails := COALESCE(merged_emails, '[]'::jsonb);
|
||||
|
||||
-- Get phone arrays
|
||||
winner_phones := COALESCE(winner_contact.phone_jsonb, '[]'::jsonb);
|
||||
loser_phones := COALESCE(loser_contact.phone_jsonb, '[]'::jsonb);
|
||||
|
||||
-- Merge phones with deduplication by number
|
||||
phone_map := '{}'::jsonb;
|
||||
|
||||
-- Add winner phones to map
|
||||
IF jsonb_array_length(winner_phones) > 0 THEN
|
||||
FOR i IN 0..jsonb_array_length(winner_phones)-1 LOOP
|
||||
phone_map := phone_map || jsonb_build_object(
|
||||
winner_phones->i->>'number',
|
||||
winner_phones->i
|
||||
);
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
-- Add loser phones to map (won't overwrite existing keys)
|
||||
IF jsonb_array_length(loser_phones) > 0 THEN
|
||||
FOR i IN 0..jsonb_array_length(loser_phones)-1 LOOP
|
||||
IF NOT phone_map ? (loser_phones->i->>'number') THEN
|
||||
phone_map := phone_map || jsonb_build_object(
|
||||
loser_phones->i->>'number',
|
||||
loser_phones->i
|
||||
);
|
||||
END IF;
|
||||
END LOOP;
|
||||
END IF;
|
||||
|
||||
-- Convert map back to array
|
||||
merged_phones := (SELECT jsonb_agg(value) FROM jsonb_each(phone_map));
|
||||
merged_phones := COALESCE(merged_phones, '[]'::jsonb);
|
||||
|
||||
-- Merge tags (remove duplicates)
|
||||
merged_tags := ARRAY(
|
||||
SELECT DISTINCT unnest(
|
||||
COALESCE(winner_contact.tags, ARRAY[]::bigint[]) ||
|
||||
COALESCE(loser_contact.tags, ARRAY[]::bigint[])
|
||||
)
|
||||
);
|
||||
|
||||
-- 5. Update winner with merged data
|
||||
UPDATE contacts SET
|
||||
avatar = COALESCE(winner_contact.avatar, loser_contact.avatar),
|
||||
gender = COALESCE(winner_contact.gender, loser_contact.gender),
|
||||
first_name = COALESCE(winner_contact.first_name, loser_contact.first_name),
|
||||
last_name = COALESCE(winner_contact.last_name, loser_contact.last_name),
|
||||
title = COALESCE(winner_contact.title, loser_contact.title),
|
||||
company_id = COALESCE(winner_contact.company_id, loser_contact.company_id),
|
||||
email_jsonb = merged_emails,
|
||||
phone_jsonb = merged_phones,
|
||||
linkedin_url = COALESCE(winner_contact.linkedin_url, loser_contact.linkedin_url),
|
||||
background = COALESCE(winner_contact.background, loser_contact.background),
|
||||
has_newsletter = COALESCE(winner_contact.has_newsletter, loser_contact.has_newsletter),
|
||||
first_seen = LEAST(COALESCE(winner_contact.first_seen, loser_contact.first_seen), COALESCE(loser_contact.first_seen, winner_contact.first_seen)),
|
||||
last_seen = GREATEST(COALESCE(winner_contact.last_seen, loser_contact.last_seen), COALESCE(loser_contact.last_seen, winner_contact.last_seen)),
|
||||
sales_id = COALESCE(winner_contact.sales_id, loser_contact.sales_id),
|
||||
tags = merged_tags
|
||||
WHERE id = winner_id;
|
||||
|
||||
-- 6. Delete loser contact
|
||||
DELETE FROM contacts WHERE id = loser_id;
|
||||
|
||||
RETURN winner_id;
|
||||
END;
|
||||
$$;
|
||||
Reference in New Issue
Block a user