Skip to content

Commit 8c4ee75

Browse files
committed
migrate to DrizzleORM v1.0.0-beta.18
1 parent 8947641 commit 8c4ee75

14 files changed

Lines changed: 1055 additions & 470 deletions

File tree

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,8 @@
5151
"bits-ui": "^2.16.3",
5252
"clsx": "^2.1.1",
5353
"concurrently": "^9.2.1",
54-
"drizzle-kit": "^0.31.9",
55-
"drizzle-seed": "^0.3.1",
54+
"drizzle-kit": "1.0.0-beta.18-7eb39f0",
55+
"drizzle-seed": "1.0.0-beta.18-7eb39f0",
5656
"eslint": "^9.39.4",
5757
"eslint-config-prettier": "^10.1.8",
5858
"eslint-plugin-svelte": "^3.15.2",
@@ -85,7 +85,7 @@
8585
"@oslojs/encoding": "^1.1.0",
8686
"@simplewebauthn/browser": "^13.3.0",
8787
"@simplewebauthn/server": "^13.3.0",
88-
"drizzle-orm": "^0.45.1",
88+
"drizzle-orm": "1.0.0-beta.18-7eb39f0",
8989
"mailgun.js": "^12.7.1",
9090
"mode-watcher": "^1.1.0",
9191
"node-cron": "^4.2.1",

pnpm-lock.yaml

