@opprs/db-prisma 2.2.1-canary.55cd794 → 2.2.1-canary.5b08a34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +886 -156
- package/dist/index.d.cts +717 -105
- package/dist/index.d.ts +717 -105
- package/dist/index.js +802 -139
- package/package.json +2 -2
- package/prisma/migrations/20260104092800_add_location_model_and_tournament_fields/migration.sql +45 -0
- package/prisma/migrations/20260104210034_add_policy_acceptance_fields/migration.sql +19 -0
- package/prisma/migrations/20260104231435_split_entries_standings/migration.sql +137 -0
- package/prisma/migrations/20260105000000_add_oppr_ranking_models/migration.sql +108 -0
- package/prisma/schema.prisma +199 -37
- package/prisma/seed.ts +107 -35
package/dist/index.cjs
CHANGED
|
@@ -20,31 +20,70 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
applyRDDecayForInactivePlayers: () => applyRDDecayForInactivePlayers,
|
|
23
24
|
connect: () => connect,
|
|
25
|
+
countEntries: () => countEntries,
|
|
26
|
+
countLocations: () => countLocations,
|
|
27
|
+
countMatches: () => countMatches,
|
|
28
|
+
countOpprPlayerRankings: () => countOpprPlayerRankings,
|
|
29
|
+
countOpprRankingHistory: () => countOpprRankingHistory,
|
|
24
30
|
countPlayers: () => countPlayers,
|
|
25
|
-
|
|
31
|
+
countRounds: () => countRounds,
|
|
32
|
+
countStandings: () => countStandings,
|
|
26
33
|
countTournaments: () => countTournaments,
|
|
27
34
|
countUsers: () => countUsers,
|
|
28
|
-
|
|
35
|
+
createEntry: () => createEntry,
|
|
36
|
+
createLocation: () => createLocation,
|
|
37
|
+
createManyEntries: () => createManyEntries,
|
|
38
|
+
createManyMatches: () => createManyMatches,
|
|
39
|
+
createManyRounds: () => createManyRounds,
|
|
40
|
+
createManyStandings: () => createManyStandings,
|
|
41
|
+
createMatch: () => createMatch,
|
|
42
|
+
createOpprPlayerRanking: () => createOpprPlayerRanking,
|
|
43
|
+
createOpprRankingHistory: () => createOpprRankingHistory,
|
|
29
44
|
createPlayer: () => createPlayer,
|
|
30
|
-
|
|
45
|
+
createRound: () => createRound,
|
|
46
|
+
createStanding: () => createStanding,
|
|
31
47
|
createTournament: () => createTournament,
|
|
32
48
|
createUser: () => createUser,
|
|
33
49
|
createUserWithPlayer: () => createUserWithPlayer,
|
|
50
|
+
deleteEntriesByMatch: () => deleteEntriesByMatch,
|
|
51
|
+
deleteEntry: () => deleteEntry,
|
|
52
|
+
deleteLocation: () => deleteLocation,
|
|
53
|
+
deleteMatch: () => deleteMatch,
|
|
54
|
+
deleteMatchesByRound: () => deleteMatchesByRound,
|
|
55
|
+
deleteMatchesByTournament: () => deleteMatchesByTournament,
|
|
56
|
+
deleteOpprPlayerRanking: () => deleteOpprPlayerRanking,
|
|
34
57
|
deletePlayer: () => deletePlayer,
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
deleteRound: () => deleteRound,
|
|
59
|
+
deleteRoundsByTournament: () => deleteRoundsByTournament,
|
|
60
|
+
deleteStanding: () => deleteStanding,
|
|
61
|
+
deleteStandingsByTournament: () => deleteStandingsByTournament,
|
|
37
62
|
deleteTournament: () => deleteTournament,
|
|
38
63
|
deleteUser: () => deleteUser,
|
|
39
64
|
disconnect: () => disconnect,
|
|
65
|
+
findEntries: () => findEntries,
|
|
66
|
+
findEntryById: () => findEntryById,
|
|
67
|
+
findEntryByMatchAndPlayer: () => findEntryByMatchAndPlayer,
|
|
68
|
+
findLocationByExternalId: () => findLocationByExternalId,
|
|
69
|
+
findLocationById: () => findLocationById,
|
|
70
|
+
findLocations: () => findLocations,
|
|
71
|
+
findMatchById: () => findMatchById,
|
|
72
|
+
findMatches: () => findMatches,
|
|
73
|
+
findOpprPlayerRankingById: () => findOpprPlayerRankingById,
|
|
74
|
+
findOpprPlayerRankingByPlayerId: () => findOpprPlayerRankingByPlayerId,
|
|
75
|
+
findOpprPlayerRankings: () => findOpprPlayerRankings,
|
|
40
76
|
findPlayerByExternalId: () => findPlayerByExternalId,
|
|
41
77
|
findPlayerById: () => findPlayerById,
|
|
42
78
|
findPlayerByPlayerNumber: () => findPlayerByPlayerNumber,
|
|
43
79
|
findPlayerByUserEmail: () => findPlayerByUserEmail,
|
|
44
80
|
findPlayers: () => findPlayers,
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
81
|
+
findRoundById: () => findRoundById,
|
|
82
|
+
findRoundByTournamentAndNumber: () => findRoundByTournamentAndNumber,
|
|
83
|
+
findRounds: () => findRounds,
|
|
84
|
+
findStandingById: () => findStandingById,
|
|
85
|
+
findStandingByPlayerAndTournament: () => findStandingByPlayerAndTournament,
|
|
86
|
+
findStandings: () => findStandings,
|
|
48
87
|
findTournamentByExternalId: () => findTournamentByExternalId,
|
|
49
88
|
findTournamentById: () => findTournamentById,
|
|
50
89
|
findTournaments: () => findTournaments,
|
|
@@ -52,17 +91,38 @@ __export(index_exports, {
|
|
|
52
91
|
findUserById: () => findUserById,
|
|
53
92
|
findUsers: () => findUsers,
|
|
54
93
|
generateUniquePlayerNumber: () => generateUniquePlayerNumber,
|
|
94
|
+
getFinalsRounds: () => getFinalsRounds,
|
|
95
|
+
getFinalsStandings: () => getFinalsStandings,
|
|
96
|
+
getLatestOpprRankingHistory: () => getLatestOpprRankingHistory,
|
|
97
|
+
getLocationWithTournaments: () => getLocationWithTournaments,
|
|
55
98
|
getMajorTournaments: () => getMajorTournaments,
|
|
56
|
-
|
|
99
|
+
getMatchEntries: () => getMatchEntries,
|
|
100
|
+
getMatchWithEntries: () => getMatchWithEntries,
|
|
101
|
+
getMergedStandings: () => getMergedStandings,
|
|
102
|
+
getOpprRankingHistory: () => getOpprRankingHistory,
|
|
103
|
+
getOpprRankingHistoryByDateRange: () => getOpprRankingHistoryByDateRange,
|
|
104
|
+
getOrCreateOpprPlayerRanking: () => getOrCreateOpprPlayerRanking,
|
|
105
|
+
getPlayerEntries: () => getPlayerEntries,
|
|
106
|
+
getPlayerEntryStats: () => getPlayerEntryStats,
|
|
107
|
+
getPlayerStandings: () => getPlayerStandings,
|
|
57
108
|
getPlayerStats: () => getPlayerStats,
|
|
58
109
|
getPlayerTopFinishes: () => getPlayerTopFinishes,
|
|
110
|
+
getPlayerTournamentEntries: () => getPlayerTournamentEntries,
|
|
111
|
+
getPlayerTournamentMatches: () => getPlayerTournamentMatches,
|
|
59
112
|
getPlayerWithResults: () => getPlayerWithResults,
|
|
60
|
-
|
|
113
|
+
getQualifyingRounds: () => getQualifyingRounds,
|
|
114
|
+
getQualifyingStandings: () => getQualifyingStandings,
|
|
115
|
+
getRatedOpprPlayers: () => getRatedOpprPlayers,
|
|
61
116
|
getRecentTournaments: () => getRecentTournaments,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
117
|
+
getRoundMatches: () => getRoundMatches,
|
|
118
|
+
getRoundWithMatches: () => getRoundWithMatches,
|
|
119
|
+
getTopPlayersByOpprRanking: () => getTopPlayersByOpprRanking,
|
|
120
|
+
getTopPlayersByOpprRating: () => getTopPlayersByOpprRating,
|
|
121
|
+
getTournamentMatches: () => getTournamentMatches,
|
|
122
|
+
getTournamentRounds: () => getTournamentRounds,
|
|
123
|
+
getTournamentStandings: () => getTournamentStandings,
|
|
65
124
|
getTournamentStats: () => getTournamentStats,
|
|
125
|
+
getTournamentWithMatches: () => getTournamentWithMatches,
|
|
66
126
|
getTournamentWithResults: () => getTournamentWithResults,
|
|
67
127
|
getTournamentsByBoosterType: () => getTournamentsByBoosterType,
|
|
68
128
|
getTournamentsByDateRange: () => getTournamentsByDateRange,
|
|
@@ -72,16 +132,23 @@ __export(index_exports, {
|
|
|
72
132
|
linkPlayerToUser: () => linkPlayerToUser,
|
|
73
133
|
prisma: () => prisma,
|
|
74
134
|
recalculateTimeDecay: () => recalculateTimeDecay,
|
|
135
|
+
searchLocations: () => searchLocations,
|
|
75
136
|
searchPlayers: () => searchPlayers,
|
|
76
137
|
searchTournaments: () => searchTournaments,
|
|
77
138
|
testConnection: () => testConnection,
|
|
139
|
+
updateEntry: () => updateEntry,
|
|
140
|
+
updateLocation: () => updateLocation,
|
|
141
|
+
updateMatch: () => updateMatch,
|
|
142
|
+
updateOpprPlayerRanking: () => updateOpprPlayerRanking,
|
|
143
|
+
updateOpprRatingAfterTournament: () => updateOpprRatingAfterTournament,
|
|
78
144
|
updatePlayer: () => updatePlayer,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
145
|
+
updateRound: () => updateRound,
|
|
146
|
+
updateStanding: () => updateStanding,
|
|
147
|
+
updateStandingPoints: () => updateStandingPoints,
|
|
82
148
|
updateTournament: () => updateTournament,
|
|
83
149
|
updateUser: () => updateUser,
|
|
84
|
-
updateUserRefreshToken: () => updateUserRefreshToken
|
|
150
|
+
updateUserRefreshToken: () => updateUserRefreshToken,
|
|
151
|
+
updateWorldRankings: () => updateWorldRankings
|
|
85
152
|
});
|
|
86
153
|
module.exports = __toCommonJS(index_exports);
|
|
87
154
|
|
|
@@ -180,48 +247,12 @@ async function findPlayers(options = {}) {
|
|
|
180
247
|
include: options.include
|
|
181
248
|
});
|
|
182
249
|
}
|
|
183
|
-
async function getRatedPlayers(options = {}) {
|
|
184
|
-
return findPlayers({
|
|
185
|
-
...options,
|
|
186
|
-
where: { isRated: true }
|
|
187
|
-
});
|
|
188
|
-
}
|
|
189
|
-
async function getTopPlayersByRating(limit = 50) {
|
|
190
|
-
return findPlayers({
|
|
191
|
-
take: limit,
|
|
192
|
-
orderBy: { rating: "desc" },
|
|
193
|
-
where: { isRated: true }
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
async function getTopPlayersByRanking(limit = 50) {
|
|
197
|
-
return findPlayers({
|
|
198
|
-
take: limit,
|
|
199
|
-
orderBy: { ranking: "asc" },
|
|
200
|
-
where: {
|
|
201
|
-
isRated: true,
|
|
202
|
-
ranking: { not: null }
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
}
|
|
206
250
|
async function updatePlayer(id, data) {
|
|
207
251
|
return prisma.player.update({
|
|
208
252
|
where: { id },
|
|
209
253
|
data
|
|
210
254
|
});
|
|
211
255
|
}
|
|
212
|
-
async function updatePlayerRating(id, rating, ratingDeviation, eventCount) {
|
|
213
|
-
const updateData = {
|
|
214
|
-
rating,
|
|
215
|
-
ratingDeviation,
|
|
216
|
-
lastRatingUpdate: /* @__PURE__ */ new Date(),
|
|
217
|
-
lastEventDate: /* @__PURE__ */ new Date()
|
|
218
|
-
};
|
|
219
|
-
if (eventCount !== void 0) {
|
|
220
|
-
updateData.eventCount = eventCount;
|
|
221
|
-
updateData.isRated = eventCount >= 5;
|
|
222
|
-
}
|
|
223
|
-
return updatePlayer(id, updateData);
|
|
224
|
-
}
|
|
225
256
|
async function deletePlayer(id) {
|
|
226
257
|
return prisma.player.delete({
|
|
227
258
|
where: { id }
|
|
@@ -234,7 +265,7 @@ async function getPlayerWithResults(id) {
|
|
|
234
265
|
const player = await prisma.player.findUnique({
|
|
235
266
|
where: { id },
|
|
236
267
|
include: {
|
|
237
|
-
|
|
268
|
+
standings: {
|
|
238
269
|
include: {
|
|
239
270
|
tournament: true
|
|
240
271
|
},
|
|
@@ -251,7 +282,7 @@ async function getPlayerWithResults(id) {
|
|
|
251
282
|
}
|
|
252
283
|
return {
|
|
253
284
|
...player,
|
|
254
|
-
results: player.
|
|
285
|
+
results: player.standings
|
|
255
286
|
};
|
|
256
287
|
}
|
|
257
288
|
async function searchPlayers(query, limit = 20) {
|
|
@@ -263,6 +294,212 @@ async function searchPlayers(query, limit = 20) {
|
|
|
263
294
|
});
|
|
264
295
|
}
|
|
265
296
|
|
|
297
|
+
// src/oppr-rankings.ts
|
|
298
|
+
async function getOrCreateOpprPlayerRanking(playerId) {
|
|
299
|
+
const existing = await prisma.opprPlayerRanking.findUnique({
|
|
300
|
+
where: { playerId }
|
|
301
|
+
});
|
|
302
|
+
if (existing) return existing;
|
|
303
|
+
return prisma.opprPlayerRanking.create({
|
|
304
|
+
data: { playerId }
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
async function createOpprPlayerRanking(data) {
|
|
308
|
+
return prisma.opprPlayerRanking.create({
|
|
309
|
+
data
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
async function findOpprPlayerRankingById(id, include) {
|
|
313
|
+
return prisma.opprPlayerRanking.findUnique({
|
|
314
|
+
where: { id },
|
|
315
|
+
include
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
async function findOpprPlayerRankingByPlayerId(playerId, include) {
|
|
319
|
+
return prisma.opprPlayerRanking.findUnique({
|
|
320
|
+
where: { playerId },
|
|
321
|
+
include
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
async function findOpprPlayerRankings(options = {}) {
|
|
325
|
+
return prisma.opprPlayerRanking.findMany({
|
|
326
|
+
take: options.take,
|
|
327
|
+
skip: options.skip,
|
|
328
|
+
where: options.where,
|
|
329
|
+
orderBy: options.orderBy,
|
|
330
|
+
include: options.include
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
async function getTopPlayersByOpprRating(limit = 50) {
|
|
334
|
+
return prisma.opprPlayerRanking.findMany({
|
|
335
|
+
take: limit,
|
|
336
|
+
where: { isRated: true },
|
|
337
|
+
orderBy: { rating: "desc" },
|
|
338
|
+
include: { player: true }
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
async function getTopPlayersByOpprRanking(limit = 50) {
|
|
342
|
+
return prisma.opprPlayerRanking.findMany({
|
|
343
|
+
take: limit,
|
|
344
|
+
where: {
|
|
345
|
+
isRated: true,
|
|
346
|
+
ranking: { not: null }
|
|
347
|
+
},
|
|
348
|
+
orderBy: { ranking: "asc" },
|
|
349
|
+
include: { player: true }
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
async function getRatedOpprPlayers(options = {}) {
|
|
353
|
+
return prisma.opprPlayerRanking.findMany({
|
|
354
|
+
...options,
|
|
355
|
+
where: { isRated: true },
|
|
356
|
+
include: { player: true, ...options.include }
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
async function updateOpprPlayerRanking(playerId, data) {
|
|
360
|
+
return prisma.opprPlayerRanking.update({
|
|
361
|
+
where: { playerId },
|
|
362
|
+
data: {
|
|
363
|
+
...data,
|
|
364
|
+
lastRatingUpdate: data.lastRatingUpdate ?? /* @__PURE__ */ new Date()
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
async function updateOpprRatingAfterTournament(playerId, newRating, newRD, tournamentId, eventCount) {
|
|
369
|
+
const ranking = await getOrCreateOpprPlayerRanking(playerId);
|
|
370
|
+
const isRated = eventCount !== void 0 ? eventCount >= 5 : ranking.isRated;
|
|
371
|
+
const updated = await prisma.opprPlayerRanking.update({
|
|
372
|
+
where: { playerId },
|
|
373
|
+
data: {
|
|
374
|
+
rating: newRating,
|
|
375
|
+
ratingDeviation: newRD,
|
|
376
|
+
lastRatingUpdate: /* @__PURE__ */ new Date(),
|
|
377
|
+
isRated
|
|
378
|
+
}
|
|
379
|
+
});
|
|
380
|
+
await createOpprRankingHistory({
|
|
381
|
+
opprPlayerRankingId: ranking.id,
|
|
382
|
+
rating: newRating,
|
|
383
|
+
ratingDeviation: newRD,
|
|
384
|
+
ranking: updated.ranking ?? void 0,
|
|
385
|
+
isRated,
|
|
386
|
+
changeType: "TOURNAMENT_RESULT",
|
|
387
|
+
tournamentId
|
|
388
|
+
});
|
|
389
|
+
return updated;
|
|
390
|
+
}
|
|
391
|
+
async function updateWorldRankings(rankings) {
|
|
392
|
+
await prisma.$transaction(async (tx) => {
|
|
393
|
+
for (const { playerId, ranking } of rankings) {
|
|
394
|
+
const opprRanking = await tx.opprPlayerRanking.findUnique({
|
|
395
|
+
where: { playerId }
|
|
396
|
+
});
|
|
397
|
+
if (opprRanking) {
|
|
398
|
+
await tx.opprPlayerRanking.update({
|
|
399
|
+
where: { playerId },
|
|
400
|
+
data: { ranking }
|
|
401
|
+
});
|
|
402
|
+
await tx.opprRankingHistory.create({
|
|
403
|
+
data: {
|
|
404
|
+
opprPlayerRankingId: opprRanking.id,
|
|
405
|
+
rating: opprRanking.rating,
|
|
406
|
+
ratingDeviation: opprRanking.ratingDeviation,
|
|
407
|
+
ranking,
|
|
408
|
+
isRated: opprRanking.isRated,
|
|
409
|
+
changeType: "RANKING_REFRESH"
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
async function applyRDDecayForInactivePlayers(thresholdDays = 30, decayPerDay = 0.3, maxRD = 200) {
|
|
417
|
+
const cutoffDate = /* @__PURE__ */ new Date();
|
|
418
|
+
cutoffDate.setDate(cutoffDate.getDate() - thresholdDays);
|
|
419
|
+
const inactivePlayers = await prisma.opprPlayerRanking.findMany({
|
|
420
|
+
where: {
|
|
421
|
+
lastRatingUpdate: { lt: cutoffDate },
|
|
422
|
+
ratingDeviation: { lt: maxRD }
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
let updatedCount = 0;
|
|
426
|
+
await prisma.$transaction(async (tx) => {
|
|
427
|
+
for (const ranking of inactivePlayers) {
|
|
428
|
+
const daysSinceUpdate = Math.floor(
|
|
429
|
+
(Date.now() - ranking.lastRatingUpdate.getTime()) / (1e3 * 60 * 60 * 24)
|
|
430
|
+
);
|
|
431
|
+
const newRD = Math.min(ranking.ratingDeviation + daysSinceUpdate * decayPerDay, maxRD);
|
|
432
|
+
await tx.opprPlayerRanking.update({
|
|
433
|
+
where: { id: ranking.id },
|
|
434
|
+
data: { ratingDeviation: newRD }
|
|
435
|
+
});
|
|
436
|
+
await tx.opprRankingHistory.create({
|
|
437
|
+
data: {
|
|
438
|
+
opprPlayerRankingId: ranking.id,
|
|
439
|
+
rating: ranking.rating,
|
|
440
|
+
ratingDeviation: newRD,
|
|
441
|
+
ranking: ranking.ranking,
|
|
442
|
+
isRated: ranking.isRated,
|
|
443
|
+
changeType: "RD_DECAY",
|
|
444
|
+
notes: `RD increased from ${ranking.ratingDeviation.toFixed(1)} to ${newRD.toFixed(1)} due to ${daysSinceUpdate} days of inactivity`
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
updatedCount++;
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
return updatedCount;
|
|
451
|
+
}
|
|
452
|
+
async function deleteOpprPlayerRanking(playerId) {
|
|
453
|
+
return prisma.opprPlayerRanking.delete({
|
|
454
|
+
where: { playerId }
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
async function countOpprPlayerRankings(where) {
|
|
458
|
+
return prisma.opprPlayerRanking.count({ where });
|
|
459
|
+
}
|
|
460
|
+
async function createOpprRankingHistory(data) {
|
|
461
|
+
return prisma.opprRankingHistory.create({
|
|
462
|
+
data
|
|
463
|
+
});
|
|
464
|
+
}
|
|
465
|
+
async function getOpprRankingHistory(playerId, limit) {
|
|
466
|
+
const ranking = await findOpprPlayerRankingByPlayerId(playerId);
|
|
467
|
+
if (!ranking) return [];
|
|
468
|
+
return prisma.opprRankingHistory.findMany({
|
|
469
|
+
where: { opprPlayerRankingId: ranking.id },
|
|
470
|
+
orderBy: { createdAt: "desc" },
|
|
471
|
+
take: limit,
|
|
472
|
+
include: { tournament: true }
|
|
473
|
+
});
|
|
474
|
+
}
|
|
475
|
+
async function getOpprRankingHistoryByDateRange(playerId, startDate, endDate) {
|
|
476
|
+
const ranking = await findOpprPlayerRankingByPlayerId(playerId);
|
|
477
|
+
if (!ranking) return [];
|
|
478
|
+
return prisma.opprRankingHistory.findMany({
|
|
479
|
+
where: {
|
|
480
|
+
opprPlayerRankingId: ranking.id,
|
|
481
|
+
createdAt: {
|
|
482
|
+
gte: startDate,
|
|
483
|
+
lte: endDate
|
|
484
|
+
}
|
|
485
|
+
},
|
|
486
|
+
orderBy: { createdAt: "asc" },
|
|
487
|
+
include: { tournament: true }
|
|
488
|
+
});
|
|
489
|
+
}
|
|
490
|
+
async function getLatestOpprRankingHistory(playerId) {
|
|
491
|
+
const ranking = await findOpprPlayerRankingByPlayerId(playerId);
|
|
492
|
+
if (!ranking) return null;
|
|
493
|
+
return prisma.opprRankingHistory.findFirst({
|
|
494
|
+
where: { opprPlayerRankingId: ranking.id },
|
|
495
|
+
orderBy: { createdAt: "desc" },
|
|
496
|
+
include: { tournament: true }
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
async function countOpprRankingHistory(where) {
|
|
500
|
+
return prisma.opprRankingHistory.count({ where });
|
|
501
|
+
}
|
|
502
|
+
|
|
266
503
|
// src/tournaments.ts
|
|
267
504
|
async function createTournament(data) {
|
|
268
505
|
return prisma.tournament.create({
|
|
@@ -342,13 +579,33 @@ async function getTournamentWithResults(id) {
|
|
|
342
579
|
return prisma.tournament.findUnique({
|
|
343
580
|
where: { id },
|
|
344
581
|
include: {
|
|
345
|
-
|
|
582
|
+
standings: {
|
|
346
583
|
include: {
|
|
347
584
|
player: true
|
|
348
585
|
},
|
|
349
|
-
orderBy: {
|
|
350
|
-
|
|
351
|
-
|
|
586
|
+
orderBy: [{ isFinals: "desc" }, { position: "asc" }]
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
async function getTournamentWithMatches(id) {
|
|
592
|
+
return prisma.tournament.findUnique({
|
|
593
|
+
where: { id },
|
|
594
|
+
include: {
|
|
595
|
+
rounds: {
|
|
596
|
+
include: {
|
|
597
|
+
matches: {
|
|
598
|
+
include: {
|
|
599
|
+
entries: {
|
|
600
|
+
include: {
|
|
601
|
+
player: true
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
},
|
|
605
|
+
orderBy: { number: "asc" }
|
|
606
|
+
}
|
|
607
|
+
},
|
|
608
|
+
orderBy: [{ isFinals: "asc" }, { number: "asc" }]
|
|
352
609
|
}
|
|
353
610
|
}
|
|
354
611
|
});
|
|
@@ -359,7 +616,7 @@ async function searchTournaments(query, limit = 20) {
|
|
|
359
616
|
where: {
|
|
360
617
|
OR: [
|
|
361
618
|
{ name: { contains: query, mode: "insensitive" } },
|
|
362
|
-
{ location: { contains: query, mode: "insensitive" } }
|
|
619
|
+
{ location: { name: { contains: query, mode: "insensitive" } } }
|
|
363
620
|
]
|
|
364
621
|
},
|
|
365
622
|
orderBy: { date: "desc" }
|
|
@@ -370,7 +627,7 @@ async function getTournamentStats(id) {
|
|
|
370
627
|
if (!tournament) {
|
|
371
628
|
return null;
|
|
372
629
|
}
|
|
373
|
-
const playerCount = tournament.
|
|
630
|
+
const playerCount = tournament.standings.length;
|
|
374
631
|
if (playerCount === 0) {
|
|
375
632
|
return {
|
|
376
633
|
tournament,
|
|
@@ -381,9 +638,9 @@ async function getTournamentStats(id) {
|
|
|
381
638
|
lowestPoints: 0
|
|
382
639
|
};
|
|
383
640
|
}
|
|
384
|
-
const totalPoints = tournament.
|
|
385
|
-
const totalEfficiency = tournament.
|
|
386
|
-
const allPoints = tournament.
|
|
641
|
+
const totalPoints = tournament.standings.reduce((sum, s) => sum + (s.totalPoints || 0), 0);
|
|
642
|
+
const totalEfficiency = tournament.standings.reduce((sum, s) => sum + (s.efficiency || 0), 0);
|
|
643
|
+
const allPoints = tournament.standings.map((s) => s.totalPoints || 0);
|
|
387
644
|
return {
|
|
388
645
|
tournament,
|
|
389
646
|
playerCount,
|
|
@@ -394,44 +651,364 @@ async function getTournamentStats(id) {
|
|
|
394
651
|
};
|
|
395
652
|
}
|
|
396
653
|
|
|
397
|
-
// src/
|
|
398
|
-
async function
|
|
399
|
-
|
|
654
|
+
// src/rounds.ts
|
|
655
|
+
async function createRound(data) {
|
|
656
|
+
return prisma.round.create({
|
|
657
|
+
data: {
|
|
658
|
+
...data,
|
|
659
|
+
isFinals: data.isFinals ?? false
|
|
660
|
+
}
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
async function createManyRounds(data) {
|
|
664
|
+
const roundsData = data.map((item) => ({
|
|
665
|
+
...item,
|
|
666
|
+
isFinals: item.isFinals ?? false
|
|
667
|
+
}));
|
|
668
|
+
return prisma.round.createMany({
|
|
669
|
+
data: roundsData
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
async function findRoundById(id, include) {
|
|
673
|
+
return prisma.round.findUnique({
|
|
674
|
+
where: { id },
|
|
675
|
+
include
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
async function findRoundByTournamentAndNumber(tournamentId, number, isFinals, include) {
|
|
679
|
+
return prisma.round.findUnique({
|
|
680
|
+
where: {
|
|
681
|
+
tournamentId_number_isFinals: {
|
|
682
|
+
tournamentId,
|
|
683
|
+
number,
|
|
684
|
+
isFinals
|
|
685
|
+
}
|
|
686
|
+
},
|
|
687
|
+
include
|
|
688
|
+
});
|
|
689
|
+
}
|
|
690
|
+
async function findRounds(options = {}) {
|
|
691
|
+
return prisma.round.findMany({
|
|
692
|
+
take: options.take,
|
|
693
|
+
skip: options.skip,
|
|
694
|
+
where: options.where,
|
|
695
|
+
orderBy: options.orderBy,
|
|
696
|
+
include: options.include
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
async function getTournamentRounds(tournamentId, options = {}) {
|
|
700
|
+
return findRounds({
|
|
701
|
+
...options,
|
|
702
|
+
where: { tournamentId },
|
|
703
|
+
orderBy: options.orderBy ?? [{ isFinals: "asc" }, { number: "asc" }]
|
|
704
|
+
});
|
|
705
|
+
}
|
|
706
|
+
async function getQualifyingRounds(tournamentId, options = {}) {
|
|
707
|
+
return findRounds({
|
|
708
|
+
...options,
|
|
709
|
+
where: { tournamentId, isFinals: false },
|
|
710
|
+
orderBy: options.orderBy ?? { number: "asc" }
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
async function getFinalsRounds(tournamentId, options = {}) {
|
|
714
|
+
return findRounds({
|
|
715
|
+
...options,
|
|
716
|
+
where: { tournamentId, isFinals: true },
|
|
717
|
+
orderBy: options.orderBy ?? { number: "asc" }
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
async function updateRound(id, data) {
|
|
721
|
+
return prisma.round.update({
|
|
722
|
+
where: { id },
|
|
723
|
+
data
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
async function deleteRound(id) {
|
|
727
|
+
return prisma.round.delete({
|
|
728
|
+
where: { id }
|
|
729
|
+
});
|
|
730
|
+
}
|
|
731
|
+
async function deleteRoundsByTournament(tournamentId) {
|
|
732
|
+
return prisma.round.deleteMany({
|
|
733
|
+
where: { tournamentId }
|
|
734
|
+
});
|
|
735
|
+
}
|
|
736
|
+
async function countRounds(where) {
|
|
737
|
+
return prisma.round.count({ where });
|
|
738
|
+
}
|
|
739
|
+
async function getRoundWithMatches(id) {
|
|
740
|
+
return prisma.round.findUnique({
|
|
741
|
+
where: { id },
|
|
742
|
+
include: {
|
|
743
|
+
matches: {
|
|
744
|
+
include: {
|
|
745
|
+
entries: {
|
|
746
|
+
include: {
|
|
747
|
+
player: true
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
},
|
|
751
|
+
orderBy: {
|
|
752
|
+
number: "asc"
|
|
753
|
+
}
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
// src/matches.ts
|
|
760
|
+
async function createMatch(data) {
|
|
761
|
+
return prisma.match.create({
|
|
762
|
+
data
|
|
763
|
+
});
|
|
764
|
+
}
|
|
765
|
+
async function createManyMatches(data) {
|
|
766
|
+
return prisma.match.createMany({
|
|
767
|
+
data
|
|
768
|
+
});
|
|
769
|
+
}
|
|
770
|
+
async function findMatchById(id, include) {
|
|
771
|
+
return prisma.match.findUnique({
|
|
772
|
+
where: { id },
|
|
773
|
+
include
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
async function findMatches(options = {}) {
|
|
777
|
+
return prisma.match.findMany({
|
|
778
|
+
take: options.take,
|
|
779
|
+
skip: options.skip,
|
|
780
|
+
where: options.where,
|
|
781
|
+
orderBy: options.orderBy,
|
|
782
|
+
include: options.include
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
async function getTournamentMatches(tournamentId, options = {}) {
|
|
786
|
+
return findMatches({
|
|
787
|
+
...options,
|
|
788
|
+
where: { tournamentId },
|
|
789
|
+
orderBy: options.orderBy ?? { number: "asc" }
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
async function getRoundMatches(roundId, options = {}) {
|
|
793
|
+
return findMatches({
|
|
794
|
+
...options,
|
|
795
|
+
where: { roundId },
|
|
796
|
+
orderBy: options.orderBy ?? { number: "asc" }
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
async function updateMatch(id, data) {
|
|
800
|
+
return prisma.match.update({
|
|
801
|
+
where: { id },
|
|
802
|
+
data
|
|
803
|
+
});
|
|
804
|
+
}
|
|
805
|
+
async function deleteMatch(id) {
|
|
806
|
+
return prisma.match.delete({
|
|
807
|
+
where: { id }
|
|
808
|
+
});
|
|
809
|
+
}
|
|
810
|
+
async function deleteMatchesByTournament(tournamentId) {
|
|
811
|
+
return prisma.match.deleteMany({
|
|
812
|
+
where: { tournamentId }
|
|
813
|
+
});
|
|
814
|
+
}
|
|
815
|
+
async function deleteMatchesByRound(roundId) {
|
|
816
|
+
return prisma.match.deleteMany({
|
|
817
|
+
where: { roundId }
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
async function countMatches(where) {
|
|
821
|
+
return prisma.match.count({ where });
|
|
822
|
+
}
|
|
823
|
+
async function getMatchWithEntries(id) {
|
|
824
|
+
return prisma.match.findUnique({
|
|
825
|
+
where: { id },
|
|
826
|
+
include: {
|
|
827
|
+
entries: {
|
|
828
|
+
include: {
|
|
829
|
+
player: true
|
|
830
|
+
},
|
|
831
|
+
orderBy: {
|
|
832
|
+
position: "asc"
|
|
833
|
+
}
|
|
834
|
+
},
|
|
835
|
+
round: true
|
|
836
|
+
}
|
|
837
|
+
});
|
|
838
|
+
}
|
|
839
|
+
async function getPlayerTournamentMatches(playerId, tournamentId, include) {
|
|
840
|
+
return findMatches({
|
|
841
|
+
where: {
|
|
842
|
+
tournamentId,
|
|
843
|
+
entries: {
|
|
844
|
+
some: {
|
|
845
|
+
playerId
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
},
|
|
849
|
+
include: include ?? {
|
|
850
|
+
entries: {
|
|
851
|
+
include: {
|
|
852
|
+
player: true
|
|
853
|
+
}
|
|
854
|
+
},
|
|
855
|
+
round: true
|
|
856
|
+
},
|
|
857
|
+
orderBy: [{ round: { number: "asc" } }, { number: "asc" }]
|
|
858
|
+
});
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// src/entries.ts
|
|
862
|
+
async function createEntry(data) {
|
|
863
|
+
return prisma.entry.create({
|
|
864
|
+
data
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
async function createManyEntries(data) {
|
|
868
|
+
return prisma.entry.createMany({
|
|
869
|
+
data
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
async function findEntryById(id, include) {
|
|
873
|
+
return prisma.entry.findUnique({
|
|
874
|
+
where: { id },
|
|
875
|
+
include
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
async function findEntryByMatchAndPlayer(matchId, playerId, include) {
|
|
879
|
+
return prisma.entry.findUnique({
|
|
880
|
+
where: {
|
|
881
|
+
matchId_playerId: {
|
|
882
|
+
matchId,
|
|
883
|
+
playerId
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
include
|
|
887
|
+
});
|
|
888
|
+
}
|
|
889
|
+
async function findEntries(options = {}) {
|
|
890
|
+
return prisma.entry.findMany({
|
|
891
|
+
take: options.take,
|
|
892
|
+
skip: options.skip,
|
|
893
|
+
where: options.where,
|
|
894
|
+
orderBy: options.orderBy,
|
|
895
|
+
include: options.include
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
async function getMatchEntries(matchId, options = {}) {
|
|
899
|
+
return findEntries({
|
|
900
|
+
...options,
|
|
901
|
+
where: { matchId },
|
|
902
|
+
include: options.include ?? { player: true },
|
|
903
|
+
orderBy: options.orderBy ?? { position: "asc" }
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
async function getPlayerEntries(playerId, options = {}) {
|
|
907
|
+
return findEntries({
|
|
908
|
+
...options,
|
|
909
|
+
where: { playerId },
|
|
910
|
+
include: options.include ?? { match: { include: { round: true, tournament: true } } }
|
|
911
|
+
});
|
|
912
|
+
}
|
|
913
|
+
async function getPlayerTournamentEntries(playerId, tournamentId, include) {
|
|
914
|
+
return findEntries({
|
|
915
|
+
where: {
|
|
916
|
+
playerId,
|
|
917
|
+
match: {
|
|
918
|
+
tournamentId
|
|
919
|
+
}
|
|
920
|
+
},
|
|
921
|
+
include: include ?? {
|
|
922
|
+
match: {
|
|
923
|
+
include: {
|
|
924
|
+
round: true,
|
|
925
|
+
entries: {
|
|
926
|
+
include: {
|
|
927
|
+
player: true
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
async function updateEntry(id, data) {
|
|
936
|
+
return prisma.entry.update({
|
|
937
|
+
where: { id },
|
|
938
|
+
data
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
async function deleteEntry(id) {
|
|
942
|
+
return prisma.entry.delete({
|
|
943
|
+
where: { id }
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
async function deleteEntriesByMatch(matchId) {
|
|
947
|
+
return prisma.entry.deleteMany({
|
|
948
|
+
where: { matchId }
|
|
949
|
+
});
|
|
950
|
+
}
|
|
951
|
+
async function countEntries(where) {
|
|
952
|
+
return prisma.entry.count({ where });
|
|
953
|
+
}
|
|
954
|
+
async function getPlayerEntryStats(playerId) {
|
|
955
|
+
const entries = await getPlayerEntries(playerId);
|
|
956
|
+
if (entries.length === 0) {
|
|
957
|
+
return null;
|
|
958
|
+
}
|
|
959
|
+
const wins = entries.filter((e) => e.result === "WIN").length;
|
|
960
|
+
const losses = entries.filter((e) => e.result === "LOSS").length;
|
|
961
|
+
const ties = entries.filter((e) => e.result === "TIE").length;
|
|
962
|
+
return {
|
|
963
|
+
totalMatches: entries.length,
|
|
964
|
+
wins,
|
|
965
|
+
losses,
|
|
966
|
+
ties,
|
|
967
|
+
winRate: wins / entries.length
|
|
968
|
+
};
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
// src/standings.ts
|
|
972
|
+
async function createStanding(data) {
|
|
973
|
+
const standingData = {
|
|
400
974
|
...data,
|
|
975
|
+
isFinals: data.isFinals ?? false,
|
|
401
976
|
decayedPoints: data.decayedPoints ?? data.totalPoints ?? 0
|
|
402
977
|
};
|
|
403
|
-
return prisma.
|
|
404
|
-
data:
|
|
978
|
+
return prisma.standing.create({
|
|
979
|
+
data: standingData
|
|
405
980
|
});
|
|
406
981
|
}
|
|
407
|
-
async function
|
|
408
|
-
const
|
|
982
|
+
async function createManyStandings(data) {
|
|
983
|
+
const standingsData = data.map((item) => ({
|
|
409
984
|
...item,
|
|
985
|
+
isFinals: item.isFinals ?? false,
|
|
410
986
|
decayedPoints: item.decayedPoints ?? item.totalPoints ?? 0
|
|
411
987
|
}));
|
|
412
|
-
return prisma.
|
|
413
|
-
data:
|
|
988
|
+
return prisma.standing.createMany({
|
|
989
|
+
data: standingsData
|
|
414
990
|
});
|
|
415
991
|
}
|
|
416
|
-
async function
|
|
417
|
-
return prisma.
|
|
992
|
+
async function findStandingById(id, include) {
|
|
993
|
+
return prisma.standing.findUnique({
|
|
418
994
|
where: { id },
|
|
419
995
|
include
|
|
420
996
|
});
|
|
421
997
|
}
|
|
422
|
-
async function
|
|
423
|
-
return prisma.
|
|
998
|
+
async function findStandingByPlayerAndTournament(playerId, tournamentId, isFinals, include) {
|
|
999
|
+
return prisma.standing.findUnique({
|
|
424
1000
|
where: {
|
|
425
|
-
|
|
1001
|
+
playerId_tournamentId_isFinals: {
|
|
426
1002
|
playerId,
|
|
427
|
-
tournamentId
|
|
1003
|
+
tournamentId,
|
|
1004
|
+
isFinals
|
|
428
1005
|
}
|
|
429
1006
|
},
|
|
430
1007
|
include
|
|
431
1008
|
});
|
|
432
1009
|
}
|
|
433
|
-
async function
|
|
434
|
-
return prisma.
|
|
1010
|
+
async function findStandings(options = {}) {
|
|
1011
|
+
return prisma.standing.findMany({
|
|
435
1012
|
take: options.take,
|
|
436
1013
|
skip: options.skip,
|
|
437
1014
|
where: options.where,
|
|
@@ -439,45 +1016,85 @@ async function findResults(options = {}) {
|
|
|
439
1016
|
include: options.include
|
|
440
1017
|
});
|
|
441
1018
|
}
|
|
442
|
-
async function
|
|
443
|
-
return
|
|
1019
|
+
async function getPlayerStandings(playerId, options = {}) {
|
|
1020
|
+
return findStandings({
|
|
444
1021
|
...options,
|
|
445
1022
|
where: { playerId },
|
|
446
1023
|
include: { tournament: true, ...options.include },
|
|
447
1024
|
orderBy: { tournament: { date: "desc" } }
|
|
448
1025
|
});
|
|
449
1026
|
}
|
|
450
|
-
async function
|
|
451
|
-
return
|
|
1027
|
+
async function getTournamentStandings(tournamentId, options = {}) {
|
|
1028
|
+
return findStandings({
|
|
452
1029
|
...options,
|
|
453
1030
|
where: { tournamentId },
|
|
454
1031
|
include: { player: true, ...options.include },
|
|
455
|
-
orderBy: { position: "asc" }
|
|
1032
|
+
orderBy: options.orderBy ?? { position: "asc" }
|
|
1033
|
+
});
|
|
1034
|
+
}
|
|
1035
|
+
async function getQualifyingStandings(tournamentId, options = {}) {
|
|
1036
|
+
return findStandings({
|
|
1037
|
+
...options,
|
|
1038
|
+
where: { tournamentId, isFinals: false },
|
|
1039
|
+
include: { player: true, ...options.include },
|
|
1040
|
+
orderBy: options.orderBy ?? { position: "asc" }
|
|
456
1041
|
});
|
|
457
1042
|
}
|
|
1043
|
+
async function getFinalsStandings(tournamentId, options = {}) {
|
|
1044
|
+
return findStandings({
|
|
1045
|
+
...options,
|
|
1046
|
+
where: { tournamentId, isFinals: true },
|
|
1047
|
+
include: { player: true, ...options.include },
|
|
1048
|
+
orderBy: options.orderBy ?? { position: "asc" }
|
|
1049
|
+
});
|
|
1050
|
+
}
|
|
1051
|
+
async function getMergedStandings(tournamentId) {
|
|
1052
|
+
const [finals, qualifying] = await Promise.all([
|
|
1053
|
+
findStandings({
|
|
1054
|
+
where: { tournamentId, isFinals: true },
|
|
1055
|
+
orderBy: { position: "asc" },
|
|
1056
|
+
include: { player: true }
|
|
1057
|
+
}),
|
|
1058
|
+
findStandings({
|
|
1059
|
+
where: { tournamentId, isFinals: false },
|
|
1060
|
+
orderBy: { position: "asc" },
|
|
1061
|
+
include: { player: true }
|
|
1062
|
+
})
|
|
1063
|
+
]);
|
|
1064
|
+
const finalistIds = new Set(finals.map((s) => s.playerId));
|
|
1065
|
+
const nonFinalists = qualifying.filter((s) => !finalistIds.has(s.playerId));
|
|
1066
|
+
return [
|
|
1067
|
+
...finals.map((s) => ({ ...s, mergedPosition: s.position, isFinalist: true })),
|
|
1068
|
+
...nonFinalists.map((s, i) => ({
|
|
1069
|
+
...s,
|
|
1070
|
+
mergedPosition: finals.length + i + 1,
|
|
1071
|
+
isFinalist: false
|
|
1072
|
+
}))
|
|
1073
|
+
];
|
|
1074
|
+
}
|
|
458
1075
|
async function getPlayerTopFinishes(playerId, limit = 15) {
|
|
459
|
-
return
|
|
1076
|
+
return findStandings({
|
|
460
1077
|
where: { playerId },
|
|
461
1078
|
take: limit,
|
|
462
1079
|
include: { tournament: true },
|
|
463
1080
|
orderBy: { decayedPoints: "desc" }
|
|
464
1081
|
});
|
|
465
1082
|
}
|
|
466
|
-
async function
|
|
467
|
-
return prisma.
|
|
1083
|
+
async function updateStanding(id, data) {
|
|
1084
|
+
return prisma.standing.update({
|
|
468
1085
|
where: { id },
|
|
469
1086
|
data
|
|
470
1087
|
});
|
|
471
1088
|
}
|
|
472
|
-
async function
|
|
473
|
-
const
|
|
1089
|
+
async function updateStandingPoints(id, linearPoints, dynamicPoints, totalPoints) {
|
|
1090
|
+
const standing = await findStandingById(id, {
|
|
474
1091
|
tournament: true
|
|
475
1092
|
});
|
|
476
|
-
if (!
|
|
477
|
-
throw new Error(`
|
|
1093
|
+
if (!standing) {
|
|
1094
|
+
throw new Error(`Standing with id ${id} not found`);
|
|
478
1095
|
}
|
|
479
1096
|
const now = /* @__PURE__ */ new Date();
|
|
480
|
-
const tournamentDate =
|
|
1097
|
+
const tournamentDate = standing.tournament.date;
|
|
481
1098
|
const ageInDays = Math.floor((now.getTime() - tournamentDate.getTime()) / (1e3 * 60 * 60 * 24));
|
|
482
1099
|
const ageInYears = ageInDays / 365;
|
|
483
1100
|
let decayMultiplier = 0;
|
|
@@ -491,7 +1108,7 @@ async function updateResultPoints(id, linearPoints, dynamicPoints, totalPoints)
|
|
|
491
1108
|
decayMultiplier = 0;
|
|
492
1109
|
}
|
|
493
1110
|
const decayedPoints = totalPoints * decayMultiplier;
|
|
494
|
-
return
|
|
1111
|
+
return updateStanding(id, {
|
|
495
1112
|
linearPoints,
|
|
496
1113
|
dynamicPoints,
|
|
497
1114
|
totalPoints,
|
|
@@ -500,50 +1117,50 @@ async function updateResultPoints(id, linearPoints, dynamicPoints, totalPoints)
|
|
|
500
1117
|
decayedPoints
|
|
501
1118
|
});
|
|
502
1119
|
}
|
|
503
|
-
async function
|
|
504
|
-
return prisma.
|
|
1120
|
+
async function deleteStanding(id) {
|
|
1121
|
+
return prisma.standing.delete({
|
|
505
1122
|
where: { id }
|
|
506
1123
|
});
|
|
507
1124
|
}
|
|
508
|
-
async function
|
|
509
|
-
return prisma.
|
|
1125
|
+
async function deleteStandingsByTournament(tournamentId) {
|
|
1126
|
+
return prisma.standing.deleteMany({
|
|
510
1127
|
where: { tournamentId }
|
|
511
1128
|
});
|
|
512
1129
|
}
|
|
513
|
-
async function
|
|
514
|
-
return prisma.
|
|
1130
|
+
async function countStandings(where) {
|
|
1131
|
+
return prisma.standing.count({ where });
|
|
515
1132
|
}
|
|
516
1133
|
async function getPlayerStats(playerId) {
|
|
517
|
-
const
|
|
518
|
-
if (
|
|
1134
|
+
const standings = await getPlayerStandings(playerId);
|
|
1135
|
+
if (standings.length === 0) {
|
|
519
1136
|
return null;
|
|
520
1137
|
}
|
|
521
|
-
const totalPoints =
|
|
522
|
-
const totalDecayedPoints =
|
|
523
|
-
const averagePosition =
|
|
524
|
-
const averageEfficiency =
|
|
525
|
-
const firstPlaceFinishes =
|
|
526
|
-
const topThreeFinishes =
|
|
1138
|
+
const totalPoints = standings.reduce((sum, s) => sum + (s.totalPoints || 0), 0);
|
|
1139
|
+
const totalDecayedPoints = standings.reduce((sum, s) => sum + (s.decayedPoints || 0), 0);
|
|
1140
|
+
const averagePosition = standings.reduce((sum, s) => sum + s.position, 0) / standings.length;
|
|
1141
|
+
const averageEfficiency = standings.reduce((sum, s) => sum + (s.efficiency || 0), 0) / standings.length;
|
|
1142
|
+
const firstPlaceFinishes = standings.filter((s) => s.position === 1).length;
|
|
1143
|
+
const topThreeFinishes = standings.filter((s) => s.position <= 3).length;
|
|
527
1144
|
return {
|
|
528
|
-
totalEvents:
|
|
1145
|
+
totalEvents: standings.length,
|
|
529
1146
|
totalPoints,
|
|
530
1147
|
totalDecayedPoints,
|
|
531
|
-
averagePoints: totalPoints /
|
|
1148
|
+
averagePoints: totalPoints / standings.length,
|
|
532
1149
|
averagePosition,
|
|
533
1150
|
averageFinish: averagePosition,
|
|
534
1151
|
averageEfficiency,
|
|
535
1152
|
firstPlaceFinishes,
|
|
536
1153
|
topThreeFinishes,
|
|
537
|
-
bestFinish: Math.min(...
|
|
538
|
-
highestPoints: Math.max(...
|
|
1154
|
+
bestFinish: Math.min(...standings.map((s) => s.position)),
|
|
1155
|
+
highestPoints: Math.max(...standings.map((s) => s.totalPoints || 0))
|
|
539
1156
|
};
|
|
540
1157
|
}
|
|
541
1158
|
async function recalculateTimeDecay(referenceDate = /* @__PURE__ */ new Date()) {
|
|
542
|
-
const
|
|
1159
|
+
const standings = await findStandings({
|
|
543
1160
|
include: { tournament: true }
|
|
544
1161
|
});
|
|
545
|
-
const updates =
|
|
546
|
-
const tournamentDate =
|
|
1162
|
+
const updates = standings.map((standing) => {
|
|
1163
|
+
const tournamentDate = standing.tournament.date;
|
|
547
1164
|
const ageInDays = Math.floor(
|
|
548
1165
|
(referenceDate.getTime() - tournamentDate.getTime()) / (1e3 * 60 * 60 * 24)
|
|
549
1166
|
);
|
|
@@ -558,9 +1175,9 @@ async function recalculateTimeDecay(referenceDate = /* @__PURE__ */ new Date())
|
|
|
558
1175
|
} else {
|
|
559
1176
|
decayMultiplier = 0;
|
|
560
1177
|
}
|
|
561
|
-
const decayedPoints = (
|
|
562
|
-
return prisma.
|
|
563
|
-
where: { id:
|
|
1178
|
+
const decayedPoints = (standing.totalPoints || 0) * decayMultiplier;
|
|
1179
|
+
return prisma.standing.update({
|
|
1180
|
+
where: { id: standing.id },
|
|
564
1181
|
data: {
|
|
565
1182
|
ageInDays,
|
|
566
1183
|
decayMultiplier,
|
|
@@ -597,10 +1214,6 @@ async function createUserWithPlayer(userData, playerData) {
|
|
|
597
1214
|
id: true,
|
|
598
1215
|
playerNumber: true,
|
|
599
1216
|
name: true,
|
|
600
|
-
rating: true,
|
|
601
|
-
ratingDeviation: true,
|
|
602
|
-
ranking: true,
|
|
603
|
-
isRated: true,
|
|
604
1217
|
eventCount: true
|
|
605
1218
|
}
|
|
606
1219
|
}
|
|
@@ -630,10 +1243,6 @@ async function getUserWithPlayer(id) {
|
|
|
630
1243
|
id: true,
|
|
631
1244
|
playerNumber: true,
|
|
632
1245
|
name: true,
|
|
633
|
-
rating: true,
|
|
634
|
-
ratingDeviation: true,
|
|
635
|
-
ranking: true,
|
|
636
|
-
isRated: true,
|
|
637
1246
|
eventCount: true
|
|
638
1247
|
}
|
|
639
1248
|
}
|
|
@@ -653,10 +1262,6 @@ async function getUserByEmailWithPlayer(email) {
|
|
|
653
1262
|
id: true,
|
|
654
1263
|
playerNumber: true,
|
|
655
1264
|
name: true,
|
|
656
|
-
rating: true,
|
|
657
|
-
ratingDeviation: true,
|
|
658
|
-
ranking: true,
|
|
659
|
-
isRated: true,
|
|
660
1265
|
eventCount: true
|
|
661
1266
|
}
|
|
662
1267
|
}
|
|
@@ -699,10 +1304,6 @@ async function findUsers(params) {
|
|
|
699
1304
|
id: true,
|
|
700
1305
|
playerNumber: true,
|
|
701
1306
|
name: true,
|
|
702
|
-
rating: true,
|
|
703
|
-
ratingDeviation: true,
|
|
704
|
-
ranking: true,
|
|
705
|
-
isRated: true,
|
|
706
1307
|
eventCount: true
|
|
707
1308
|
}
|
|
708
1309
|
}
|
|
@@ -731,10 +1332,6 @@ async function linkPlayerToUser(userId, playerId) {
|
|
|
731
1332
|
id: true,
|
|
732
1333
|
playerNumber: true,
|
|
733
1334
|
name: true,
|
|
734
|
-
rating: true,
|
|
735
|
-
ratingDeviation: true,
|
|
736
|
-
ranking: true,
|
|
737
|
-
isRated: true,
|
|
738
1335
|
eventCount: true
|
|
739
1336
|
}
|
|
740
1337
|
}
|
|
@@ -743,33 +1340,138 @@ async function linkPlayerToUser(userId, playerId) {
|
|
|
743
1340
|
return user;
|
|
744
1341
|
});
|
|
745
1342
|
}
|
|
1343
|
+
|
|
1344
|
+
// src/locations.ts
|
|
1345
|
+
async function createLocation(data) {
|
|
1346
|
+
return prisma.location.create({
|
|
1347
|
+
data
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
async function findLocationById(id, include) {
|
|
1351
|
+
return prisma.location.findUnique({
|
|
1352
|
+
where: { id },
|
|
1353
|
+
include
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
async function findLocationByExternalId(externalId, include) {
|
|
1357
|
+
return prisma.location.findUnique({
|
|
1358
|
+
where: { externalId },
|
|
1359
|
+
include
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
async function findLocations(options = {}) {
|
|
1363
|
+
return prisma.location.findMany({
|
|
1364
|
+
take: options.take,
|
|
1365
|
+
skip: options.skip,
|
|
1366
|
+
where: options.where,
|
|
1367
|
+
orderBy: options.orderBy,
|
|
1368
|
+
include: options.include
|
|
1369
|
+
});
|
|
1370
|
+
}
|
|
1371
|
+
async function searchLocations(query, limit = 20) {
|
|
1372
|
+
return findLocations({
|
|
1373
|
+
take: limit,
|
|
1374
|
+
where: {
|
|
1375
|
+
OR: [
|
|
1376
|
+
{ name: { contains: query, mode: "insensitive" } },
|
|
1377
|
+
{ city: { contains: query, mode: "insensitive" } }
|
|
1378
|
+
]
|
|
1379
|
+
},
|
|
1380
|
+
orderBy: { name: "asc" }
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1383
|
+
async function updateLocation(id, data) {
|
|
1384
|
+
return prisma.location.update({
|
|
1385
|
+
where: { id },
|
|
1386
|
+
data
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
async function deleteLocation(id) {
|
|
1390
|
+
return prisma.location.delete({
|
|
1391
|
+
where: { id }
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
async function countLocations(where) {
|
|
1395
|
+
return prisma.location.count({ where });
|
|
1396
|
+
}
|
|
1397
|
+
async function getLocationWithTournaments(id) {
|
|
1398
|
+
return prisma.location.findUnique({
|
|
1399
|
+
where: { id },
|
|
1400
|
+
include: {
|
|
1401
|
+
tournaments: {
|
|
1402
|
+
orderBy: {
|
|
1403
|
+
date: "desc"
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
746
1409
|
// Annotate the CommonJS export names for ESM import in node:
|
|
747
1410
|
0 && (module.exports = {
|
|
1411
|
+
applyRDDecayForInactivePlayers,
|
|
748
1412
|
connect,
|
|
1413
|
+
countEntries,
|
|
1414
|
+
countLocations,
|
|
1415
|
+
countMatches,
|
|
1416
|
+
countOpprPlayerRankings,
|
|
1417
|
+
countOpprRankingHistory,
|
|
749
1418
|
countPlayers,
|
|
750
|
-
|
|
1419
|
+
countRounds,
|
|
1420
|
+
countStandings,
|
|
751
1421
|
countTournaments,
|
|
752
1422
|
countUsers,
|
|
753
|
-
|
|
1423
|
+
createEntry,
|
|
1424
|
+
createLocation,
|
|
1425
|
+
createManyEntries,
|
|
1426
|
+
createManyMatches,
|
|
1427
|
+
createManyRounds,
|
|
1428
|
+
createManyStandings,
|
|
1429
|
+
createMatch,
|
|
1430
|
+
createOpprPlayerRanking,
|
|
1431
|
+
createOpprRankingHistory,
|
|
754
1432
|
createPlayer,
|
|
755
|
-
|
|
1433
|
+
createRound,
|
|
1434
|
+
createStanding,
|
|
756
1435
|
createTournament,
|
|
757
1436
|
createUser,
|
|
758
1437
|
createUserWithPlayer,
|
|
1438
|
+
deleteEntriesByMatch,
|
|
1439
|
+
deleteEntry,
|
|
1440
|
+
deleteLocation,
|
|
1441
|
+
deleteMatch,
|
|
1442
|
+
deleteMatchesByRound,
|
|
1443
|
+
deleteMatchesByTournament,
|
|
1444
|
+
deleteOpprPlayerRanking,
|
|
759
1445
|
deletePlayer,
|
|
760
|
-
|
|
761
|
-
|
|
1446
|
+
deleteRound,
|
|
1447
|
+
deleteRoundsByTournament,
|
|
1448
|
+
deleteStanding,
|
|
1449
|
+
deleteStandingsByTournament,
|
|
762
1450
|
deleteTournament,
|
|
763
1451
|
deleteUser,
|
|
764
1452
|
disconnect,
|
|
1453
|
+
findEntries,
|
|
1454
|
+
findEntryById,
|
|
1455
|
+
findEntryByMatchAndPlayer,
|
|
1456
|
+
findLocationByExternalId,
|
|
1457
|
+
findLocationById,
|
|
1458
|
+
findLocations,
|
|
1459
|
+
findMatchById,
|
|
1460
|
+
findMatches,
|
|
1461
|
+
findOpprPlayerRankingById,
|
|
1462
|
+
findOpprPlayerRankingByPlayerId,
|
|
1463
|
+
findOpprPlayerRankings,
|
|
765
1464
|
findPlayerByExternalId,
|
|
766
1465
|
findPlayerById,
|
|
767
1466
|
findPlayerByPlayerNumber,
|
|
768
1467
|
findPlayerByUserEmail,
|
|
769
1468
|
findPlayers,
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
1469
|
+
findRoundById,
|
|
1470
|
+
findRoundByTournamentAndNumber,
|
|
1471
|
+
findRounds,
|
|
1472
|
+
findStandingById,
|
|
1473
|
+
findStandingByPlayerAndTournament,
|
|
1474
|
+
findStandings,
|
|
773
1475
|
findTournamentByExternalId,
|
|
774
1476
|
findTournamentById,
|
|
775
1477
|
findTournaments,
|
|
@@ -777,17 +1479,38 @@ async function linkPlayerToUser(userId, playerId) {
|
|
|
777
1479
|
findUserById,
|
|
778
1480
|
findUsers,
|
|
779
1481
|
generateUniquePlayerNumber,
|
|
1482
|
+
getFinalsRounds,
|
|
1483
|
+
getFinalsStandings,
|
|
1484
|
+
getLatestOpprRankingHistory,
|
|
1485
|
+
getLocationWithTournaments,
|
|
780
1486
|
getMajorTournaments,
|
|
781
|
-
|
|
1487
|
+
getMatchEntries,
|
|
1488
|
+
getMatchWithEntries,
|
|
1489
|
+
getMergedStandings,
|
|
1490
|
+
getOpprRankingHistory,
|
|
1491
|
+
getOpprRankingHistoryByDateRange,
|
|
1492
|
+
getOrCreateOpprPlayerRanking,
|
|
1493
|
+
getPlayerEntries,
|
|
1494
|
+
getPlayerEntryStats,
|
|
1495
|
+
getPlayerStandings,
|
|
782
1496
|
getPlayerStats,
|
|
783
1497
|
getPlayerTopFinishes,
|
|
1498
|
+
getPlayerTournamentEntries,
|
|
1499
|
+
getPlayerTournamentMatches,
|
|
784
1500
|
getPlayerWithResults,
|
|
785
|
-
|
|
1501
|
+
getQualifyingRounds,
|
|
1502
|
+
getQualifyingStandings,
|
|
1503
|
+
getRatedOpprPlayers,
|
|
786
1504
|
getRecentTournaments,
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
1505
|
+
getRoundMatches,
|
|
1506
|
+
getRoundWithMatches,
|
|
1507
|
+
getTopPlayersByOpprRanking,
|
|
1508
|
+
getTopPlayersByOpprRating,
|
|
1509
|
+
getTournamentMatches,
|
|
1510
|
+
getTournamentRounds,
|
|
1511
|
+
getTournamentStandings,
|
|
790
1512
|
getTournamentStats,
|
|
1513
|
+
getTournamentWithMatches,
|
|
791
1514
|
getTournamentWithResults,
|
|
792
1515
|
getTournamentsByBoosterType,
|
|
793
1516
|
getTournamentsByDateRange,
|
|
@@ -797,14 +1520,21 @@ async function linkPlayerToUser(userId, playerId) {
|
|
|
797
1520
|
linkPlayerToUser,
|
|
798
1521
|
prisma,
|
|
799
1522
|
recalculateTimeDecay,
|
|
1523
|
+
searchLocations,
|
|
800
1524
|
searchPlayers,
|
|
801
1525
|
searchTournaments,
|
|
802
1526
|
testConnection,
|
|
1527
|
+
updateEntry,
|
|
1528
|
+
updateLocation,
|
|
1529
|
+
updateMatch,
|
|
1530
|
+
updateOpprPlayerRanking,
|
|
1531
|
+
updateOpprRatingAfterTournament,
|
|
803
1532
|
updatePlayer,
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
1533
|
+
updateRound,
|
|
1534
|
+
updateStanding,
|
|
1535
|
+
updateStandingPoints,
|
|
807
1536
|
updateTournament,
|
|
808
1537
|
updateUser,
|
|
809
|
-
updateUserRefreshToken
|
|
1538
|
+
updateUserRefreshToken,
|
|
1539
|
+
updateWorldRankings
|
|
810
1540
|
});
|