24 lines
1.8 KiB
MySQL
24 lines
1.8 KiB
MySQL
|
|
CREATE TABLE "user_email_identities" (
|
||
|
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||
|
|
"user_id" uuid NOT NULL,
|
||
|
|
"email" varchar(255) NOT NULL,
|
||
|
|
"verified_at" timestamp with time zone,
|
||
|
|
"source" varchar(30) NOT NULL,
|
||
|
|
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
|
||
|
|
"last_used_at" timestamp with time zone
|
||
|
|
);
|
||
|
|
--> statement-breakpoint
|
||
|
|
ALTER TABLE "user_email_identities" ADD CONSTRAINT "user_email_identities_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
|
||
|
|
CREATE INDEX "user_email_identities_user_id_idx" ON "user_email_identities" USING btree ("user_id");--> statement-breakpoint
|
||
|
|
CREATE INDEX "user_email_identities_email_idx" ON "user_email_identities" USING btree ("email");--> statement-breakpoint
|
||
|
|
CREATE UNIQUE INDEX "user_email_identities_user_id_email_unique" ON "user_email_identities" USING btree ("user_id","email");--> statement-breakpoint
|
||
|
|
CREATE UNIQUE INDEX "user_email_identities_verified_email_unique" ON "user_email_identities" USING btree ("email") WHERE "user_email_identities"."verified_at" IS NOT NULL;--> statement-breakpoint
|
||
|
|
-- Backfill: every existing user gets a `source='primary'` identity with
|
||
|
|
-- their `users.email` (lowercased). We trust existing rows because they
|
||
|
|
-- came in via our own sign-up/credentials flow, so `verified_at` is set
|
||
|
|
-- to `created_at`. This is what makes the new
|
||
|
|
-- `ensureUserIdByVerifiedEmail` lookup return the same `users.id` that
|
||
|
|
-- `ensureUserIdByEmail` used to return for every pre-existing user.
|
||
|
|
INSERT INTO "user_email_identities" ("user_id", "email", "verified_at", "source", "created_at")
|
||
|
|
SELECT "id", lower("email"), "created_at", 'primary', "created_at" FROM "users"
|
||
|
|
ON CONFLICT ("user_id", "email") DO NOTHING;
|