Skip to content

Commit

Permalink
score history
Browse files Browse the repository at this point in the history
  • Loading branch information
uzairname committed Jan 25, 2024
1 parent 18c0432 commit d751e0c
Show file tree
Hide file tree
Showing 48 changed files with 1,330 additions and 908 deletions.
File renamed without changes.
2 changes: 1 addition & 1 deletion migrations/migrations/meta/0003_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"version": "5",
"dialect": "pg",
"id": "cb6a7381-9661-4cf9-98dd-388d86607f42",
"id": "a3ac305b-8d04-46a4-a2f8-8c475c20dffe",
"prevId": "01154bcb-b8f2-41a2-aa34-3e30129c9b2b",
"tables": {
"ActiveMatches": {
Expand Down
4 changes: 2 additions & 2 deletions migrations/migrations/meta/0004_snapshot.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"version": "5",
"dialect": "pg",
"id": "a67eb7dd-3606-404e-8263-904af626125b",
"prevId": "cb6a7381-9661-4cf9-98dd-388d86607f42",
"id": "315862f3-1893-4d66-8216-61015564147e",
"prevId": "a3ac305b-8d04-46a4-a2f8-8c475c20dffe",
"tables": {
"AccessTokens": {
"name": "AccessTokens",
Expand Down
8 changes: 4 additions & 4 deletions migrations/migrations/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
{
"idx": 3,
"version": "5",
"when": 1706043615998,
"tag": "0003_hot_sentinel",
"when": 1706068779439,
"tag": "0003_spooky_bloodaxe",
"breakpoints": true
},
{
"idx": 4,
"version": "5",
"when": 1706043636689,
"tag": "0004_free_iron_patriot",
"when": 1706068983826,
"tag": "0004_powerful_nick_fury",
"breakpoints": true
}
]
Expand Down
122 changes: 95 additions & 27 deletions src/database/models/models/matches.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,18 @@
import { and, eq, sql, desc, inArray, SQL } from 'drizzle-orm'
import { and, eq, sql, desc, inArray, SQL, asc } from 'drizzle-orm'
import { Player, Ranking } from '..'
import { sentry } from '../../../request/sentry'
import { cloneSimpleObj, nonNullable } from '../../../utils/utils'
import { nonNullable } from '../../../utils/utils'
import { DbClient } from '../../client'
import { DbErrors } from '../../errors'
import { DbObject, DbObjectManager } from '../../managers'
import { MatchPlayers, Matches, Players } from '../../schema'
import { MatchInsert, MatchPlayerSelect, MatchSelect, MatchUpdate, PlayerSelect } from '../../types'
import { MatchPlayers, MatchSummaryMessages, Matches, Players } from '../../schema'
import {
MatchInsert,
MatchPlayerSelect,
MatchSelect,
MatchSummaryMessageSelect,
MatchUpdate,
} from '../../types'

export class Match extends DbObject<MatchSelect> {
constructor(data: MatchSelect, db: DbClient) {
Expand Down Expand Up @@ -39,40 +46,76 @@ export class Match extends DbObject<MatchSelect> {
return player_teams
}

async summaryMessage(guild_id: string): Promise<MatchSummaryMessageSelect | undefined> {
const data = (
await this.db.db
.select()
.from(MatchSummaryMessages)
.where(
and(
eq(MatchSummaryMessages.match_id, this.data.id),
eq(MatchSummaryMessages.guild_id, guild_id),
),
)
)[0]
return data
}

async update(
data: { team_players_before: { id: number; rating: number; rd: number }[][] } & Omit<
MatchUpdate,
'team_players' | 'number'
data: Partial<
{ team_players: { id: number; rating_before: number; rd_before: number }[][] } & Omit<
MatchUpdate,
'team_players' | 'number'
>
>,
): Promise<this> {
this.data = (
await this.db.db
.update(Matches)
.set({
...data,
team_players: data.team_players_before.map(team => team.map(player => player.id)),
team_players: data.team_players?.map(team => team.map(player => player.id)),
})
.where(eq(Matches.id, this.data.id))
.returning()
)[0]

// update all match players' ratings and rd before
if (data.team_players) {
await this.updateMatchPlayers(data.team_players)
}

return this
}

async updateMatchPlayers(
team_players: { id: number; rating_before: number; rd_before: number }[][],
): Promise<this> {
sentry.debug(
`updating match players for match ${this.data.id}, ${JSON.stringify(
team_players.map(t => t.map(p => p.rating_before)),
)}`,
)
await Promise.all(
data.team_players_before.flat().map(player => {
team_players.flat().map(player =>
this.db.db
.update(MatchPlayers)
.set({
rating_before: player.rating,
rd_before: player.rd,
rating_before: player.rating_before,
rd_before: player.rd_before,
})
.where(
and(eq(MatchPlayers.match_id, this.data.id), eq(MatchPlayers.player_id, player.id)),
)
}),
),
),
)

return this
}

async delete(): Promise<void> {
await this.db.db.delete(Matches).where(eq(Matches.id, this.data.id))
delete this.db.cache.matches[this.data.id]
}
}

export class MatchesManager extends DbObjectManager {
Expand Down Expand Up @@ -111,16 +154,28 @@ export class MatchesManager extends DbObjectManager {
return new_match
}

async get(filters: {
async get(id: number): Promise<Match> {
if (this.db.cache.matches[id]) {
return this.db.cache.matches[id]
}

const data = (await this.db.db.select().from(Matches).where(eq(Matches.id, id)))[0]

if (!data) {
throw new DbErrors.NotFoundError(`Match ${id} doesn't exist`)
}

return new Match(data, this.db)
}

async getMany(filters: {
player_ids?: number[]
user_ids?: string[]
ranking_ids?: number[]
after?: Match
on_or_after?: Date
limit_matches?: number
offset?: number
}): Promise<{ match: Match; teams: { player: Player; match_player: MatchPlayerSelect }[][] }[]> {
const default_limit = 10

let sql_chunks: SQL[] = []

if (filters.player_ids) {
Expand All @@ -133,33 +188,46 @@ export class MatchesManager extends DbObjectManager {
if (filters.user_ids) {
sql_chunks.push(sql`${Matches.id} in (
select ${MatchPlayers.match_id} from ${MatchPlayers}
where ${Players.user_id} in ${filters.user_ids}
inner join ${Players} on ${Players.id} = ${MatchPlayers.player_id}
where ${Players.user_id} in ${filters.user_ids}
)`)
}

if (filters.ranking_ids) {
sql_chunks.push(inArray(Matches.ranking_id, filters.ranking_ids))
}

if (filters.after) {
const date = nonNullable(filters.after.data.time_finished, 'time_finished')
sql_chunks.push(sql`${Matches.time_finished} < ${date}`)
if (filters.on_or_after) {
sql_chunks.push(sql`${Matches.time_finished} >= ${filters.on_or_after}`)
}

const matches_sql = sql`
${Matches.id} in (select ${Matches.id} from ${Matches} where ${and(...sql_chunks)} order by ${
sentry.debug(`sql_chunks: ${sql_chunks}`, `and(...sql_chunks): ${and(...sql_chunks)}`)

const matches_sql_chunks = [
sql`select ${Matches.id} from ${Matches} where ${and(...sql_chunks)} order by ${
Matches.time_finished
} desc${filters.limit_matches ? sql` limit ${filters.limit_matches}` : ``} offset ${
filters.offset ?? 0
})
} desc`,
]

if (filters.limit_matches) {
matches_sql_chunks.push(sql` limit ${filters.limit_matches}`)
}

if (filters.offset) {
matches_sql_chunks.push(sql` offset ${filters.offset}`)
}

const matches_sql = sql`
${Matches.id} in (${sql.join(matches_sql_chunks)})
`

const result = await this.db.db
.select({ match: Matches, player: Players, match_player: MatchPlayers })
.from(Matches)
.innerJoin(MatchPlayers, eq(Matches.id, MatchPlayers.match_id))
.innerJoin(Players, eq(MatchPlayers.player_id, Players.id))
.where(matches_sql)
.orderBy(asc(Matches.time_finished))

const matches = new Map<
number,
Expand Down
14 changes: 10 additions & 4 deletions src/database/models/models/players.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { and, eq, sql } from 'drizzle-orm'
import { Ranking, Team, User } from '..'
import { sentry } from '../../../request/sentry'
import { DbClient } from '../../client'
import { DbErrors } from '../../errors'
import { DbObject, DbObjectManager } from '../../managers'
Expand All @@ -9,6 +10,7 @@ import { PlayerInsert, PlayerSelect } from '../../types'
export class Player extends DbObject<PlayerSelect> {
constructor(data: PlayerSelect, db: DbClient) {
super(data, db)
sentry.debug(`Created player with id ${data.id}, rating ${data.rating}`)
db.cache.players_by_id[data.id] = this
db.cache.players[data.ranking_id] ??= {}
db.cache.players[data.ranking_id][data.user_id] = this
Expand All @@ -19,12 +21,12 @@ export class Player extends DbObject<PlayerSelect> {
await this.db.db
.update(Players)
.set(data)
.where(and(
eq(Players.user_id, this.data.user_id),
eq(Players.ranking_id, this.data.ranking_id)
))
.where(
eq(Players.id, this.data.id),
)
.returning()
)[0] // prettier-ignore
sentry.debug(`Updated player ${this.data.id} rating to ${this.data.rating}`)
return this
}

Expand Down Expand Up @@ -107,6 +109,10 @@ export class PlayersManager extends DbObjectManager {
}

getPartial(id: number): Player {
if (this.db.cache.players_by_id[id]) {
// sentry.debug(`Using cached player ${id}. Rating is ${this.db.cache.players_by_id[id].data.rating}`)
return this.db.cache.players_by_id[id]
}
return new Player(
{
id,
Expand Down
14 changes: 7 additions & 7 deletions src/database/models/models/rankings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,17 @@ export class Ranking extends DbObject<Partial<RankingSelect> & { id: number }> {
*
* @returns The top players in this ranking, ordered by highest rating to lowest
*/
async getOrderedTopPlayers(): Promise<Player[]> {
sentry.debug('getting ordered top players')
const players = await this.db.db
async getOrderedTopPlayers(limit?: number): Promise<Player[]> {
const query = this.db.db
.select()
.from(Players)
.where(eq(Players.ranking_id, this.data.id))
.orderBy(desc(Players.rating))
// const players = await this.db.db.execute(
// sql`select * from "Players" where "Players".ranking_id=${this.data.id} order by "Players".rating desc`,
// )
sentry.debug(`got players`, players)

if (limit) query.limit(limit)

const players = await query

return players.map(item => {
return new Player(item, this.db)
})
Expand Down
2 changes: 0 additions & 2 deletions src/database/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const Users = pgTable('Users', {
linked_roles_ranking_id: integer('linked_roles_ranking_id')
})


export const AccessTokens = pgTable('AccessTokens', {
id: serial('id').primaryKey(),
user_id: text('user_id').notNull().references(() => Users.id, {onDelete: 'cascade'}),
Expand All @@ -25,7 +24,6 @@ export const AccessTokens = pgTable('AccessTokens', {
time_created: timestamp('time_created').defaultNow(),
})


export const Guilds = pgTable('Guilds', {
id: text('id').primaryKey(),
name: text('name'),
Expand Down
3 changes: 3 additions & 0 deletions src/database/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
GuildRankings,
Guilds,
MatchPlayers,
MatchSummaryMessages,
Matches,
Players,
Rankings,
Expand Down Expand Up @@ -46,5 +47,7 @@ export type MatchSelect = InferSelectModel<typeof Matches>
export type MatchInsert = Omit<InferInsertModel<typeof Matches>, 'id'>
export type MatchUpdate = Partial<Omit<MatchInsert, 'ranking_id'>>

export type MatchSummaryMessageSelect = InferSelectModel<typeof MatchSummaryMessages>

export type MatchPlayerSelect = InferSelectModel<typeof MatchPlayers>
export type MatchPlayerInsert = InferInsertModel<typeof MatchPlayers>
10 changes: 9 additions & 1 deletion src/discord-framework/interactions/deploy_commands.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { DiscordAPIError } from '@discordjs/rest'
import * as D from 'discord-api-types/v10'
import { AppError } from '../../main/app/errors'
import { sentry } from '../../request/sentry'
import type { DiscordAPIClient } from '../rest/client'
import { AnyAppCommand, viewIsChatInputAppCommand } from './types'
Expand All @@ -13,7 +15,13 @@ export async function overwriteDiscordCommandsWithViews(
if (guild_id === undefined) {
await bot.overwriteGlobalCommands(commands_data)
} else {
await bot.overwriteGuildCommands(guild_id, commands_data)
try {
await bot.overwriteGuildCommands(guild_id, commands_data)
} catch (e) {
if (e instanceof DiscordAPIError && e.code === D.RESTJSONErrorCodes.MissingAccess) {
throw new AppError(`Missing access to guild ${guild_id}`)
}
}
}

sentry.addBreadcrumb({
Expand Down
7 changes: 6 additions & 1 deletion src/discord-framework/interactions/views.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,12 @@ export abstract class View<TSchema extends StringDataSchema> {
return args.bot.createFollowupMessage(args.interaction.token, response_data)
},
edit: async (data: D.RESTPatchAPIWebhookWithTokenMessageJSONBody) => {
await args.bot.editOriginalInteractionResponse(args.interaction.token, data)
await args.bot.editOriginalInteractionResponse(args.interaction.token, {
content: null,
embeds: null,
components: null,
...data,
})
},
delete: async (message_id?: string) => {
await args.bot.deleteInteractionResponse(args.interaction.token, message_id)
Expand Down
Loading

0 comments on commit d751e0c

Please sign in to comment.