import db from "db/connection"; import { timeouts, users } from "db/schema"; import { and, between, count, desc, eq, type InferSelectModel, inArray, ne, type SQL, sql, } from "drizzle-orm"; import { itemarray, type items } from "items"; import { ANIVNAMES } from "lib/handleAnivMessage"; import type User from "user"; /** Use this function to both ensure existance and to retreive data */ export async function getUserRecord(user: User) { const data = await db.query.users.findFirst({ where: eq(users.id, parseInt(user.id, 10)), }); if (!data) return createUserRecord(user); if ( Object.keys(data.inventory).sort().toString() !== itemarray.sort().toString() ) { // If the items in the user inventory are missing an item. itemarray.forEach((key) => { if (!(key in data.inventory)) data.inventory[key] = 0; }); } return data; } export async function getAllUserRecords() { return await db.select().from(users); } async function createUserRecord(user: User) { return await db .insert(users) .values({ id: parseInt(user.id, 10), username: user.username, }) .returning() .then((a) => { if (!a[0]) throw Error("Something went horribly wrong"); return a[0]; }); } export type UserRecord = InferSelectModel; export async function updateUserRecord(user: User, newData: UserRecord) { await db .update(users) .set(newData) .where(eq(users.id, parseInt(user.id, 10))); return true; } export async function getBalanceLeaderboard() { return await db.select().from(users).orderBy(desc(users.balance)).limit(10); } export async function getKDLeaderboard(monthData?: string) { let condition: SQL | undefined = ne(timeouts.item, "silverbullet"); if (monthData) { const begin = Date.parse(monthData); const end = new Date(begin).setMonth(new Date(begin).getMonth() + 1); condition = and( condition, between(timeouts.created, new Date(begin), new Date(end)), ); } const usersGotShot = await db .select({ userId: users.id, amount: count(timeouts.target), }) .from(users) .innerJoin(timeouts, eq(users.id, timeouts.target)) .groupBy(users.id) .having(sql`count(${timeouts.id}) > 5`) .where(condition); const usersThatShot = await db .select({ userId: users.id, amount: count(timeouts.user), }) .from(users) .innerJoin(timeouts, eq(users.id, timeouts.user)) .groupBy(users.id) .where( and( condition, inArray( users.id, usersGotShot.map((a) => a.userId), ), ), ); const lookup = new Map(usersThatShot.map((a) => [a.userId, a.amount])); const result = usersGotShot.map((user) => ({ userId: user.userId, KD: lookup.get(user.userId)! / user.amount, })); result.map((user) => { if (Number.isNaN(user.KD)) user.KD = 0; return user; }); return result; } type ItemCounts = Record; export async function getTotalItemCounts(): Promise { const allUsers = await db .select({ username: users.username, inventory: users.inventory }) .from(users); const filteredUsers = allUsers.filter( (user) => !Array.from(ANIVNAMES).includes(user.username.toLowerCase()), ); const counts = itemarray.reduce((acc, item) => { acc[item] = filteredUsers.reduce((sum, user) => { return sum + (user.inventory[item] || 0); }, 0); return acc; }, {} as ItemCounts); return counts; }