Fix date handling (force iso on drizzle side)

This commit is contained in:
Zoe Roux 2025-06-23 01:36:18 +02:00
parent dfe0d52b1e
commit 985a13c1e4
No known key found for this signature in database
11 changed files with 74 additions and 54 deletions

View File

@ -8,11 +8,11 @@ import {
primaryKey, primaryKey,
real, real,
text, text,
timestamp,
unique, unique,
uuid, uuid,
varchar, varchar,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import { timestamp } from "../utils";
import { shows } from "./shows"; import { shows } from "./shows";
import { image, language, schema } from "./utils"; import { image, language, schema } from "./utils";
import { entryVideoJoin } from "./videos"; import { entryVideoJoin } from "./videos";
@ -67,14 +67,14 @@ export const entries = schema.table(
externalId: entry_extid(), externalId: entry_extid(),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
availableSince: timestamp({ withTimezone: true, mode: "string" }), availableSince: timestamp({ withTimezone: true, mode: "iso" }),
nextRefresh: timestamp({ withTimezone: true, mode: "string" }).notNull(), nextRefresh: timestamp({ withTimezone: true, mode: "iso" }).notNull(),
}, },
(t) => [ (t) => [
unique().on(t.showPk, t.seasonNumber, t.episodeNumber), unique().on(t.showPk, t.seasonNumber, t.episodeNumber),

View File

@ -1,5 +1,6 @@
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
import { check, index, integer, timestamp } from "drizzle-orm/pg-core"; import { check, index, integer } from "drizzle-orm/pg-core";
import { timestamp } from "../utils";
import { entries } from "./entries"; import { entries } from "./entries";
import { profiles } from "./profiles"; import { profiles } from "./profiles";
import { schema } from "./utils"; import { schema } from "./utils";
@ -18,9 +19,9 @@ export const history = schema.table(
videoPk: integer().references(() => videos.pk, { onDelete: "set null" }), videoPk: integer().references(() => videos.pk, { onDelete: "set null" }),
percent: integer().notNull().default(0), percent: integer().notNull().default(0),
time: integer(), time: integer(),
playedDate: timestamp({ withTimezone: true, mode: "string" }) playedDate: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
}, },
(t) => [ (t) => [
index("history_play_date").on(t.playedDate.desc()), index("history_play_date").on(t.playedDate.desc()),

View File

@ -1,11 +1,6 @@
import { import { sql } from "drizzle-orm";
index, import { index, integer, jsonb, uuid, varchar } from "drizzle-orm/pg-core";
integer, import { timestamp } from "../utils";
jsonb,
timestamp,
uuid,
varchar,
} from "drizzle-orm/pg-core";
import { schema } from "./utils"; import { schema } from "./utils";
export const mqueue = schema.table( export const mqueue = schema.table(
@ -15,9 +10,9 @@ export const mqueue = schema.table(
kind: varchar({ length: 255 }).notNull(), kind: varchar({ length: 255 }).notNull(),
message: jsonb().notNull(), message: jsonb().notNull(),
attempt: integer().notNull().default(0), attempt: integer().notNull().default(0),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
}, },
(t) => [index("mqueue_created").on(t.createdAt)], (t) => [index("mqueue_created").on(t.createdAt)],
); );

View File

@ -6,11 +6,11 @@ import {
jsonb, jsonb,
primaryKey, primaryKey,
text, text,
timestamp,
unique, unique,
uuid, uuid,
varchar, varchar,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import { timestamp } from "../utils";
import { shows } from "./shows"; import { shows } from "./shows";
import { image, language, schema } from "./utils"; import { image, language, schema } from "./utils";
@ -42,13 +42,13 @@ export const seasons = schema.table(
externalId: season_extid(), externalId: season_extid(),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
nextRefresh: timestamp({ withTimezone: true, mode: "string" }).notNull(), nextRefresh: timestamp({ withTimezone: true, mode: "iso" }).notNull(),
}, },
(t) => [ (t) => [
unique().on(t.showPk, t.seasonNumber), unique().on(t.showPk, t.seasonNumber),

View File

@ -9,11 +9,11 @@ import {
primaryKey, primaryKey,
smallint, smallint,
text, text,
timestamp,
uuid, uuid,
varchar, varchar,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import type { Image, Original } from "~/models/utils"; import type { Image, Original } from "~/models/utils";
import { timestamp } from "../utils";
import { entries } from "./entries"; import { entries } from "./entries";
import { seasons } from "./seasons"; import { seasons } from "./seasons";
import { roles } from "./staff"; import { roles } from "./staff";
@ -87,13 +87,13 @@ export const shows = schema.table(
externalId: externalid(), externalId: externalid(),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
nextRefresh: timestamp({ withTimezone: true, mode: "string" }).notNull(), nextRefresh: timestamp({ withTimezone: true, mode: "iso" }).notNull(),
}, },
(t) => [ (t) => [
check("rating_valid", sql`${t.rating} between 0 and 100`), check("rating_valid", sql`${t.rating} between 0 and 100`),

View File

@ -3,13 +3,12 @@ import {
index, index,
integer, integer,
jsonb, jsonb,
primaryKey,
text, text,
timestamp,
uuid, uuid,
varchar, varchar,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import type { Character } from "~/models/staff"; import type { Character } from "~/models/staff";
import { timestamp } from "../utils";
import { shows } from "./shows"; import { shows } from "./shows";
import { externalid, image, schema } from "./utils"; import { externalid, image, schema } from "./utils";
@ -32,10 +31,10 @@ export const staff = schema.table("staff", {
image: image(), image: image(),
externalId: externalid(), externalId: externalid(),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
}); });

View File

@ -4,10 +4,10 @@ import {
integer, integer,
primaryKey, primaryKey,
text, text,
timestamp,
uuid, uuid,
varchar, varchar,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import { timestamp } from "../utils";
import { shows } from "./shows"; import { shows } from "./shows";
import { externalid, image, language, schema } from "./utils"; import { externalid, image, language, schema } from "./utils";
@ -17,10 +17,10 @@ export const studios = schema.table("studios", {
slug: varchar({ length: 255 }).notNull().unique(), slug: varchar({ length: 255 }).notNull().unique(),
externalId: externalid(), externalId: externalid(),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
}); });

View File

@ -5,12 +5,12 @@ import {
jsonb, jsonb,
primaryKey, primaryKey,
text, text,
timestamp,
unique, unique,
uuid, uuid,
varchar, varchar,
} from "drizzle-orm/pg-core"; } from "drizzle-orm/pg-core";
import type { Guess } from "~/models/video"; import type { Guess } from "~/models/video";
import { timestamp } from "../utils";
import { entries } from "./entries"; import { entries } from "./entries";
import { schema } from "./utils"; import { schema } from "./utils";
@ -25,10 +25,10 @@ export const videos = schema.table(
version: integer().notNull().default(1), version: integer().notNull().default(1),
guess: jsonb().$type<Guess>().notNull(), guess: jsonb().$type<Guess>().notNull(),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
}, },

View File

@ -1,5 +1,6 @@
import { sql } from "drizzle-orm"; import { sql } from "drizzle-orm";
import { check, integer, primaryKey, timestamp } from "drizzle-orm/pg-core"; import { check, integer, primaryKey } from "drizzle-orm/pg-core";
import { timestamp } from "../utils";
import { entries } from "./entries"; import { entries } from "./entries";
import { profiles } from "./profiles"; import { profiles } from "./profiles";
import { shows } from "./shows"; import { shows } from "./shows";
@ -29,14 +30,14 @@ export const watchlist = schema.table(
score: integer(), score: integer(),
startedAt: timestamp({ withTimezone: true, mode: "string" }), startedAt: timestamp({ withTimezone: true, mode: "iso" }),
lastPlayedAt: timestamp({ withTimezone: true, mode: "string" }), lastPlayedAt: timestamp({ withTimezone: true, mode: "iso" }),
completedAt: timestamp({ withTimezone: true, mode: "string" }), completedAt: timestamp({ withTimezone: true, mode: "iso" }),
createdAt: timestamp({ withTimezone: true, mode: "string" }) createdAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.defaultNow(), .default(sql`now()`),
updatedAt: timestamp({ withTimezone: true, mode: "string" }) updatedAt: timestamp({ withTimezone: true, mode: "iso" })
.notNull() .notNull()
.$onUpdate(() => sql`now()`), .$onUpdate(() => sql`now()`),
}, },

View File

@ -1,19 +1,23 @@
import { import {
type Column, type Column,
type ColumnsSelection, type ColumnsSelection,
getTableColumns,
is,
type SQL, type SQL,
type SQLWrapper, type SQLWrapper,
type Subquery, type Subquery,
sql,
Table, Table,
View, View,
ViewBaseConfig, ViewBaseConfig,
getTableColumns,
is,
sql,
} from "drizzle-orm"; } from "drizzle-orm";
import type { CasingCache } from "drizzle-orm/casing"; import type { CasingCache } from "drizzle-orm/casing";
import type { AnyMySqlSelect } from "drizzle-orm/mysql-core"; import type { AnyMySqlSelect } from "drizzle-orm/mysql-core";
import type { AnyPgSelect, SelectedFieldsFlat } from "drizzle-orm/pg-core"; import {
type AnyPgSelect,
customType,
type SelectedFieldsFlat,
} from "drizzle-orm/pg-core";
import type { AnySQLiteSelect } from "drizzle-orm/sqlite-core"; import type { AnySQLiteSelect } from "drizzle-orm/sqlite-core";
import type { WithSubquery } from "drizzle-orm/subquery"; import type { WithSubquery } from "drizzle-orm/subquery";
import { db } from "./index"; import { db } from "./index";
@ -148,3 +152,19 @@ export const isUniqueConstraint = (e: unknown): boolean => {
typeof e === "object" && e != null && "code" in e && e.code === "23505" typeof e === "object" && e != null && "code" in e && e.code === "23505"
); );
}; };
export const timestamp = customType<{
data: string;
driverData: string;
config: { withTimezone: boolean; precision?: number; mode: "iso" };
}>({
dataType(config) {
const precision = config?.precision ? ` (${config.precision})` : "";
return `timestamp${precision}${config?.withTimezone ? " with time zone" : ""}`;
},
fromDriver(value: string): string {
// postgres format: 2025-06-22 16:13:37.489301+00
// what we want: 2025-06-22T16:13:37Z
return `${value.substring(0, 10)}T${value.substring(11, 19)}Z`;
},
});

View File

@ -1,3 +1,7 @@
import { z } from "zod/v4"; import { z } from "zod/v4";
export const zdate = z.coerce.date; export const zdate = () =>
z.iso
.date()
.or(z.iso.datetime())
.transform((x) => new Date(x));