Lines changed: 941 additions & 399 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/lib/api/retry-payment.remote.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const retryPayment = form(retryPaymentSchema, async ({ memberId }) => {
1414
}
1515

1616
// Verify the member belongs to this user and is awaiting_payment
17-
const member = await db.query.member.findFirst({
17+
const member = await db._query.member.findFirst({
1818
where: and(eq(table.member.id, memberId), eq(table.member.userId, event.locals.user.id)),
1919
});
2020

src/lib/server/attendance/qr-token.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function generateQrToken(): string {
2222
* @throws Error if user not found
2323
*/
2424
export async function ensureUserHasQrToken(userId: string): Promise<string> {
25-
const user = await db.query.user.findFirst({
25+
const user = await db._query.user.findFirst({
2626
where: eq(table.user.id, userId),
2727
columns: {
2828
id: true,
@@ -46,7 +46,7 @@ export async function ensureUserHasQrToken(userId: string): Promise<string> {
4646
.where(and(eq(table.user.id, userId), isNull(table.user.qrToken)));
4747

4848
// Re-read to get the actual token (ours or the concurrent one)
49-
const updated = await db.query.user.findFirst({
49+
const updated = await db._query.user.findFirst({
5050
where: eq(table.user.id, userId),
5151
columns: { qrToken: true },
5252
});
@@ -65,7 +65,7 @@ export async function ensureUserHasQrToken(userId: string): Promise<string> {
6565
* @returns User ID if valid, null otherwise
6666
*/
6767
export async function verifyQrToken(token: string): Promise<string | null> {
68-
const user = await db.query.user.findFirst({
68+
const user = await db._query.user.findFirst({
6969
where: eq(table.user.qrToken, token),
7070
columns: {
7171
id: true,

src/lib/server/db/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@ import { drizzle } from "drizzle-orm/postgres-js";
22
import postgres from "postgres";
33
import { env } from "$lib/server/env";
44
import { dev } from "$app/environment";
5-
import * as schema from "$lib/server/db/schema";
5+
import * as schema from "./schema";
6+
import * as relations from "./relations";
67

78
const client = postgres(env.DATABASE_URL, {
89
ssl: dev ? undefined : "prefer", // Prefer SSL in production, optional in dev
910
});
10-
export const db = drizzle(client, { schema, casing: "snake_case" });
11+
export const db = drizzle({ client, schema: { ...schema, ...relations }, casing: "snake_case" });

src/lib/server/db/relations.ts

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
import { relations } from "drizzle-orm/_relations";
2+
import {
3+
user,
4+
session,
5+
passkey,
6+
secondaryEmail,
7+
membershipType,
8+
membership,
9+
member,
10+
auditLog,
11+
} from "./schema";
12+
13+
export const userRelations = relations(user, ({ many }) => ({
14+
members: many(member),
15+
sessions: many(session),
16+
passkeys: many(passkey),
17+
secondaryEmails: many(secondaryEmail),
18+
auditLogs: many(auditLog),
19+
}));
20+
21+
export const sessionRelations = relations(session, ({ one }) => ({
22+
user: one(user, {
23+
fields: [session.userId],
24+
references: [user.id],
25+
}),
26+
}));
27+
28+
export const passkeyRelations = relations(passkey, ({ one }) => ({
29+
user: one(user, {
30+
fields: [passkey.userId],
31+
references: [user.id],
32+
}),
33+
}));
34+
35+
export const secondaryEmailRelations = relations(secondaryEmail, ({ one }) => ({
36+
user: one(user, {
37+
fields: [secondaryEmail.userId],
38+
references: [user.id],
39+
}),
40+
}));
41+
42+
export const membershipTypeRelations = relations(membershipType, ({ many }) => ({
43+
memberships: many(membership),
44+
}));
45+
46+
export const membershipRelations = relations(membership, ({ one, many }) => ({
47+
membershipType: one(membershipType, {
48+
fields: [membership.membershipTypeId],
49+
references: [membershipType.id],
50+
}),
51+
members: many(member),
52+
}));
53+
54+
export const memberRelations = relations(member, ({ one }) => ({
55+
user: one(user, {
56+
fields: [member.userId],
57+
references: [user.id],
58+
}),
59+
membership: one(membership, {
60+
fields: [member.membershipId],
61+
references: [membership.id],
62+
}),
63+
}));
64+
65+
export const auditLogRelations = relations(auditLog, ({ one }) => ({
66+
user: one(user, {
67+
fields: [auditLog.userId],
68+
references: [user.id],
69+
}),
70+
}));

src/lib/server/db/schema.ts

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { relations, sql } from "drizzle-orm";
1+
import { sql } from "drizzle-orm";
22
import {
33
boolean,
44
bytea,
@@ -16,7 +16,7 @@ import {
1616
import * as v from "valibot";
1717

1818
import { DEFAULT_CUSTOMISATION } from "../customisation/defaults";
19-
import { ADMIN_ROLE_VALUES, MEMBER_STATUS_VALUES, PREFERRED_LANGUAGE_VALUES } from "$lib/shared/enums";
19+
import { ADMIN_ROLE_VALUES, MEMBER_STATUS_VALUES, PREFERRED_LANGUAGE_VALUES } from "../../shared/enums";
2020
import type { AuthenticatorTransportFuture } from "@simplewebauthn/server";
2121

2222
export type LocalizedString = { fi: string; en: string };
@@ -155,29 +155,6 @@ export const member = pgTable(
155155
],
156156
);
157157

158-
export const memberRelations = relations(member, ({ one }) => ({
159-
user: one(user, {
160-
fields: [member.userId],
161-
references: [user.id],
162-
}),
163-
membership: one(membership, {
164-
fields: [member.membershipId],
165-
references: [membership.id],
166-
}),
167-
}));
168-
169-
export const membershipTypeRelations = relations(membershipType, ({ many }) => ({
170-
memberships: many(membership),
171-
}));
172-
173-
export const membershipRelations = relations(membership, ({ one, many }) => ({
174-
membershipType: one(membershipType, {
175-
fields: [membership.membershipTypeId],
176-
references: [membershipType.id],
177-
}),
178-
members: many(member),
179-
}));
180-
181158
export const auditLog = pgTable("audit_log", {
182159
id: text().primaryKey(),
183160
userId: text().references(() => user.id),

src/lib/server/db/seed.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,10 @@ try {
1212
if (!process.env.DATABASE_URL) throw new Error("DATABASE_URL is not set");
1313

1414
const client = postgres(process.env.DATABASE_URL);
15-
const db = drizzle(client, { schema: table, casing: "snake_case" });
15+
const db = drizzle({ client, schema: table, casing: "snake_case" });
1616

1717
console.log("Resetting database...");
18-
await reset(db, {
19-
user: table.user,
20-
membership: table.membership,
21-
member: table.member,
22-
membershipType: table.membershipType,
23-
});
18+
await reset(db, table);
2419
console.log("Database reset!");
2520

2621
console.log("Seeding database...");

src/lib/server/payment/auto-approval.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export async function checkAutoApprovalEligibility(
2727
): Promise<boolean> {
2828
// Find the immediately preceding membership of the same type
2929
// (same membershipTypeId, endTime <= newMembership.startTime, most recent)
30-
const precedingMembership = await db.query.membership.findFirst({
30+
const precedingMembership = await db._query.membership.findFirst({
3131
where: and(
3232
eq(table.membership.membershipTypeId, newMembership.membershipTypeId),
3333
lte(table.membership.endTime, newMembership.startTime),
@@ -48,7 +48,7 @@ export async function checkAutoApprovalEligibility(
4848
// Check if user had an active member record for that preceding membership.
4949
// Only "active" qualifies — resigned members were deliberately removed by the
5050
// board at year-end (§8 p2) and should go through board review again.
51-
const previousMember = await db.query.member.findFirst({
51+
const previousMember = await db._query.member.findFirst({
5252
where: and(
5353
eq(table.member.userId, userId),
5454
eq(table.member.membershipId, precedingMembership.id),
@@ -76,7 +76,7 @@ export async function checkAutoApprovalEligibility(
7676
*/
7777
async function checkStudentEmail(db: DbHandle, userId: string): Promise<boolean> {
7878
// Check primary email
79-
const user = await db.query.user.findFirst({
79+
const user = await db._query.user.findFirst({
8080
where: eq(table.user.id, userId),
8181
columns: { email: true },
8282
});

src/lib/server/payment/session.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,11 +110,11 @@ async function createCheckoutSessionWithRetry(
110110
* @see {@link https://docs.stripe.com/checkout/quickstart}
111111
*/
112112
export async function createSession(userId: string, membershipId: string, locale: Locale, description?: string | null) {
113-
const membership = await db.query.membership.findFirst({
113+
const membership = await db._query.membership.findFirst({
114114
where: eq(table.membership.id, membershipId),
115115
with: { membershipType: true },
116116
});
117-
const user = await db.query.user.findFirst({
117+
const user = await db._query.user.findFirst({
118118
where: eq(table.user.id, userId),
119119
});
120120
if (!membership || !user) {
@@ -162,7 +162,7 @@ export async function createSession(userId: string, membershipId: string, locale
162162
* This is used when a user with "awaiting_payment" status wants to complete their payment.
163163
*/
164164
export async function resumeOrCreateSession(memberId: string, locale: Locale) {
165-
const member = await db.query.member.findFirst({
165+
const member = await db._query.member.findFirst({
166166
where: eq(table.member.id, memberId),
167167
with: {
168168
membership: {
@@ -306,7 +306,7 @@ export async function fulfillSession(sessionId: string) {
306306
// 3. Email failures are caught and logged without failing the transaction
307307
if (newStatus) {
308308
try {
309-
const memberWithDetails = await db.query.member.findFirst({
309+
const memberWithDetails = await db._query.member.findFirst({
310310
where: eq(table.member.id, memberId),
311311
with: {
312312
user: true,

0 commit comments

Comments
 (0)