🏗️ Update how we store date values

This also fixes a few bugs:
- some values had end times that were before the start times
- some values has end times a couple of days in the future

It’s not entirely clear how users were able to set these values but this update fixes these values and helps avoid similar issues in the future.
This commit is contained in:
Luke Vella 2023-03-30 14:10:23 +01:00
parent 8a9159c322
commit 51c5016656
12 changed files with 203 additions and 158 deletions

View file

@ -0,0 +1,35 @@
-- AlterTable
ALTER TABLE "options"
ADD COLUMN "duration_minutes" INTEGER NOT NULL DEFAULT 0,
ADD COLUMN "start" TIMESTAMP(0);
-- AlterTable
ALTER TABLE "polls" DROP COLUMN "type";
-- DropEnum
DROP TYPE "poll_type";
-- Reformat option value into new columns
UPDATE "options"
SET "start" = CASE
WHEN POSITION('/' IN "value") = 0 THEN (value || 'T00:00:00')::TIMESTAMP WITHOUT TIME ZONE
ELSE SPLIT_PART("value", '/', 1)::TIMESTAMP WITHOUT TIME ZONE
END,
"duration_minutes" = CASE
WHEN POSITION('/' IN "value") = 0 THEN 0
ELSE
LEAST(EXTRACT(EPOCH FROM (split_part("value", '/', 2)::timestamp - split_part("value", '/', 1)::timestamp)) / 60, 1440)
END;
-- Fix cases where we have a negative duration due to the end time being in the past
-- eg. Some polls have value 2023-03-29T23:00:00/2023-03-29T01:00:00
UPDATE "options"
SET "duration_minutes" = "duration_minutes" + 1440
WHERE "duration_minutes" < 0;
-- Set start date to be not null now that we have all the data and drop the old value column
ALTER TABLE "options"
DROP COLUMN "value",
DROP COLUMN "updated_at",
ALTER COLUMN "start" SET NOT NULL;

View file

@ -22,19 +22,12 @@ model User {
@@map("users")
}
enum PollType {
date
@@map("poll_type")
}
model Poll {
id String @id @unique @map("id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
deadline DateTime?
title String
type PollType
description String?
location String?
user User? @relation(fields: [userId], references: [id])
@ -88,11 +81,11 @@ model Participant {
model Option {
id String @id @default(cuid())
value String
start DateTime @db.Timestamp(0)
duration Int @default(0) @map("duration_minutes")
pollId String @map("poll_id")
poll Poll @relation(fields: [pollId], references: [id])
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime? @updatedAt @map("updated_at")
@@index([pollId], type: Hash)
@@map("options")

View file

@ -1,5 +1,5 @@
import { faker } from "@faker-js/faker";
import { PrismaClient, VoteType } from "@prisma/client";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
@ -11,14 +11,16 @@ async function main() {
// Create some users
const user = await prisma.user.create({
data: {
name: faker.name.fullName(),
email: faker.internet.email(),
name: "Dev User",
email: "dev@rallly.co",
},
});
// Create some polls
const polls = await Promise.all(
Array.from({ length: 20 }).map(async () => {
Array.from({ length: 20 }).map(async (_, i) => {
// create some polls with no duration (all day) and some with a random duration.
const duration = i % 5 === 0 ? 15 * randInt(8) : 0;
const poll = await prisma.poll.create({
include: {
participants: true,
@ -30,7 +32,6 @@ async function main() {
description: faker.lorem.paragraph(),
location: faker.address.streetAddress(),
deadline: faker.date.future(),
type: "date",
user: {
connect: {
id: user.id,
@ -46,7 +47,8 @@ async function main() {
) //
.map((date) => {
return {
value: date.toISOString().substring(0, 10),
start: date,
duration,
};
}),
},
@ -73,7 +75,7 @@ async function main() {
data: poll.options.map((option) => {
const randomNumber = randInt(100);
const vote =
randomNumber > 90 ? "ifNeedBe" : randomNumber > 50 ? "yes" : "no";
randomNumber > 95 ? "ifNeedBe" : randomNumber > 50 ? "yes" : "no";
return {
participantId: participant.id,
pollId: poll.id,