63 lines
2.4 KiB
SQL
63 lines
2.4 KiB
SQL
-- 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;
|