mirror of
https://github.com/qwerinope/qweribot.git
synced 2025-12-18 23:01:38 +01:00
rewrite kd leaderboard generation, add explicit relations to schema
This commit is contained in:
@@ -1,6 +1,5 @@
|
|||||||
import { Command, sendMessage } from "commands";
|
import { Command, sendMessage } from "commands";
|
||||||
import { getAllUserRecords } from "db/dbUser";
|
import { getKDLeaderboard } from "db/dbUser";
|
||||||
import { getTimeoutStats } from "lib/getStats";
|
|
||||||
import User from "user";
|
import User from "user";
|
||||||
|
|
||||||
type KD = { user: User; kd: number; };
|
type KD = { user: User; kd: number; };
|
||||||
@@ -10,27 +9,19 @@ export default new Command({
|
|||||||
aliases: ['alltimeleaderboard', 'alltimekdleaderboard'],
|
aliases: ['alltimeleaderboard', 'alltimekdleaderboard'],
|
||||||
usertype: 'chatter',
|
usertype: 'chatter',
|
||||||
execution: async msg => {
|
execution: async msg => {
|
||||||
const users = await getAllUserRecords();
|
const rawKD = await getKDLeaderboard();
|
||||||
if (!users) return;
|
if (rawKD.length === 0) {
|
||||||
|
|
||||||
const userKDs: KD[] = [];
|
|
||||||
await Promise.all(users.map(async userRecord => {
|
|
||||||
const user = await User.initUserId(userRecord.id.toString());
|
|
||||||
if (!user) return;
|
|
||||||
const data = await getTimeoutStats(user, false);
|
|
||||||
if (!data) return;
|
|
||||||
if (data.hit.blaster < 5) return;
|
|
||||||
|
|
||||||
let kd = data.shot.blaster / data.hit.blaster;
|
|
||||||
if (isNaN(kd)) kd = 0;
|
|
||||||
userKDs.push({ user, kd });
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (userKDs.length === 0) {
|
|
||||||
await sendMessage(`No users on leaderboard yet!`, msg.messageId);
|
await sendMessage(`No users on leaderboard yet!`, msg.messageId);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const userKDs: KD[] = [];
|
||||||
|
await Promise.all(rawKD.map(async userRecord => {
|
||||||
|
const user = await User.initUserId(userRecord.userId.toString());
|
||||||
|
if (!user) return;
|
||||||
|
userKDs.push({ user, kd: userRecord.KD })
|
||||||
|
}));
|
||||||
|
|
||||||
userKDs.sort((a, b) => b.kd - a.kd);
|
userKDs.sort((a, b) => b.kd - a.kd);
|
||||||
|
|
||||||
const txt: string[] = [];
|
const txt: string[] = [];
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { Command, sendMessage } from "commands";
|
import { Command, sendMessage } from "commands";
|
||||||
import { getAllUserRecords } from "db/dbUser";
|
import { getKDLeaderboard } from "db/dbUser";
|
||||||
import { getTimeoutStats } from "lib/getStats";
|
|
||||||
import User from "user";
|
import User from "user";
|
||||||
|
|
||||||
type KD = { user: User; kd: number; };
|
type KD = { user: User; kd: number; };
|
||||||
@@ -10,27 +9,21 @@ export default new Command({
|
|||||||
aliases: ['monthlyleaderboard', 'kdleaderboard', 'leaderboard'],
|
aliases: ['monthlyleaderboard', 'kdleaderboard', 'leaderboard'],
|
||||||
usertype: 'chatter',
|
usertype: 'chatter',
|
||||||
execution: async msg => {
|
execution: async msg => {
|
||||||
const users = await getAllUserRecords();
|
const monthdata = new Date().toISOString().slice(0, 7);
|
||||||
if (!users) return;
|
|
||||||
|
|
||||||
const userKDs: KD[] = [];
|
const rawKD = await getKDLeaderboard(monthdata);
|
||||||
await Promise.all(users.map(async userRecord => {
|
if (rawKD.length === 0) {
|
||||||
const user = await User.initUserId(userRecord.id.toString());
|
|
||||||
if (!user) return;
|
|
||||||
const data = await getTimeoutStats(user, true);
|
|
||||||
if (!data) return;
|
|
||||||
if (data.hit.blaster < 5) return;
|
|
||||||
|
|
||||||
let kd = data.shot.blaster / data.hit.blaster;
|
|
||||||
if (isNaN(kd)) kd = 0;
|
|
||||||
userKDs.push({ user, kd });
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (userKDs.length === 0) {
|
|
||||||
await sendMessage(`No users on leaderboard yet!`, msg.messageId);
|
await sendMessage(`No users on leaderboard yet!`, msg.messageId);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const userKDs: KD[] = [];
|
||||||
|
await Promise.all(rawKD.map(async userRecord => {
|
||||||
|
const user = await User.initUserId(userRecord.userId.toString());
|
||||||
|
if (!user) return;
|
||||||
|
userKDs.push({ user, kd: userRecord.KD })
|
||||||
|
}));
|
||||||
|
|
||||||
userKDs.sort((a, b) => b.kd - a.kd);
|
userKDs.sort((a, b) => b.kd - a.kd);
|
||||||
|
|
||||||
const txt: string[] = [];
|
const txt: string[] = [];
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { getLoots } from "db/schema";
|
|||||||
import type { inventory } from "items";
|
import type { inventory } from "items";
|
||||||
import type User from "user";
|
import type User from "user";
|
||||||
|
|
||||||
|
|
||||||
export async function createGetLootRecord(user: User, qbucks: number, inventory: inventory) {
|
export async function createGetLootRecord(user: User, qbucks: number, inventory: inventory) {
|
||||||
await db.insert(getLoots).values({
|
await db.insert(getLoots).values({
|
||||||
user: parseInt(user.id),
|
user: parseInt(user.id),
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import db from "db/connection";
|
import db from "db/connection";
|
||||||
import { users } from "db/schema";
|
import { timeouts, users } from "db/schema";
|
||||||
import { itemarray, type inventory } from "items";
|
import { itemarray, type inventory } from "items";
|
||||||
import type User from "user";
|
import type User from "user";
|
||||||
import logger from "lib/logger";
|
import { count, desc, eq, inArray, sql, ne, between, and, SQL } from "drizzle-orm";
|
||||||
import { desc, eq } from "drizzle-orm";
|
|
||||||
|
|
||||||
/** Use this function to both ensure existance and to retreive data */
|
/** Use this function to both ensure existance and to retreive data */
|
||||||
export async function getUserRecord(user: User) {
|
export async function getUserRecord(user: User) {
|
||||||
@@ -45,3 +44,49 @@ export async function updateUserRecord(user: User, newData: updateUser) {
|
|||||||
export async function getBalanceLeaderboard() {
|
export async function getBalanceLeaderboard() {
|
||||||
return await db.select().from(users).orderBy(desc(users.balance)).limit(10);
|
return await db.select().from(users).orderBy(desc(users.balance)).limit(10);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export async function getKDLeaderboard(monthData?: string) {
|
||||||
|
let condition: SQL<unknown> | 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 (isNaN(user.KD)) user.KD = 0;
|
||||||
|
return user
|
||||||
|
});
|
||||||
|
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import type { AccessToken } from "@twurple/auth";
|
import type { AccessToken } from "@twurple/auth";
|
||||||
import type { inventory, items } from "items";
|
import type { inventory, items } from "items";
|
||||||
|
|
||||||
import { integer, jsonb, pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core";
|
import { integer, jsonb, pgTable, timestamp, uuid, varchar } from "drizzle-orm/pg-core";
|
||||||
import type { anivBots } from "lib/handleAnivMessage";
|
import type { anivBots } from "lib/handleAnivMessage";
|
||||||
|
import { relations } from "drizzle-orm";
|
||||||
|
|
||||||
export const auth = pgTable('auth', {
|
export const auth = pgTable('auth', {
|
||||||
id: integer().primaryKey(),
|
id: integer().primaryKey(),
|
||||||
@@ -17,6 +17,16 @@ export const users = pgTable('users', {
|
|||||||
lastlootbox: timestamp().default(new Date(0)).notNull()
|
lastlootbox: timestamp().default(new Date(0)).notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const usersRelations = relations(users, ({ many }) => ({
|
||||||
|
timeouts_target: many(timeouts),
|
||||||
|
timeouts_shooter: many(timeouts),
|
||||||
|
usedItems: many(usedItems),
|
||||||
|
cheerEvents: many(cheerEvents),
|
||||||
|
cheers: many(cheers),
|
||||||
|
anivTimeouts: many(anivTimeouts),
|
||||||
|
getLoots: many(getLoots)
|
||||||
|
}));
|
||||||
|
|
||||||
export const timeouts = pgTable('timeouts', {
|
export const timeouts = pgTable('timeouts', {
|
||||||
id: uuid().defaultRandom().primaryKey(),
|
id: uuid().defaultRandom().primaryKey(),
|
||||||
user: integer().notNull().references(() => users.id),
|
user: integer().notNull().references(() => users.id),
|
||||||
@@ -25,6 +35,19 @@ export const timeouts = pgTable('timeouts', {
|
|||||||
created: timestamp().defaultNow().notNull()
|
created: timestamp().defaultNow().notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const timeoutsRelations = relations(timeouts, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [timeouts.user],
|
||||||
|
references: [users.id],
|
||||||
|
relationName: 'shooter'
|
||||||
|
}),
|
||||||
|
target: one(users, {
|
||||||
|
fields: [timeouts.target],
|
||||||
|
references: [users.id],
|
||||||
|
relationName: 'target'
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
export const usedItems = pgTable('usedItems', {
|
export const usedItems = pgTable('usedItems', {
|
||||||
id: uuid().defaultRandom().primaryKey(),
|
id: uuid().defaultRandom().primaryKey(),
|
||||||
user: integer().notNull().references(() => users.id),
|
user: integer().notNull().references(() => users.id),
|
||||||
@@ -32,6 +55,13 @@ export const usedItems = pgTable('usedItems', {
|
|||||||
created: timestamp().defaultNow().notNull()
|
created: timestamp().defaultNow().notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const usedItemsRelations = relations(usedItems, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [usedItems.user],
|
||||||
|
references: [users.id]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
export const cheerEvents = pgTable('cheerEvents', {
|
export const cheerEvents = pgTable('cheerEvents', {
|
||||||
id: uuid().defaultRandom().primaryKey(),
|
id: uuid().defaultRandom().primaryKey(),
|
||||||
user: integer().notNull().references(() => users.id),
|
user: integer().notNull().references(() => users.id),
|
||||||
@@ -39,6 +69,13 @@ export const cheerEvents = pgTable('cheerEvents', {
|
|||||||
created: timestamp().defaultNow().notNull()
|
created: timestamp().defaultNow().notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const cheerEventsRelations = relations(cheerEvents, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [cheerEvents.user],
|
||||||
|
references: [users.id]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
export const cheers = pgTable('cheers', {
|
export const cheers = pgTable('cheers', {
|
||||||
id: uuid().defaultRandom().primaryKey(),
|
id: uuid().defaultRandom().primaryKey(),
|
||||||
user: integer().notNull().references(() => users.id),
|
user: integer().notNull().references(() => users.id),
|
||||||
@@ -46,6 +83,13 @@ export const cheers = pgTable('cheers', {
|
|||||||
created: timestamp().defaultNow().notNull()
|
created: timestamp().defaultNow().notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const cheersRelations = relations(cheers, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [cheers.user],
|
||||||
|
references: [users.id]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
export const anivTimeouts = pgTable('anivTimeouts', {
|
export const anivTimeouts = pgTable('anivTimeouts', {
|
||||||
id: uuid().defaultRandom().primaryKey(),
|
id: uuid().defaultRandom().primaryKey(),
|
||||||
user: integer().notNull().references(() => users.id),
|
user: integer().notNull().references(() => users.id),
|
||||||
@@ -55,6 +99,13 @@ export const anivTimeouts = pgTable('anivTimeouts', {
|
|||||||
created: timestamp().defaultNow().notNull()
|
created: timestamp().defaultNow().notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const anivTimeoutsRelations = relations(anivTimeouts, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [anivTimeouts.user],
|
||||||
|
references: [users.id]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
export const getLoots = pgTable('getLoots', {
|
export const getLoots = pgTable('getLoots', {
|
||||||
id: uuid().defaultRandom().primaryKey(),
|
id: uuid().defaultRandom().primaryKey(),
|
||||||
user: integer().notNull().references(() => users.id),
|
user: integer().notNull().references(() => users.id),
|
||||||
@@ -62,3 +113,10 @@ export const getLoots = pgTable('getLoots', {
|
|||||||
items: jsonb().$type<inventory>().notNull(),
|
items: jsonb().$type<inventory>().notNull(),
|
||||||
created: timestamp().defaultNow().notNull()
|
created: timestamp().defaultNow().notNull()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const getLootsRelations = relations(getLoots, ({ one }) => ({
|
||||||
|
user: one(users, {
|
||||||
|
fields: [getLoots.user],
|
||||||
|
references: [users.id]
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|||||||
Reference in New Issue
Block a user