Files
apskel-pos-backend/migrations/000116_normalize_customer_phone_numbers.up.sql
T

63 lines
2.4 KiB
SQL
Raw Normal View History

-- Customer phone numbers are stored in one form, 62… without + (util.NormalizePhoneNumber),
-- and every number a customer types is rewritten to it before it is looked up. This
-- rewrites the numbers stored before, so 0812…, +62 812… and 812… become 62812….
--
-- Only one customer may have a number. When several stored numbers become the same one,
-- the customer that already has it keeps it, else a registered one (with a password),
-- else the oldest; the others are left as they are. A number that is not an Indonesian
-- mobile number is left as it is too. Neither can log in until it is fixed by hand:
--
-- SELECT id, name, phone_number FROM customers
-- WHERE phone_number IS NOT NULL AND phone_number !~ '^628[0-9]{7,11}$';
WITH stripped AS (
SELECT id, phone_number, password_hash, created_at,
regexp_replace(regexp_replace(phone_number, '[[:space:]().-]', '', 'g'), '^\+', '') AS p
FROM customers
WHERE phone_number IS NOT NULL
),
normalized AS (
SELECT id, phone_number, password_hash, created_at,
CASE
WHEN p LIKE '620%' THEN '62' || substr(p, 4)
WHEN p LIKE '0%' THEN '62' || substr(p, 2)
WHEN p LIKE '8%' THEN '62' || p
ELSE p
END AS new_phone
FROM stripped
),
ranked AS (
SELECT id, new_phone,
row_number() OVER (
PARTITION BY new_phone
ORDER BY phone_number = new_phone DESC, password_hash IS NOT NULL DESC, created_at, id
) AS rank
FROM normalized
WHERE new_phone ~ '^628[0-9]{7,11}$'
)
UPDATE customers c
SET phone_number = r.new_phone, updated_at = NOW()
FROM ranked r
WHERE c.id = r.id AND r.rank = 1 AND c.phone_number <> r.new_phone;
-- A registration started before this migration finishes with the number in its OTP
-- session, and a resent OTP is found by it.
UPDATE otp_sessions
SET phone_number = n.new_phone, updated_at = NOW()
FROM (
SELECT id,
CASE
WHEN p LIKE '620%' THEN '62' || substr(p, 4)
WHEN p LIKE '0%' THEN '62' || substr(p, 2)
WHEN p LIKE '8%' THEN '62' || p
ELSE p
END AS new_phone
FROM (
SELECT id, regexp_replace(regexp_replace(phone_number, '[[:space:]().-]', '', 'g'), '^\+', '') AS p
FROM otp_sessions
) stripped
) n
WHERE otp_sessions.id = n.id
AND n.new_phone ~ '^628[0-9]{7,11}$'
AND otp_sessions.phone_number <> n.new_phone;