From 77d3fafdce7b9807561239718e3b49f786e74b98 Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Wed, 24 Dec 2025 21:57:14 +0100 Subject: [PATCH] refactor: standardize transaction pattern in class.service.ts Replace manual transaction handling with withTransaction helper pattern for consistency with other services (economy, inventory, quest, leveling). Also fix validation bug in modifyClassBalance: - Before: if (balance < amount) - After: if (balance + amount < 0n) This correctly validates negative amounts (debits) to prevent balances going below zero. --- src/modules/class/class.service.ts | 39 ++++++++++++++---------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/src/modules/class/class.service.ts b/src/modules/class/class.service.ts index a84fa5b..eb25bd2 100644 --- a/src/modules/class/class.service.ts +++ b/src/modules/class/class.service.ts @@ -2,14 +2,16 @@ import { classes, users } from "@/db/schema"; import { eq, sql } from "drizzle-orm"; import { DrizzleClient } from "@/lib/DrizzleClient"; import { UserError } from "@/lib/errors"; +import { withTransaction } from "@/lib/db"; +import type { Transaction } from "@/lib/types"; export const classService = { getAllClasses: async () => { return await DrizzleClient.query.classes.findMany(); }, - assignClass: async (userId: string, classId: bigint, tx?: any) => { - const execute = async (txFn: any) => { + assignClass: async (userId: string, classId: bigint, tx?: Transaction) => { + return await withTransaction(async (txFn) => { const cls = await txFn.query.classes.findFirst({ where: eq(classes.id, classId), }); @@ -22,8 +24,7 @@ export const classService = { .returning(); return user; - }; - return tx ? await execute(tx) : await DrizzleClient.transaction(execute); + }, tx); }, getClassBalance: async (classId: bigint) => { const cls = await DrizzleClient.query.classes.findFirst({ @@ -31,15 +32,15 @@ export const classService = { }); return cls?.balance || 0n; }, - modifyClassBalance: async (classId: bigint, amount: bigint, tx?: any) => { - const execute = async (txFn: any) => { + modifyClassBalance: async (classId: bigint, amount: bigint, tx?: Transaction) => { + return await withTransaction(async (txFn) => { const cls = await txFn.query.classes.findFirst({ where: eq(classes.id, classId), }); if (!cls) throw new UserError("Class not found"); - if ((cls.balance ?? 0n) < amount) { + if ((cls.balance ?? 0n) + amount < 0n) { throw new UserError("Insufficient class funds"); } @@ -51,35 +52,31 @@ export const classService = { .returning(); return updatedClass; - }; - return tx ? await execute(tx) : await DrizzleClient.transaction(execute); + }, tx); }, - updateClass: async (id: bigint, data: Partial, tx?: any) => { - const execute = async (txFn: any) => { + updateClass: async (id: bigint, data: Partial, tx?: Transaction) => { + return await withTransaction(async (txFn) => { const [updatedClass] = await txFn.update(classes) .set(data) .where(eq(classes.id, id)) .returning(); return updatedClass; - }; - return tx ? await execute(tx) : await DrizzleClient.transaction(execute); + }, tx); }, - createClass: async (data: typeof classes.$inferInsert, tx?: any) => { - const execute = async (txFn: any) => { + createClass: async (data: typeof classes.$inferInsert, tx?: Transaction) => { + return await withTransaction(async (txFn) => { const [newClass] = await txFn.insert(classes) .values(data) .returning(); return newClass; - }; - return tx ? await execute(tx) : await DrizzleClient.transaction(execute); + }, tx); }, - deleteClass: async (id: bigint, tx?: any) => { - const execute = async (txFn: any) => { + deleteClass: async (id: bigint, tx?: Transaction) => { + return await withTransaction(async (txFn) => { await txFn.delete(classes).where(eq(classes.id, id)); - }; - return tx ? await execute(tx) : await DrizzleClient.transaction(execute); + }, tx); } };