feat: Implement custom error classes, a Drizzle transaction utility, and update Discord.js ephemeral message flags.
This commit is contained in:
@@ -1,30 +1,32 @@
|
||||
import { users, transactions, userTimers } from "@/db/schema";
|
||||
import { eq, sql, and } from "drizzle-orm";
|
||||
import { DrizzleClient } from "@/lib/DrizzleClient";
|
||||
import { config } from "@/lib/config";
|
||||
import { withTransaction } from "@/lib/db";
|
||||
import type { Transaction } from "@/lib/types";
|
||||
import { UserError } from "@/lib/errors";
|
||||
|
||||
export const economyService = {
|
||||
transfer: async (fromUserId: string, toUserId: string, amount: bigint, tx?: any) => {
|
||||
transfer: async (fromUserId: string, toUserId: string, amount: bigint, tx?: Transaction) => {
|
||||
if (amount <= 0n) {
|
||||
throw new Error("Amount must be positive");
|
||||
throw new UserError("Amount must be positive");
|
||||
}
|
||||
|
||||
if (fromUserId === toUserId) {
|
||||
throw new Error("Cannot transfer to self");
|
||||
throw new UserError("Cannot transfer to self");
|
||||
}
|
||||
|
||||
const execute = async (txFn: any) => {
|
||||
return await withTransaction(async (txFn) => {
|
||||
// Check sender balance
|
||||
const sender = await txFn.query.users.findFirst({
|
||||
where: eq(users.id, BigInt(fromUserId)),
|
||||
});
|
||||
|
||||
if (!sender) {
|
||||
throw new Error("Sender not found");
|
||||
throw new UserError("Sender not found");
|
||||
}
|
||||
|
||||
if ((sender.balance ?? 0n) < amount) {
|
||||
throw new Error("Insufficient funds");
|
||||
throw new UserError("Insufficient funds");
|
||||
}
|
||||
|
||||
// Deduct from sender
|
||||
@@ -59,19 +61,11 @@ export const economyService = {
|
||||
});
|
||||
|
||||
return { success: true, amount };
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
return await execute(tx);
|
||||
} else {
|
||||
return await DrizzleClient.transaction(async (t) => {
|
||||
return await execute(t);
|
||||
});
|
||||
}
|
||||
}, tx);
|
||||
},
|
||||
|
||||
claimDaily: async (userId: string, tx?: any) => {
|
||||
const execute = async (txFn: any) => {
|
||||
claimDaily: async (userId: string, tx?: Transaction) => {
|
||||
return await withTransaction(async (txFn) => {
|
||||
const now = new Date();
|
||||
const startOfDay = new Date(now);
|
||||
startOfDay.setHours(0, 0, 0, 0);
|
||||
@@ -86,7 +80,7 @@ export const economyService = {
|
||||
});
|
||||
|
||||
if (cooldown && cooldown.expiresAt > now) {
|
||||
throw new Error(`Daily already claimed. Ready at ${cooldown.expiresAt}`);
|
||||
throw new UserError(`Daily already claimed. Ready at ${cooldown.expiresAt}`);
|
||||
}
|
||||
|
||||
// Get user for streak logic
|
||||
@@ -95,7 +89,7 @@ export const economyService = {
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new Error("User not found");
|
||||
throw new Error("User not found"); // This might be system error because user should exist if authenticated, but keeping simple for now
|
||||
}
|
||||
|
||||
let streak = (user.dailyStreak || 0) + 1;
|
||||
@@ -145,26 +139,18 @@ export const economyService = {
|
||||
});
|
||||
|
||||
return { claimed: true, amount: totalReward, streak, nextReadyAt };
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
return await execute(tx);
|
||||
} else {
|
||||
return await DrizzleClient.transaction(async (t) => {
|
||||
return await execute(t);
|
||||
});
|
||||
}
|
||||
}, tx);
|
||||
},
|
||||
|
||||
modifyUserBalance: async (id: string, amount: bigint, type: string, description: string, relatedUserId?: string | null, tx?: any) => {
|
||||
const execute = async (txFn: any) => {
|
||||
modifyUserBalance: async (id: string, amount: bigint, type: string, description: string, relatedUserId?: string | null, tx?: Transaction) => {
|
||||
return await withTransaction(async (txFn) => {
|
||||
if (amount < 0n) {
|
||||
// Check sufficient funds if removing
|
||||
const user = await txFn.query.users.findFirst({
|
||||
where: eq(users.id, BigInt(id))
|
||||
});
|
||||
if (!user || (user.balance ?? 0n) < -amount) {
|
||||
throw new Error("Insufficient funds");
|
||||
throw new UserError("Insufficient funds");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,14 +170,6 @@ export const economyService = {
|
||||
});
|
||||
|
||||
return user;
|
||||
};
|
||||
|
||||
if (tx) {
|
||||
return await execute(tx);
|
||||
} else {
|
||||
return await DrizzleClient.transaction(async (t) => {
|
||||
return await execute(t);
|
||||
});
|
||||
}
|
||||
}, tx);
|
||||
},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user