From 1e466718fc38395ddae2612c5f96a204b4fcd3ec Mon Sep 17 00:00:00 2001 From: Luke Vella Date: Thu, 14 Apr 2022 13:04:47 +0100 Subject: [PATCH] Remove users with duplicate emails --- .../migration.sql | 43 +++++++++++++++++++ package.json | 4 +- schema.prisma | 24 +++++++---- yarn.lock | 36 ++++++++-------- 4 files changed, 79 insertions(+), 28 deletions(-) create mode 100644 migrations/20220414101318_remove_duplicate_emails/migration.sql diff --git a/migrations/20220414101318_remove_duplicate_emails/migration.sql b/migrations/20220414101318_remove_duplicate_emails/migration.sql new file mode 100644 index 000000000..bc69bad40 --- /dev/null +++ b/migrations/20220414101318_remove_duplicate_emails/migration.sql @@ -0,0 +1,43 @@ +-- AlterTable +ALTER TABLE "Comment" ADD COLUMN "updatedAt" TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "Option" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ADD COLUMN "updatedAt" TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "Participant" ADD COLUMN "updatedAt" TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "User" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ADD COLUMN "updatedAt" TIMESTAMP(3); + +-- AlterTable +ALTER TABLE "Vote" ADD COLUMN "createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP, +ADD COLUMN "updatedAt" TIMESTAMP(3); + +-- We need to get rid of duplicate email addresses in the users table +-- because the index was previously case sensitive + +-- First we update all polls created by users with a duplicate email address +-- to a single user +UPDATE "Poll" p SET "userId" = u.id +FROM ( + SELECT min(id) id, array_agg(id) as "userIds" + FROM "User" u + GROUP BY lower(email) + HAVING count(*) > 1 +) u +WHERE p."userId" = any(u."userIds") +AND p."userId" <> u.id; + +-- Remove all users that do not have polls +DELETE FROM "User" u +WHERE NOT EXISTS (SELECT * FROM "Poll" p WHERE u.id = p."userId"); + +-- Add citext extension +CREATE EXTENSION citext; + +-- Change email to citext +ALTER TABLE "User" +ALTER COLUMN email TYPE citext; diff --git a/package.json b/package.json index 8378354a0..aeaf3916a 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@headlessui/react": "^1.5.0", "@next/bundle-analyzer": "^12.1.0", "@popperjs/core": "^2.11.4", - "@prisma/client": "^3.11.0", + "@prisma/client": "^3.12.0", "@sentry/nextjs": "^6.19.3", "@svgr/webpack": "^6.2.1", "@tailwindcss/forms": "^0.4.0", @@ -35,7 +35,7 @@ "next-i18next": "^10.5.0", "next-plausible": "^3.1.9", "nodemailer": "^6.7.2", - "prisma": "^3.11.0", + "prisma": "^3.12.0", "react": "17.0.2", "react-big-calendar": "^0.38.9", "react-dom": "17.0.2", diff --git a/schema.prisma b/schema.prisma index 2f24e315d..03991783a 100644 --- a/schema.prisma +++ b/schema.prisma @@ -10,7 +10,9 @@ generator client { model User { id String @id @default(cuid()) name String - email String @unique + email String @unique() @db.Citext + createdAt DateTime @default(now()) + updatedAt DateTime? @updatedAt polls Poll[] participants Participant[] comments Comment[] @@ -68,19 +70,22 @@ model Participant { name String user User? @relation(fields: [userId], references: [id]) userId String? - poll Poll @relation(fields: [pollId], references: [urlId], onDelete: Cascade) + poll Poll @relation(fields: [pollId], references: [urlId], onDelete: Cascade) pollId String votes Vote[] createdAt DateTime @default(now()) + updatedAt DateTime? @updatedAt @@unique([id, pollId]) } model Option { - id String @id @default(cuid()) - value String - pollId String - poll Poll @relation(fields: [pollId], references: [urlId], onDelete: Cascade) - votes Vote[] + id String @id @default(cuid()) + value String + pollId String + poll Poll @relation(fields: [pollId], references: [urlId], onDelete: Cascade) + createdAt DateTime @default(now()) + updatedAt DateTime? @updatedAt + votes Vote[] } model Vote { @@ -89,8 +94,10 @@ model Vote { participantId String option Option @relation(fields: [optionId], references: [id], onDelete: Cascade) optionId String - poll Poll @relation(fields: [pollId], references: [urlId], onDelete: Cascade) + poll Poll @relation(fields: [pollId], references: [urlId], onDelete: Cascade) pollId String + createdAt DateTime @default(now()) + updatedAt DateTime? @updatedAt } model Comment { @@ -102,6 +109,7 @@ model Comment { user User? @relation(fields: [userId], references: [id]) userId String? createdAt DateTime @default(now()) + updatedAt DateTime? @updatedAt @@unique([id, pollId]) } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index c48b7103c..6a6713255 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1334,22 +1334,22 @@ resolved "https://registry.npmjs.org/@popperjs/core/-/core-2.9.2.tgz" integrity sha512-VZMYa7+fXHdwIq1TDhSXoVmSPEGM/aa+6Aiq3nVVJ9bXr24zScr+NlKFKC3iPljA7ho/GAZr+d2jOf5GIRC30Q== -"@prisma/client@^3.11.0": - version "3.11.0" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.11.0.tgz#6aa05165b641578c74816aaa15b389e0062318ee" - integrity sha512-d42o/tlalaWMmNOR4r5BiR6YYTYEV82eZ2lNKOm5ht3WyYwI9e+zy2MyZnNO4Fx5e08RAhW+GRVcEgKl5faUaQ== +"@prisma/client@^3.12.0": + version "3.12.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-3.12.0.tgz#a0eb49ffea5c128dd11dffb896d7139a60073d12" + integrity sha512-4NEQjUcWja/NVBvfuDFscWSk1/rXg3+wj+TSkqXCb1tKlx/bsUE00rxsvOvGg7VZ6lw1JFpGkwjwmsOIc4zvQw== dependencies: - "@prisma/engines-version" "3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b" + "@prisma/engines-version" "3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980" -"@prisma/engines-version@3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b": - version "3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b.tgz#808ab9636184e4a0b2bf79016d6ed72c4a1ed54f" - integrity sha512-bhMW1XybXZyqCf+9QqjP7Oi7xgVHcISVyOZNMm51qeZsy12M1RtHaCcXUFeMMV0JOCZZuPFVr3+0KVpQqK35CQ== +"@prisma/engines-version@3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980": + version "3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980.tgz#829ca3d9d0d92555f44644606d4edfd45b2f5886" + integrity sha512-o+jo8d7ZEiVpcpNWUDh3fj2uPQpBxl79XE9ih9nkogJbhw6P33274SHnqheedZ7PyvPIK/mvU8MLNYgetgXPYw== -"@prisma/engines@3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b": - version "3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b.tgz#4c1093f7b24c433a9cef2e60f13f57f7c89b5cfa" - integrity sha512-m9iZd5F5vP6A2IvKWfHpOO/qK8OOO9nbsV/pdyEkF/1WNe0E8SIWFBKb+HcMLkG9OFbDDBy8QItXmp/mIULuwQ== +"@prisma/engines@3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980": + version "3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980.tgz#e52e364084c4d05278f62768047b788665e64a45" + integrity sha512-zULjkN8yhzS7B3yeEz4aIym4E2w1ChrV12i14pht3ePFufvsAvBSoZ+tuXMvfSoNTgBS5E4bolRzLbMmbwkkMQ== "@restart/hooks@^0.3.25": version "0.3.26" @@ -4764,12 +4764,12 @@ pretty-format@^27.2.5, pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" -prisma@^3.11.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.11.0.tgz#0e384e9d36785711b579fda60117a2d41f79c72c" - integrity sha512-8SdsLPhKR3mOfoo2o73h9mNn3v5kA/RqGA26Sv6qDS78Eh2uepPqt5e8/nwj5EOblYm5HEGuitaXQrOCLb6uTw== +prisma@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-3.12.0.tgz#9675e0e72407122759d3eadcb6d27cdccd3497bd" + integrity sha512-ltCMZAx1i0i9xuPM692Srj8McC665h6E5RqJom999sjtVSccHSD8Z+HSdBN2183h9PJKvC5dapkn78dd0NWMBg== dependencies: - "@prisma/engines" "3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b" + "@prisma/engines" "3.12.0-37.22b822189f46ef0dc5c5b503368d1bee01213980" process-nextick-args@~2.0.0: version "2.0.1"