@opprs/db-prisma 2.2.1 → 2.5.0

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 CHANGED
@@ -20,65 +20,164 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ MAX_API_KEYS_PER_USER: () => MAX_API_KEYS_PER_USER,
24
+ applyRDDecayForInactivePlayers: () => applyRDDecayForInactivePlayers,
23
25
  connect: () => connect,
26
+ countBlogPosts: () => countBlogPosts,
27
+ countBlogTags: () => countBlogTags,
28
+ countEntries: () => countEntries,
29
+ countLocations: () => countLocations,
30
+ countMatches: () => countMatches,
31
+ countOpprPlayerRankings: () => countOpprPlayerRankings,
32
+ countOpprRankingHistory: () => countOpprRankingHistory,
24
33
  countPlayers: () => countPlayers,
25
- countResults: () => countResults,
34
+ countPublishedBlogPosts: () => countPublishedBlogPosts,
35
+ countRounds: () => countRounds,
36
+ countStandings: () => countStandings,
26
37
  countTournaments: () => countTournaments,
38
+ countUserApiKeys: () => countUserApiKeys,
27
39
  countUsers: () => countUsers,
28
- createManyResults: () => createManyResults,
40
+ createApiKey: () => createApiKey,
41
+ createBlogPost: () => createBlogPost,
42
+ createBlogTag: () => createBlogTag,
43
+ createEntry: () => createEntry,
44
+ createLocation: () => createLocation,
45
+ createManyEntries: () => createManyEntries,
46
+ createManyMatches: () => createManyMatches,
47
+ createManyRounds: () => createManyRounds,
48
+ createManyStandings: () => createManyStandings,
49
+ createMatch: () => createMatch,
50
+ createOpprPlayerRanking: () => createOpprPlayerRanking,
51
+ createOpprRankingHistory: () => createOpprRankingHistory,
29
52
  createPlayer: () => createPlayer,
30
- createResult: () => createResult,
53
+ createRound: () => createRound,
54
+ createStanding: () => createStanding,
31
55
  createTournament: () => createTournament,
32
56
  createUser: () => createUser,
33
57
  createUserWithPlayer: () => createUserWithPlayer,
58
+ deleteApiKey: () => deleteApiKey,
59
+ deleteBlogPost: () => deleteBlogPost,
60
+ deleteBlogTag: () => deleteBlogTag,
61
+ deleteEntriesByMatch: () => deleteEntriesByMatch,
62
+ deleteEntry: () => deleteEntry,
63
+ deleteLocation: () => deleteLocation,
64
+ deleteMatch: () => deleteMatch,
65
+ deleteMatchesByRound: () => deleteMatchesByRound,
66
+ deleteMatchesByTournament: () => deleteMatchesByTournament,
67
+ deleteOpprPlayerRanking: () => deleteOpprPlayerRanking,
34
68
  deletePlayer: () => deletePlayer,
35
- deleteResult: () => deleteResult,
36
- deleteResultsByTournament: () => deleteResultsByTournament,
69
+ deleteRound: () => deleteRound,
70
+ deleteRoundsByTournament: () => deleteRoundsByTournament,
71
+ deleteStanding: () => deleteStanding,
72
+ deleteStandingsByTournament: () => deleteStandingsByTournament,
37
73
  deleteTournament: () => deleteTournament,
38
74
  deleteUser: () => deleteUser,
75
+ deleteUserApiKey: () => deleteUserApiKey,
39
76
  disconnect: () => disconnect,
77
+ findApiKeyById: () => findApiKeyById,
78
+ findApiKeysByPrefix: () => findApiKeysByPrefix,
79
+ findBlogPostById: () => findBlogPostById,
80
+ findBlogPostBySlug: () => findBlogPostBySlug,
81
+ findBlogPosts: () => findBlogPosts,
82
+ findBlogTagById: () => findBlogTagById,
83
+ findBlogTagBySlug: () => findBlogTagBySlug,
84
+ findBlogTags: () => findBlogTags,
85
+ findEntries: () => findEntries,
86
+ findEntryById: () => findEntryById,
87
+ findEntryByMatchAndPlayer: () => findEntryByMatchAndPlayer,
88
+ findLocationByExternalId: () => findLocationByExternalId,
89
+ findLocationById: () => findLocationById,
90
+ findLocations: () => findLocations,
91
+ findMatchById: () => findMatchById,
92
+ findMatches: () => findMatches,
93
+ findOpprPlayerRankingById: () => findOpprPlayerRankingById,
94
+ findOpprPlayerRankingByPlayerId: () => findOpprPlayerRankingByPlayerId,
95
+ findOpprPlayerRankings: () => findOpprPlayerRankings,
40
96
  findPlayerByExternalId: () => findPlayerByExternalId,
41
97
  findPlayerById: () => findPlayerById,
98
+ findPlayerByPlayerNumber: () => findPlayerByPlayerNumber,
42
99
  findPlayerByUserEmail: () => findPlayerByUserEmail,
43
100
  findPlayers: () => findPlayers,
44
- findResultById: () => findResultById,
45
- findResultByPlayerAndTournament: () => findResultByPlayerAndTournament,
46
- findResults: () => findResults,
101
+ findPublishedBlogPosts: () => findPublishedBlogPosts,
102
+ findRoundById: () => findRoundById,
103
+ findRoundByTournamentAndNumber: () => findRoundByTournamentAndNumber,
104
+ findRounds: () => findRounds,
105
+ findStandingById: () => findStandingById,
106
+ findStandingByPlayerAndTournament: () => findStandingByPlayerAndTournament,
107
+ findStandings: () => findStandings,
47
108
  findTournamentByExternalId: () => findTournamentByExternalId,
48
109
  findTournamentById: () => findTournamentById,
49
110
  findTournaments: () => findTournaments,
50
111
  findUserByEmail: () => findUserByEmail,
51
112
  findUserById: () => findUserById,
52
113
  findUsers: () => findUsers,
114
+ generateUniquePlayerNumber: () => generateUniquePlayerNumber,
115
+ getBlogTagWithPostCount: () => getBlogTagWithPostCount,
116
+ getBlogTagsWithPostCounts: () => getBlogTagsWithPostCounts,
117
+ getFinalsRounds: () => getFinalsRounds,
118
+ getFinalsStandings: () => getFinalsStandings,
119
+ getLatestOpprRankingHistory: () => getLatestOpprRankingHistory,
120
+ getLocationWithTournaments: () => getLocationWithTournaments,
53
121
  getMajorTournaments: () => getMajorTournaments,
54
- getPlayerResults: () => getPlayerResults,
122
+ getMatchEntries: () => getMatchEntries,
123
+ getMatchWithEntries: () => getMatchWithEntries,
124
+ getMergedStandings: () => getMergedStandings,
125
+ getOpprRankingHistory: () => getOpprRankingHistory,
126
+ getOpprRankingHistoryByDateRange: () => getOpprRankingHistoryByDateRange,
127
+ getOrCreateOpprPlayerRanking: () => getOrCreateOpprPlayerRanking,
128
+ getPlayerEntries: () => getPlayerEntries,
129
+ getPlayerEntryStats: () => getPlayerEntryStats,
130
+ getPlayerStandings: () => getPlayerStandings,
55
131
  getPlayerStats: () => getPlayerStats,
56
132
  getPlayerTopFinishes: () => getPlayerTopFinishes,
133
+ getPlayerTournamentEntries: () => getPlayerTournamentEntries,
134
+ getPlayerTournamentMatches: () => getPlayerTournamentMatches,
57
135
  getPlayerWithResults: () => getPlayerWithResults,
58
- getRatedPlayers: () => getRatedPlayers,
136
+ getQualifyingRounds: () => getQualifyingRounds,
137
+ getQualifyingStandings: () => getQualifyingStandings,
138
+ getRatedOpprPlayers: () => getRatedOpprPlayers,
59
139
  getRecentTournaments: () => getRecentTournaments,
60
- getTopPlayersByRanking: () => getTopPlayersByRanking,
61
- getTopPlayersByRating: () => getTopPlayersByRating,
62
- getTournamentResults: () => getTournamentResults,
140
+ getRoundMatches: () => getRoundMatches,
141
+ getRoundWithMatches: () => getRoundWithMatches,
142
+ getTopPlayersByOpprRanking: () => getTopPlayersByOpprRanking,
143
+ getTopPlayersByOpprRating: () => getTopPlayersByOpprRating,
144
+ getTournamentMatches: () => getTournamentMatches,
145
+ getTournamentRounds: () => getTournamentRounds,
146
+ getTournamentStandings: () => getTournamentStandings,
63
147
  getTournamentStats: () => getTournamentStats,
148
+ getTournamentWithMatches: () => getTournamentWithMatches,
64
149
  getTournamentWithResults: () => getTournamentWithResults,
65
150
  getTournamentsByBoosterType: () => getTournamentsByBoosterType,
66
151
  getTournamentsByDateRange: () => getTournamentsByDateRange,
152
+ getUserApiKeys: () => getUserApiKeys,
67
153
  getUserByEmailWithPlayer: () => getUserByEmailWithPlayer,
68
154
  getUserWithPlayer: () => getUserWithPlayer,
155
+ isValidPlayerNumber: () => isValidPlayerNumber,
69
156
  linkPlayerToUser: () => linkPlayerToUser,
70
157
  prisma: () => prisma,
71
158
  recalculateTimeDecay: () => recalculateTimeDecay,
159
+ searchBlogPosts: () => searchBlogPosts,
160
+ searchBlogTags: () => searchBlogTags,
161
+ searchLocations: () => searchLocations,
72
162
  searchPlayers: () => searchPlayers,
73
163
  searchTournaments: () => searchTournaments,
74
164
  testConnection: () => testConnection,
165
+ updateApiKeyLastUsed: () => updateApiKeyLastUsed,
166
+ updateBlogPost: () => updateBlogPost,
167
+ updateBlogTag: () => updateBlogTag,
168
+ updateEntry: () => updateEntry,
169
+ updateLocation: () => updateLocation,
170
+ updateMatch: () => updateMatch,
171
+ updateOpprPlayerRanking: () => updateOpprPlayerRanking,
172
+ updateOpprRatingAfterTournament: () => updateOpprRatingAfterTournament,
75
173
  updatePlayer: () => updatePlayer,
76
- updatePlayerRating: () => updatePlayerRating,
77
- updateResult: () => updateResult,
78
- updateResultPoints: () => updateResultPoints,
174
+ updateRound: () => updateRound,
175
+ updateStanding: () => updateStanding,
176
+ updateStandingPoints: () => updateStandingPoints,
79
177
  updateTournament: () => updateTournament,
80
178
  updateUser: () => updateUser,
81
- updateUserRefreshToken: () => updateUserRefreshToken
179
+ updateUserRefreshToken: () => updateUserRefreshToken,
180
+ updateWorldRankings: () => updateWorldRankings
82
181
  });
83
182
  module.exports = __toCommonJS(index_exports);
84
183
 
@@ -107,10 +206,40 @@ async function testConnection() {
107
206
  }
108
207
  }
109
208
 
209
+ // src/player-number.ts
210
+ var MIN_PLAYER_NUMBER = 1e4;
211
+ var MAX_PLAYER_NUMBER = 99999;
212
+ var MAX_RETRIES = 10;
213
+ function generateRandomPlayerNumber() {
214
+ return Math.floor(Math.random() * (MAX_PLAYER_NUMBER - MIN_PLAYER_NUMBER + 1)) + MIN_PLAYER_NUMBER;
215
+ }
216
+ async function generateUniquePlayerNumber() {
217
+ for (let attempt = 0; attempt < MAX_RETRIES; attempt++) {
218
+ const candidate = generateRandomPlayerNumber();
219
+ const existing = await prisma.player.findUnique({
220
+ where: { playerNumber: candidate },
221
+ select: { id: true }
222
+ });
223
+ if (!existing) {
224
+ return candidate;
225
+ }
226
+ }
227
+ throw new Error(
228
+ `Failed to generate unique player number after ${MAX_RETRIES} attempts. Consider increasing the number range or implementing a different allocation strategy.`
229
+ );
230
+ }
231
+ function isValidPlayerNumber(playerNumber) {
232
+ return Number.isInteger(playerNumber) && playerNumber >= MIN_PLAYER_NUMBER && playerNumber <= MAX_PLAYER_NUMBER;
233
+ }
234
+
110
235
  // src/players.ts
111
236
  async function createPlayer(data) {
237
+ const playerNumber = data.playerNumber ?? await generateUniquePlayerNumber();
112
238
  return prisma.player.create({
113
- data
239
+ data: {
240
+ ...data,
241
+ playerNumber
242
+ }
114
243
  });
115
244
  }
116
245
  async function findPlayerById(id, include) {
@@ -125,6 +254,12 @@ async function findPlayerByExternalId(externalId, include) {
125
254
  include
126
255
  });
127
256
  }
257
+ async function findPlayerByPlayerNumber(playerNumber, include) {
258
+ return prisma.player.findUnique({
259
+ where: { playerNumber },
260
+ include
261
+ });
262
+ }
128
263
  async function findPlayerByUserEmail(email, include) {
129
264
  const user = await prisma.user.findUnique({
130
265
  where: { email },
@@ -141,48 +276,12 @@ async function findPlayers(options = {}) {
141
276
  include: options.include
142
277
  });
143
278
  }
144
- async function getRatedPlayers(options = {}) {
145
- return findPlayers({
146
- ...options,
147
- where: { isRated: true }
148
- });
149
- }
150
- async function getTopPlayersByRating(limit = 50) {
151
- return findPlayers({
152
- take: limit,
153
- orderBy: { rating: "desc" },
154
- where: { isRated: true }
155
- });
156
- }
157
- async function getTopPlayersByRanking(limit = 50) {
158
- return findPlayers({
159
- take: limit,
160
- orderBy: { ranking: "asc" },
161
- where: {
162
- isRated: true,
163
- ranking: { not: null }
164
- }
165
- });
166
- }
167
279
  async function updatePlayer(id, data) {
168
280
  return prisma.player.update({
169
281
  where: { id },
170
282
  data
171
283
  });
172
284
  }
173
- async function updatePlayerRating(id, rating, ratingDeviation, eventCount) {
174
- const updateData = {
175
- rating,
176
- ratingDeviation,
177
- lastRatingUpdate: /* @__PURE__ */ new Date(),
178
- lastEventDate: /* @__PURE__ */ new Date()
179
- };
180
- if (eventCount !== void 0) {
181
- updateData.eventCount = eventCount;
182
- updateData.isRated = eventCount >= 5;
183
- }
184
- return updatePlayer(id, updateData);
185
- }
186
285
  async function deletePlayer(id) {
187
286
  return prisma.player.delete({
188
287
  where: { id }
@@ -195,7 +294,7 @@ async function getPlayerWithResults(id) {
195
294
  const player = await prisma.player.findUnique({
196
295
  where: { id },
197
296
  include: {
198
- tournamentResults: {
297
+ standings: {
199
298
  include: {
200
299
  tournament: true
201
300
  },
@@ -212,7 +311,7 @@ async function getPlayerWithResults(id) {
212
311
  }
213
312
  return {
214
313
  ...player,
215
- results: player.tournamentResults
314
+ results: player.standings
216
315
  };
217
316
  }
218
317
  async function searchPlayers(query, limit = 20) {
@@ -224,6 +323,212 @@ async function searchPlayers(query, limit = 20) {
224
323
  });
225
324
  }
226
325
 
326
+ // src/oppr-rankings.ts
327
+ async function getOrCreateOpprPlayerRanking(playerId) {
328
+ const existing = await prisma.opprPlayerRanking.findUnique({
329
+ where: { playerId }
330
+ });
331
+ if (existing) return existing;
332
+ return prisma.opprPlayerRanking.create({
333
+ data: { playerId }
334
+ });
335
+ }
336
+ async function createOpprPlayerRanking(data) {
337
+ return prisma.opprPlayerRanking.create({
338
+ data
339
+ });
340
+ }
341
+ async function findOpprPlayerRankingById(id, include) {
342
+ return prisma.opprPlayerRanking.findUnique({
343
+ where: { id },
344
+ include
345
+ });
346
+ }
347
+ async function findOpprPlayerRankingByPlayerId(playerId, include) {
348
+ return prisma.opprPlayerRanking.findUnique({
349
+ where: { playerId },
350
+ include
351
+ });
352
+ }
353
+ async function findOpprPlayerRankings(options = {}) {
354
+ return prisma.opprPlayerRanking.findMany({
355
+ take: options.take,
356
+ skip: options.skip,
357
+ where: options.where,
358
+ orderBy: options.orderBy,
359
+ include: options.include
360
+ });
361
+ }
362
+ async function getTopPlayersByOpprRating(limit = 50) {
363
+ return prisma.opprPlayerRanking.findMany({
364
+ take: limit,
365
+ where: { isRated: true },
366
+ orderBy: { rating: "desc" },
367
+ include: { player: true }
368
+ });
369
+ }
370
+ async function getTopPlayersByOpprRanking(limit = 50) {
371
+ return prisma.opprPlayerRanking.findMany({
372
+ take: limit,
373
+ where: {
374
+ isRated: true,
375
+ ranking: { not: null }
376
+ },
377
+ orderBy: { ranking: "asc" },
378
+ include: { player: true }
379
+ });
380
+ }
381
+ async function getRatedOpprPlayers(options = {}) {
382
+ return prisma.opprPlayerRanking.findMany({
383
+ ...options,
384
+ where: { isRated: true },
385
+ include: { player: true, ...options.include }
386
+ });
387
+ }
388
+ async function updateOpprPlayerRanking(playerId, data) {
389
+ return prisma.opprPlayerRanking.update({
390
+ where: { playerId },
391
+ data: {
392
+ ...data,
393
+ lastRatingUpdate: data.lastRatingUpdate ?? /* @__PURE__ */ new Date()
394
+ }
395
+ });
396
+ }
397
+ async function updateOpprRatingAfterTournament(playerId, newRating, newRD, tournamentId, eventCount) {
398
+ const ranking = await getOrCreateOpprPlayerRanking(playerId);
399
+ const isRated = eventCount !== void 0 ? eventCount >= 5 : ranking.isRated;
400
+ const updated = await prisma.opprPlayerRanking.update({
401
+ where: { playerId },
402
+ data: {
403
+ rating: newRating,
404
+ ratingDeviation: newRD,
405
+ lastRatingUpdate: /* @__PURE__ */ new Date(),
406
+ isRated
407
+ }
408
+ });
409
+ await createOpprRankingHistory({
410
+ opprPlayerRankingId: ranking.id,
411
+ rating: newRating,
412
+ ratingDeviation: newRD,
413
+ ranking: updated.ranking ?? void 0,
414
+ isRated,
415
+ changeType: "TOURNAMENT_RESULT",
416
+ tournamentId
417
+ });
418
+ return updated;
419
+ }
420
+ async function updateWorldRankings(rankings) {
421
+ await prisma.$transaction(async (tx) => {
422
+ for (const { playerId, ranking } of rankings) {
423
+ const opprRanking = await tx.opprPlayerRanking.findUnique({
424
+ where: { playerId }
425
+ });
426
+ if (opprRanking) {
427
+ await tx.opprPlayerRanking.update({
428
+ where: { playerId },
429
+ data: { ranking }
430
+ });
431
+ await tx.opprRankingHistory.create({
432
+ data: {
433
+ opprPlayerRankingId: opprRanking.id,
434
+ rating: opprRanking.rating,
435
+ ratingDeviation: opprRanking.ratingDeviation,
436
+ ranking,
437
+ isRated: opprRanking.isRated,
438
+ changeType: "RANKING_REFRESH"
439
+ }
440
+ });
441
+ }
442
+ }
443
+ });
444
+ }
445
+ async function applyRDDecayForInactivePlayers(thresholdDays = 30, decayPerDay = 0.3, maxRD = 200) {
446
+ const cutoffDate = /* @__PURE__ */ new Date();
447
+ cutoffDate.setDate(cutoffDate.getDate() - thresholdDays);
448
+ const inactivePlayers = await prisma.opprPlayerRanking.findMany({
449
+ where: {
450
+ lastRatingUpdate: { lt: cutoffDate },
451
+ ratingDeviation: { lt: maxRD }
452
+ }
453
+ });
454
+ let updatedCount = 0;
455
+ await prisma.$transaction(async (tx) => {
456
+ for (const ranking of inactivePlayers) {
457
+ const daysSinceUpdate = Math.floor(
458
+ (Date.now() - ranking.lastRatingUpdate.getTime()) / (1e3 * 60 * 60 * 24)
459
+ );
460
+ const newRD = Math.min(ranking.ratingDeviation + daysSinceUpdate * decayPerDay, maxRD);
461
+ await tx.opprPlayerRanking.update({
462
+ where: { id: ranking.id },
463
+ data: { ratingDeviation: newRD }
464
+ });
465
+ await tx.opprRankingHistory.create({
466
+ data: {
467
+ opprPlayerRankingId: ranking.id,
468
+ rating: ranking.rating,
469
+ ratingDeviation: newRD,
470
+ ranking: ranking.ranking,
471
+ isRated: ranking.isRated,
472
+ changeType: "RD_DECAY",
473
+ notes: `RD increased from ${ranking.ratingDeviation.toFixed(1)} to ${newRD.toFixed(1)} due to ${daysSinceUpdate} days of inactivity`
474
+ }
475
+ });
476
+ updatedCount++;
477
+ }
478
+ });
479
+ return updatedCount;
480
+ }
481
+ async function deleteOpprPlayerRanking(playerId) {
482
+ return prisma.opprPlayerRanking.delete({
483
+ where: { playerId }
484
+ });
485
+ }
486
+ async function countOpprPlayerRankings(where) {
487
+ return prisma.opprPlayerRanking.count({ where });
488
+ }
489
+ async function createOpprRankingHistory(data) {
490
+ return prisma.opprRankingHistory.create({
491
+ data
492
+ });
493
+ }
494
+ async function getOpprRankingHistory(playerId, limit) {
495
+ const ranking = await findOpprPlayerRankingByPlayerId(playerId);
496
+ if (!ranking) return [];
497
+ return prisma.opprRankingHistory.findMany({
498
+ where: { opprPlayerRankingId: ranking.id },
499
+ orderBy: { createdAt: "desc" },
500
+ take: limit,
501
+ include: { tournament: true }
502
+ });
503
+ }
504
+ async function getOpprRankingHistoryByDateRange(playerId, startDate, endDate) {
505
+ const ranking = await findOpprPlayerRankingByPlayerId(playerId);
506
+ if (!ranking) return [];
507
+ return prisma.opprRankingHistory.findMany({
508
+ where: {
509
+ opprPlayerRankingId: ranking.id,
510
+ createdAt: {
511
+ gte: startDate,
512
+ lte: endDate
513
+ }
514
+ },
515
+ orderBy: { createdAt: "asc" },
516
+ include: { tournament: true }
517
+ });
518
+ }
519
+ async function getLatestOpprRankingHistory(playerId) {
520
+ const ranking = await findOpprPlayerRankingByPlayerId(playerId);
521
+ if (!ranking) return null;
522
+ return prisma.opprRankingHistory.findFirst({
523
+ where: { opprPlayerRankingId: ranking.id },
524
+ orderBy: { createdAt: "desc" },
525
+ include: { tournament: true }
526
+ });
527
+ }
528
+ async function countOpprRankingHistory(where) {
529
+ return prisma.opprRankingHistory.count({ where });
530
+ }
531
+
227
532
  // src/tournaments.ts
228
533
  async function createTournament(data) {
229
534
  return prisma.tournament.create({
@@ -303,13 +608,33 @@ async function getTournamentWithResults(id) {
303
608
  return prisma.tournament.findUnique({
304
609
  where: { id },
305
610
  include: {
306
- results: {
611
+ standings: {
307
612
  include: {
308
613
  player: true
309
614
  },
310
- orderBy: {
311
- position: "asc"
312
- }
615
+ orderBy: [{ isFinals: "desc" }, { position: "asc" }]
616
+ }
617
+ }
618
+ });
619
+ }
620
+ async function getTournamentWithMatches(id) {
621
+ return prisma.tournament.findUnique({
622
+ where: { id },
623
+ include: {
624
+ rounds: {
625
+ include: {
626
+ matches: {
627
+ include: {
628
+ entries: {
629
+ include: {
630
+ player: true
631
+ }
632
+ }
633
+ },
634
+ orderBy: { number: "asc" }
635
+ }
636
+ },
637
+ orderBy: [{ isFinals: "asc" }, { number: "asc" }]
313
638
  }
314
639
  }
315
640
  });
@@ -320,7 +645,7 @@ async function searchTournaments(query, limit = 20) {
320
645
  where: {
321
646
  OR: [
322
647
  { name: { contains: query, mode: "insensitive" } },
323
- { location: { contains: query, mode: "insensitive" } }
648
+ { location: { name: { contains: query, mode: "insensitive" } } }
324
649
  ]
325
650
  },
326
651
  orderBy: { date: "desc" }
@@ -331,7 +656,7 @@ async function getTournamentStats(id) {
331
656
  if (!tournament) {
332
657
  return null;
333
658
  }
334
- const playerCount = tournament.results.length;
659
+ const playerCount = tournament.standings.length;
335
660
  if (playerCount === 0) {
336
661
  return {
337
662
  tournament,
@@ -342,9 +667,9 @@ async function getTournamentStats(id) {
342
667
  lowestPoints: 0
343
668
  };
344
669
  }
345
- const totalPoints = tournament.results.reduce((sum, r) => sum + (r.totalPoints || 0), 0);
346
- const totalEfficiency = tournament.results.reduce((sum, r) => sum + (r.efficiency || 0), 0);
347
- const allPoints = tournament.results.map((r) => r.totalPoints || 0);
670
+ const totalPoints = tournament.standings.reduce((sum, s) => sum + (s.totalPoints || 0), 0);
671
+ const totalEfficiency = tournament.standings.reduce((sum, s) => sum + (s.efficiency || 0), 0);
672
+ const allPoints = tournament.standings.map((s) => s.totalPoints || 0);
348
673
  return {
349
674
  tournament,
350
675
  playerCount,
@@ -355,44 +680,364 @@ async function getTournamentStats(id) {
355
680
  };
356
681
  }
357
682
 
358
- // src/results.ts
359
- async function createResult(data) {
360
- const resultData = {
683
+ // src/rounds.ts
684
+ async function createRound(data) {
685
+ return prisma.round.create({
686
+ data: {
687
+ ...data,
688
+ isFinals: data.isFinals ?? false
689
+ }
690
+ });
691
+ }
692
+ async function createManyRounds(data) {
693
+ const roundsData = data.map((item) => ({
694
+ ...item,
695
+ isFinals: item.isFinals ?? false
696
+ }));
697
+ return prisma.round.createMany({
698
+ data: roundsData
699
+ });
700
+ }
701
+ async function findRoundById(id, include) {
702
+ return prisma.round.findUnique({
703
+ where: { id },
704
+ include
705
+ });
706
+ }
707
+ async function findRoundByTournamentAndNumber(tournamentId, number, isFinals, include) {
708
+ return prisma.round.findUnique({
709
+ where: {
710
+ tournamentId_number_isFinals: {
711
+ tournamentId,
712
+ number,
713
+ isFinals
714
+ }
715
+ },
716
+ include
717
+ });
718
+ }
719
+ async function findRounds(options = {}) {
720
+ return prisma.round.findMany({
721
+ take: options.take,
722
+ skip: options.skip,
723
+ where: options.where,
724
+ orderBy: options.orderBy,
725
+ include: options.include
726
+ });
727
+ }
728
+ async function getTournamentRounds(tournamentId, options = {}) {
729
+ return findRounds({
730
+ ...options,
731
+ where: { tournamentId },
732
+ orderBy: options.orderBy ?? [{ isFinals: "asc" }, { number: "asc" }]
733
+ });
734
+ }
735
+ async function getQualifyingRounds(tournamentId, options = {}) {
736
+ return findRounds({
737
+ ...options,
738
+ where: { tournamentId, isFinals: false },
739
+ orderBy: options.orderBy ?? { number: "asc" }
740
+ });
741
+ }
742
+ async function getFinalsRounds(tournamentId, options = {}) {
743
+ return findRounds({
744
+ ...options,
745
+ where: { tournamentId, isFinals: true },
746
+ orderBy: options.orderBy ?? { number: "asc" }
747
+ });
748
+ }
749
+ async function updateRound(id, data) {
750
+ return prisma.round.update({
751
+ where: { id },
752
+ data
753
+ });
754
+ }
755
+ async function deleteRound(id) {
756
+ return prisma.round.delete({
757
+ where: { id }
758
+ });
759
+ }
760
+ async function deleteRoundsByTournament(tournamentId) {
761
+ return prisma.round.deleteMany({
762
+ where: { tournamentId }
763
+ });
764
+ }
765
+ async function countRounds(where) {
766
+ return prisma.round.count({ where });
767
+ }
768
+ async function getRoundWithMatches(id) {
769
+ return prisma.round.findUnique({
770
+ where: { id },
771
+ include: {
772
+ matches: {
773
+ include: {
774
+ entries: {
775
+ include: {
776
+ player: true
777
+ }
778
+ }
779
+ },
780
+ orderBy: {
781
+ number: "asc"
782
+ }
783
+ }
784
+ }
785
+ });
786
+ }
787
+
788
+ // src/matches.ts
789
+ async function createMatch(data) {
790
+ return prisma.match.create({
791
+ data
792
+ });
793
+ }
794
+ async function createManyMatches(data) {
795
+ return prisma.match.createMany({
796
+ data
797
+ });
798
+ }
799
+ async function findMatchById(id, include) {
800
+ return prisma.match.findUnique({
801
+ where: { id },
802
+ include
803
+ });
804
+ }
805
+ async function findMatches(options = {}) {
806
+ return prisma.match.findMany({
807
+ take: options.take,
808
+ skip: options.skip,
809
+ where: options.where,
810
+ orderBy: options.orderBy,
811
+ include: options.include
812
+ });
813
+ }
814
+ async function getTournamentMatches(tournamentId, options = {}) {
815
+ return findMatches({
816
+ ...options,
817
+ where: { tournamentId },
818
+ orderBy: options.orderBy ?? { number: "asc" }
819
+ });
820
+ }
821
+ async function getRoundMatches(roundId, options = {}) {
822
+ return findMatches({
823
+ ...options,
824
+ where: { roundId },
825
+ orderBy: options.orderBy ?? { number: "asc" }
826
+ });
827
+ }
828
+ async function updateMatch(id, data) {
829
+ return prisma.match.update({
830
+ where: { id },
831
+ data
832
+ });
833
+ }
834
+ async function deleteMatch(id) {
835
+ return prisma.match.delete({
836
+ where: { id }
837
+ });
838
+ }
839
+ async function deleteMatchesByTournament(tournamentId) {
840
+ return prisma.match.deleteMany({
841
+ where: { tournamentId }
842
+ });
843
+ }
844
+ async function deleteMatchesByRound(roundId) {
845
+ return prisma.match.deleteMany({
846
+ where: { roundId }
847
+ });
848
+ }
849
+ async function countMatches(where) {
850
+ return prisma.match.count({ where });
851
+ }
852
+ async function getMatchWithEntries(id) {
853
+ return prisma.match.findUnique({
854
+ where: { id },
855
+ include: {
856
+ entries: {
857
+ include: {
858
+ player: true
859
+ },
860
+ orderBy: {
861
+ position: "asc"
862
+ }
863
+ },
864
+ round: true
865
+ }
866
+ });
867
+ }
868
+ async function getPlayerTournamentMatches(playerId, tournamentId, include) {
869
+ return findMatches({
870
+ where: {
871
+ tournamentId,
872
+ entries: {
873
+ some: {
874
+ playerId
875
+ }
876
+ }
877
+ },
878
+ include: include ?? {
879
+ entries: {
880
+ include: {
881
+ player: true
882
+ }
883
+ },
884
+ round: true
885
+ },
886
+ orderBy: [{ round: { number: "asc" } }, { number: "asc" }]
887
+ });
888
+ }
889
+
890
+ // src/entries.ts
891
+ async function createEntry(data) {
892
+ return prisma.entry.create({
893
+ data
894
+ });
895
+ }
896
+ async function createManyEntries(data) {
897
+ return prisma.entry.createMany({
898
+ data
899
+ });
900
+ }
901
+ async function findEntryById(id, include) {
902
+ return prisma.entry.findUnique({
903
+ where: { id },
904
+ include
905
+ });
906
+ }
907
+ async function findEntryByMatchAndPlayer(matchId, playerId, include) {
908
+ return prisma.entry.findUnique({
909
+ where: {
910
+ matchId_playerId: {
911
+ matchId,
912
+ playerId
913
+ }
914
+ },
915
+ include
916
+ });
917
+ }
918
+ async function findEntries(options = {}) {
919
+ return prisma.entry.findMany({
920
+ take: options.take,
921
+ skip: options.skip,
922
+ where: options.where,
923
+ orderBy: options.orderBy,
924
+ include: options.include
925
+ });
926
+ }
927
+ async function getMatchEntries(matchId, options = {}) {
928
+ return findEntries({
929
+ ...options,
930
+ where: { matchId },
931
+ include: options.include ?? { player: true },
932
+ orderBy: options.orderBy ?? { position: "asc" }
933
+ });
934
+ }
935
+ async function getPlayerEntries(playerId, options = {}) {
936
+ return findEntries({
937
+ ...options,
938
+ where: { playerId },
939
+ include: options.include ?? { match: { include: { round: true, tournament: true } } }
940
+ });
941
+ }
942
+ async function getPlayerTournamentEntries(playerId, tournamentId, include) {
943
+ return findEntries({
944
+ where: {
945
+ playerId,
946
+ match: {
947
+ tournamentId
948
+ }
949
+ },
950
+ include: include ?? {
951
+ match: {
952
+ include: {
953
+ round: true,
954
+ entries: {
955
+ include: {
956
+ player: true
957
+ }
958
+ }
959
+ }
960
+ }
961
+ }
962
+ });
963
+ }
964
+ async function updateEntry(id, data) {
965
+ return prisma.entry.update({
966
+ where: { id },
967
+ data
968
+ });
969
+ }
970
+ async function deleteEntry(id) {
971
+ return prisma.entry.delete({
972
+ where: { id }
973
+ });
974
+ }
975
+ async function deleteEntriesByMatch(matchId) {
976
+ return prisma.entry.deleteMany({
977
+ where: { matchId }
978
+ });
979
+ }
980
+ async function countEntries(where) {
981
+ return prisma.entry.count({ where });
982
+ }
983
+ async function getPlayerEntryStats(playerId) {
984
+ const entries = await getPlayerEntries(playerId);
985
+ if (entries.length === 0) {
986
+ return null;
987
+ }
988
+ const wins = entries.filter((e) => e.result === "WIN").length;
989
+ const losses = entries.filter((e) => e.result === "LOSS").length;
990
+ const ties = entries.filter((e) => e.result === "TIE").length;
991
+ return {
992
+ totalMatches: entries.length,
993
+ wins,
994
+ losses,
995
+ ties,
996
+ winRate: wins / entries.length
997
+ };
998
+ }
999
+
1000
+ // src/standings.ts
1001
+ async function createStanding(data) {
1002
+ const standingData = {
361
1003
  ...data,
1004
+ isFinals: data.isFinals ?? false,
362
1005
  decayedPoints: data.decayedPoints ?? data.totalPoints ?? 0
363
1006
  };
364
- return prisma.tournamentResult.create({
365
- data: resultData
1007
+ return prisma.standing.create({
1008
+ data: standingData
366
1009
  });
367
1010
  }
368
- async function createManyResults(data) {
369
- const resultsData = data.map((item) => ({
1011
+ async function createManyStandings(data) {
1012
+ const standingsData = data.map((item) => ({
370
1013
  ...item,
1014
+ isFinals: item.isFinals ?? false,
371
1015
  decayedPoints: item.decayedPoints ?? item.totalPoints ?? 0
372
1016
  }));
373
- return prisma.tournamentResult.createMany({
374
- data: resultsData
1017
+ return prisma.standing.createMany({
1018
+ data: standingsData
375
1019
  });
376
1020
  }
377
- async function findResultById(id, include) {
378
- return prisma.tournamentResult.findUnique({
1021
+ async function findStandingById(id, include) {
1022
+ return prisma.standing.findUnique({
379
1023
  where: { id },
380
1024
  include
381
1025
  });
382
1026
  }
383
- async function findResultByPlayerAndTournament(playerId, tournamentId, include) {
384
- return prisma.tournamentResult.findUnique({
1027
+ async function findStandingByPlayerAndTournament(playerId, tournamentId, isFinals, include) {
1028
+ return prisma.standing.findUnique({
385
1029
  where: {
386
- playerId_tournamentId: {
1030
+ playerId_tournamentId_isFinals: {
387
1031
  playerId,
388
- tournamentId
1032
+ tournamentId,
1033
+ isFinals
389
1034
  }
390
1035
  },
391
1036
  include
392
1037
  });
393
1038
  }
394
- async function findResults(options = {}) {
395
- return prisma.tournamentResult.findMany({
1039
+ async function findStandings(options = {}) {
1040
+ return prisma.standing.findMany({
396
1041
  take: options.take,
397
1042
  skip: options.skip,
398
1043
  where: options.where,
@@ -400,45 +1045,85 @@ async function findResults(options = {}) {
400
1045
  include: options.include
401
1046
  });
402
1047
  }
403
- async function getPlayerResults(playerId, options = {}) {
404
- return findResults({
1048
+ async function getPlayerStandings(playerId, options = {}) {
1049
+ return findStandings({
405
1050
  ...options,
406
1051
  where: { playerId },
407
1052
  include: { tournament: true, ...options.include },
408
1053
  orderBy: { tournament: { date: "desc" } }
409
1054
  });
410
1055
  }
411
- async function getTournamentResults(tournamentId, options = {}) {
412
- return findResults({
1056
+ async function getTournamentStandings(tournamentId, options = {}) {
1057
+ return findStandings({
413
1058
  ...options,
414
1059
  where: { tournamentId },
415
1060
  include: { player: true, ...options.include },
416
- orderBy: { position: "asc" }
1061
+ orderBy: options.orderBy ?? { position: "asc" }
1062
+ });
1063
+ }
1064
+ async function getQualifyingStandings(tournamentId, options = {}) {
1065
+ return findStandings({
1066
+ ...options,
1067
+ where: { tournamentId, isFinals: false },
1068
+ include: { player: true, ...options.include },
1069
+ orderBy: options.orderBy ?? { position: "asc" }
417
1070
  });
418
1071
  }
1072
+ async function getFinalsStandings(tournamentId, options = {}) {
1073
+ return findStandings({
1074
+ ...options,
1075
+ where: { tournamentId, isFinals: true },
1076
+ include: { player: true, ...options.include },
1077
+ orderBy: options.orderBy ?? { position: "asc" }
1078
+ });
1079
+ }
1080
+ async function getMergedStandings(tournamentId) {
1081
+ const [finals, qualifying] = await Promise.all([
1082
+ findStandings({
1083
+ where: { tournamentId, isFinals: true },
1084
+ orderBy: { position: "asc" },
1085
+ include: { player: true }
1086
+ }),
1087
+ findStandings({
1088
+ where: { tournamentId, isFinals: false },
1089
+ orderBy: { position: "asc" },
1090
+ include: { player: true }
1091
+ })
1092
+ ]);
1093
+ const finalistIds = new Set(finals.map((s) => s.playerId));
1094
+ const nonFinalists = qualifying.filter((s) => !finalistIds.has(s.playerId));
1095
+ return [
1096
+ ...finals.map((s) => ({ ...s, mergedPosition: s.position, isFinalist: true })),
1097
+ ...nonFinalists.map((s, i) => ({
1098
+ ...s,
1099
+ mergedPosition: finals.length + i + 1,
1100
+ isFinalist: false
1101
+ }))
1102
+ ];
1103
+ }
419
1104
  async function getPlayerTopFinishes(playerId, limit = 15) {
420
- return findResults({
1105
+ return findStandings({
421
1106
  where: { playerId },
422
1107
  take: limit,
423
1108
  include: { tournament: true },
424
1109
  orderBy: { decayedPoints: "desc" }
425
1110
  });
426
1111
  }
427
- async function updateResult(id, data) {
428
- return prisma.tournamentResult.update({
1112
+ async function updateStanding(id, data) {
1113
+ return prisma.standing.update({
429
1114
  where: { id },
430
1115
  data
431
1116
  });
432
1117
  }
433
- async function updateResultPoints(id, linearPoints, dynamicPoints, totalPoints) {
434
- const result = await findResultById(id, {
1118
+ async function updateStandingPoints(id, linearPoints, dynamicPoints, totalPoints) {
1119
+ const standing = await findStandingById(id, {
435
1120
  tournament: true
436
1121
  });
437
- if (!result) {
438
- throw new Error(`Result with id ${id} not found`);
1122
+ if (!standing) {
1123
+ throw new Error(`Standing with id ${id} not found`);
439
1124
  }
440
1125
  const now = /* @__PURE__ */ new Date();
441
- const tournamentDate = result.tournament.date;
1126
+ const tournamentDate = standing.tournament.date;
442
1127
  const ageInDays = Math.floor((now.getTime() - tournamentDate.getTime()) / (1e3 * 60 * 60 * 24));
443
1128
  const ageInYears = ageInDays / 365;
444
1129
  let decayMultiplier = 0;
@@ -452,7 +1137,7 @@ async function updateResultPoints(id, linearPoints, dynamicPoints, totalPoints)
452
1137
  decayMultiplier = 0;
453
1138
  }
454
1139
  const decayedPoints = totalPoints * decayMultiplier;
455
- return updateResult(id, {
1140
+ return updateStanding(id, {
456
1141
  linearPoints,
457
1142
  dynamicPoints,
458
1143
  totalPoints,
@@ -461,50 +1146,50 @@ async function updateResultPoints(id, linearPoints, dynamicPoints, totalPoints)
461
1146
  decayedPoints
462
1147
  });
463
1148
  }
464
- async function deleteResult(id) {
465
- return prisma.tournamentResult.delete({
1149
+ async function deleteStanding(id) {
1150
+ return prisma.standing.delete({
466
1151
  where: { id }
467
1152
  });
468
1153
  }
469
- async function deleteResultsByTournament(tournamentId) {
470
- return prisma.tournamentResult.deleteMany({
1154
+ async function deleteStandingsByTournament(tournamentId) {
1155
+ return prisma.standing.deleteMany({
471
1156
  where: { tournamentId }
472
1157
  });
473
1158
  }
474
- async function countResults(where) {
475
- return prisma.tournamentResult.count({ where });
1159
+ async function countStandings(where) {
1160
+ return prisma.standing.count({ where });
476
1161
  }
477
1162
  async function getPlayerStats(playerId) {
478
- const results = await getPlayerResults(playerId);
479
- if (results.length === 0) {
1163
+ const standings = await getPlayerStandings(playerId);
1164
+ if (standings.length === 0) {
480
1165
  return null;
481
1166
  }
482
- const totalPoints = results.reduce((sum, r) => sum + (r.totalPoints || 0), 0);
483
- const totalDecayedPoints = results.reduce((sum, r) => sum + (r.decayedPoints || 0), 0);
484
- const averagePosition = results.reduce((sum, r) => sum + r.position, 0) / results.length;
485
- const averageEfficiency = results.reduce((sum, r) => sum + (r.efficiency || 0), 0) / results.length;
486
- const firstPlaceFinishes = results.filter((r) => r.position === 1).length;
487
- const topThreeFinishes = results.filter((r) => r.position <= 3).length;
1167
+ const totalPoints = standings.reduce((sum, s) => sum + (s.totalPoints || 0), 0);
1168
+ const totalDecayedPoints = standings.reduce((sum, s) => sum + (s.decayedPoints || 0), 0);
1169
+ const averagePosition = standings.reduce((sum, s) => sum + s.position, 0) / standings.length;
1170
+ const averageEfficiency = standings.reduce((sum, s) => sum + (s.efficiency || 0), 0) / standings.length;
1171
+ const firstPlaceFinishes = standings.filter((s) => s.position === 1).length;
1172
+ const topThreeFinishes = standings.filter((s) => s.position <= 3).length;
488
1173
  return {
489
- totalEvents: results.length,
1174
+ totalEvents: standings.length,
490
1175
  totalPoints,
491
1176
  totalDecayedPoints,
492
- averagePoints: totalPoints / results.length,
1177
+ averagePoints: totalPoints / standings.length,
493
1178
  averagePosition,
494
1179
  averageFinish: averagePosition,
495
1180
  averageEfficiency,
496
1181
  firstPlaceFinishes,
497
1182
  topThreeFinishes,
498
- bestFinish: Math.min(...results.map((r) => r.position)),
499
- highestPoints: Math.max(...results.map((r) => r.totalPoints || 0))
1183
+ bestFinish: Math.min(...standings.map((s) => s.position)),
1184
+ highestPoints: Math.max(...standings.map((s) => s.totalPoints || 0))
500
1185
  };
501
1186
  }
502
1187
  async function recalculateTimeDecay(referenceDate = /* @__PURE__ */ new Date()) {
503
- const results = await findResults({
1188
+ const standings = await findStandings({
504
1189
  include: { tournament: true }
505
1190
  });
506
- const updates = results.map((result) => {
507
- const tournamentDate = result.tournament.date;
1191
+ const updates = standings.map((standing) => {
1192
+ const tournamentDate = standing.tournament.date;
508
1193
  const ageInDays = Math.floor(
509
1194
  (referenceDate.getTime() - tournamentDate.getTime()) / (1e3 * 60 * 60 * 24)
510
1195
  );
@@ -519,9 +1204,9 @@ async function recalculateTimeDecay(referenceDate = /* @__PURE__ */ new Date())
519
1204
  } else {
520
1205
  decayMultiplier = 0;
521
1206
  }
522
- const decayedPoints = (result.totalPoints || 0) * decayMultiplier;
523
- return prisma.tournamentResult.update({
524
- where: { id: result.id },
1207
+ const decayedPoints = (standing.totalPoints || 0) * decayMultiplier;
1208
+ return prisma.standing.update({
1209
+ where: { id: standing.id },
525
1210
  data: {
526
1211
  ageInDays,
527
1212
  decayMultiplier,
@@ -540,9 +1225,11 @@ async function createUser(data) {
540
1225
  }
541
1226
  async function createUserWithPlayer(userData, playerData) {
542
1227
  return prisma.$transaction(async (tx) => {
1228
+ const playerNumber = await generateUniquePlayerNumber();
543
1229
  const player = await tx.player.create({
544
1230
  data: {
545
- name: playerData.name
1231
+ name: playerData.name,
1232
+ playerNumber
546
1233
  }
547
1234
  });
548
1235
  const user = await tx.user.create({
@@ -554,11 +1241,8 @@ async function createUserWithPlayer(userData, playerData) {
554
1241
  player: {
555
1242
  select: {
556
1243
  id: true,
1244
+ playerNumber: true,
557
1245
  name: true,
558
- rating: true,
559
- ratingDeviation: true,
560
- ranking: true,
561
- isRated: true,
562
1246
  eventCount: true
563
1247
  }
564
1248
  }
@@ -586,11 +1270,8 @@ async function getUserWithPlayer(id) {
586
1270
  player: {
587
1271
  select: {
588
1272
  id: true,
1273
+ playerNumber: true,
589
1274
  name: true,
590
- rating: true,
591
- ratingDeviation: true,
592
- ranking: true,
593
- isRated: true,
594
1275
  eventCount: true
595
1276
  }
596
1277
  }
@@ -608,11 +1289,8 @@ async function getUserByEmailWithPlayer(email) {
608
1289
  player: {
609
1290
  select: {
610
1291
  id: true,
1292
+ playerNumber: true,
611
1293
  name: true,
612
- rating: true,
613
- ratingDeviation: true,
614
- ranking: true,
615
- isRated: true,
616
1294
  eventCount: true
617
1295
  }
618
1296
  }
@@ -653,11 +1331,8 @@ async function findUsers(params) {
653
1331
  player: {
654
1332
  select: {
655
1333
  id: true,
1334
+ playerNumber: true,
656
1335
  name: true,
657
- rating: true,
658
- ratingDeviation: true,
659
- ranking: true,
660
- isRated: true,
661
1336
  eventCount: true
662
1337
  }
663
1338
  }
@@ -684,11 +1359,8 @@ async function linkPlayerToUser(userId, playerId) {
684
1359
  player: {
685
1360
  select: {
686
1361
  id: true,
1362
+ playerNumber: true,
687
1363
  name: true,
688
- rating: true,
689
- ratingDeviation: true,
690
- ranking: true,
691
- isRated: true,
692
1364
  eventCount: true
693
1365
  }
694
1366
  }
@@ -697,65 +1369,468 @@ async function linkPlayerToUser(userId, playerId) {
697
1369
  return user;
698
1370
  });
699
1371
  }
1372
+
1373
+ // src/api-keys.ts
1374
+ var MAX_API_KEYS_PER_USER = 5;
1375
+ async function createApiKey(data) {
1376
+ return prisma.apiKey.create({ data });
1377
+ }
1378
+ async function findApiKeyById(id) {
1379
+ return prisma.apiKey.findUnique({ where: { id } });
1380
+ }
1381
+ async function findApiKeysByPrefix(keyPrefix) {
1382
+ const keys = await prisma.apiKey.findMany({
1383
+ where: { keyPrefix },
1384
+ include: {
1385
+ user: {
1386
+ select: {
1387
+ id: true,
1388
+ email: true,
1389
+ role: true
1390
+ }
1391
+ }
1392
+ }
1393
+ });
1394
+ return keys;
1395
+ }
1396
+ async function getUserApiKeys(userId) {
1397
+ return prisma.apiKey.findMany({
1398
+ where: { userId },
1399
+ select: {
1400
+ id: true,
1401
+ name: true,
1402
+ keyPrefix: true,
1403
+ expiresAt: true,
1404
+ lastUsedAt: true,
1405
+ createdAt: true
1406
+ },
1407
+ orderBy: { createdAt: "desc" }
1408
+ });
1409
+ }
1410
+ async function countUserApiKeys(userId) {
1411
+ return prisma.apiKey.count({ where: { userId } });
1412
+ }
1413
+ async function updateApiKeyLastUsed(id) {
1414
+ await prisma.apiKey.update({
1415
+ where: { id },
1416
+ data: { lastUsedAt: /* @__PURE__ */ new Date() }
1417
+ });
1418
+ }
1419
+ async function deleteApiKey(id) {
1420
+ return prisma.apiKey.delete({ where: { id } });
1421
+ }
1422
+ async function deleteUserApiKey(id, userId) {
1423
+ const key = await prisma.apiKey.findFirst({
1424
+ where: { id, userId }
1425
+ });
1426
+ if (!key) {
1427
+ return null;
1428
+ }
1429
+ return prisma.apiKey.delete({ where: { id } });
1430
+ }
1431
+
1432
+ // src/locations.ts
1433
+ async function createLocation(data) {
1434
+ return prisma.location.create({
1435
+ data
1436
+ });
1437
+ }
1438
+ async function findLocationById(id, include) {
1439
+ return prisma.location.findUnique({
1440
+ where: { id },
1441
+ include
1442
+ });
1443
+ }
1444
+ async function findLocationByExternalId(externalId, include) {
1445
+ return prisma.location.findUnique({
1446
+ where: { externalId },
1447
+ include
1448
+ });
1449
+ }
1450
+ async function findLocations(options = {}) {
1451
+ return prisma.location.findMany({
1452
+ take: options.take,
1453
+ skip: options.skip,
1454
+ where: options.where,
1455
+ orderBy: options.orderBy,
1456
+ include: options.include
1457
+ });
1458
+ }
1459
+ async function searchLocations(query, limit = 20) {
1460
+ return findLocations({
1461
+ take: limit,
1462
+ where: {
1463
+ OR: [
1464
+ { name: { contains: query, mode: "insensitive" } },
1465
+ { city: { contains: query, mode: "insensitive" } }
1466
+ ]
1467
+ },
1468
+ orderBy: { name: "asc" }
1469
+ });
1470
+ }
1471
+ async function updateLocation(id, data) {
1472
+ return prisma.location.update({
1473
+ where: { id },
1474
+ data
1475
+ });
1476
+ }
1477
+ async function deleteLocation(id) {
1478
+ return prisma.location.delete({
1479
+ where: { id }
1480
+ });
1481
+ }
1482
+ async function countLocations(where) {
1483
+ return prisma.location.count({ where });
1484
+ }
1485
+ async function getLocationWithTournaments(id) {
1486
+ return prisma.location.findUnique({
1487
+ where: { id },
1488
+ include: {
1489
+ tournaments: {
1490
+ orderBy: {
1491
+ date: "desc"
1492
+ }
1493
+ }
1494
+ }
1495
+ });
1496
+ }
1497
+
1498
+ // src/blog-posts.ts
1499
+ var defaultInclude = {
1500
+ author: {
1501
+ select: { id: true, email: true }
1502
+ },
1503
+ tags: {
1504
+ select: { id: true, name: true, slug: true }
1505
+ }
1506
+ };
1507
+ async function createBlogPost(data) {
1508
+ const { tagIds, ...postData } = data;
1509
+ return prisma.blogPost.create({
1510
+ data: {
1511
+ ...postData,
1512
+ tags: tagIds?.length ? { connect: tagIds.map((id) => ({ id })) } : void 0
1513
+ },
1514
+ include: defaultInclude
1515
+ });
1516
+ }
1517
+ async function findBlogPostById(id) {
1518
+ return prisma.blogPost.findUnique({
1519
+ where: { id },
1520
+ include: defaultInclude
1521
+ });
1522
+ }
1523
+ async function findBlogPostBySlug(slug) {
1524
+ return prisma.blogPost.findUnique({
1525
+ where: { slug },
1526
+ include: defaultInclude
1527
+ });
1528
+ }
1529
+ async function findBlogPosts(options = {}) {
1530
+ return prisma.blogPost.findMany({
1531
+ take: options.take,
1532
+ skip: options.skip,
1533
+ where: options.where,
1534
+ orderBy: options.orderBy ?? { createdAt: "desc" },
1535
+ include: options.include ?? defaultInclude
1536
+ });
1537
+ }
1538
+ async function findPublishedBlogPosts(options = {}) {
1539
+ const { tagSlug, ...restOptions } = options;
1540
+ const where = {
1541
+ status: "PUBLISHED",
1542
+ publishedAt: { not: null },
1543
+ ...tagSlug && {
1544
+ tags: {
1545
+ some: { slug: tagSlug }
1546
+ }
1547
+ }
1548
+ };
1549
+ return findBlogPosts({
1550
+ ...restOptions,
1551
+ where,
1552
+ orderBy: options.orderBy ?? { publishedAt: "desc" }
1553
+ });
1554
+ }
1555
+ async function searchBlogPosts(query, limit = 20, publishedOnly = true) {
1556
+ const where = {
1557
+ OR: [
1558
+ { title: { contains: query, mode: "insensitive" } },
1559
+ { excerpt: { contains: query, mode: "insensitive" } }
1560
+ ],
1561
+ ...publishedOnly && {
1562
+ status: "PUBLISHED",
1563
+ publishedAt: { not: null }
1564
+ }
1565
+ };
1566
+ return findBlogPosts({
1567
+ take: limit,
1568
+ where,
1569
+ orderBy: { publishedAt: "desc" }
1570
+ });
1571
+ }
1572
+ async function updateBlogPost(id, data) {
1573
+ const { tagIds, ...postData } = data;
1574
+ return prisma.blogPost.update({
1575
+ where: { id },
1576
+ data: {
1577
+ ...postData,
1578
+ // If tagIds is provided, replace all tags
1579
+ ...tagIds !== void 0 && {
1580
+ tags: {
1581
+ set: tagIds.map((tagId) => ({ id: tagId }))
1582
+ }
1583
+ }
1584
+ },
1585
+ include: defaultInclude
1586
+ });
1587
+ }
1588
+ async function deleteBlogPost(id) {
1589
+ return prisma.blogPost.delete({
1590
+ where: { id }
1591
+ });
1592
+ }
1593
+ async function countBlogPosts(where) {
1594
+ return prisma.blogPost.count({ where });
1595
+ }
1596
+ async function countPublishedBlogPosts(tagSlug) {
1597
+ return countBlogPosts({
1598
+ status: "PUBLISHED",
1599
+ publishedAt: { not: null },
1600
+ ...tagSlug && {
1601
+ tags: {
1602
+ some: { slug: tagSlug }
1603
+ }
1604
+ }
1605
+ });
1606
+ }
1607
+
1608
+ // src/blog-tags.ts
1609
+ async function createBlogTag(data) {
1610
+ return prisma.blogTag.create({
1611
+ data
1612
+ });
1613
+ }
1614
+ async function findBlogTagById(id) {
1615
+ return prisma.blogTag.findUnique({
1616
+ where: { id }
1617
+ });
1618
+ }
1619
+ async function findBlogTagBySlug(slug) {
1620
+ return prisma.blogTag.findUnique({
1621
+ where: { slug }
1622
+ });
1623
+ }
1624
+ async function findBlogTags(options = {}) {
1625
+ return prisma.blogTag.findMany({
1626
+ take: options.take,
1627
+ skip: options.skip,
1628
+ where: options.where,
1629
+ orderBy: options.orderBy ?? { name: "asc" },
1630
+ include: options.include
1631
+ });
1632
+ }
1633
+ async function searchBlogTags(query, limit = 20) {
1634
+ return findBlogTags({
1635
+ take: limit,
1636
+ where: {
1637
+ name: { contains: query, mode: "insensitive" }
1638
+ },
1639
+ orderBy: { name: "asc" }
1640
+ });
1641
+ }
1642
+ async function updateBlogTag(id, data) {
1643
+ return prisma.blogTag.update({
1644
+ where: { id },
1645
+ data
1646
+ });
1647
+ }
1648
+ async function deleteBlogTag(id) {
1649
+ return prisma.blogTag.delete({
1650
+ where: { id }
1651
+ });
1652
+ }
1653
+ async function countBlogTags(where) {
1654
+ return prisma.blogTag.count({ where });
1655
+ }
1656
+ async function getBlogTagWithPostCount(id) {
1657
+ return prisma.blogTag.findUnique({
1658
+ where: { id },
1659
+ include: {
1660
+ _count: {
1661
+ select: { posts: true }
1662
+ }
1663
+ }
1664
+ });
1665
+ }
1666
+ async function getBlogTagsWithPostCounts() {
1667
+ return prisma.blogTag.findMany({
1668
+ include: {
1669
+ _count: {
1670
+ select: { posts: true }
1671
+ }
1672
+ },
1673
+ orderBy: { name: "asc" }
1674
+ });
1675
+ }
700
1676
  // Annotate the CommonJS export names for ESM import in node:
701
1677
  0 && (module.exports = {
1678
+ MAX_API_KEYS_PER_USER,
1679
+ applyRDDecayForInactivePlayers,
702
1680
  connect,
1681
+ countBlogPosts,
1682
+ countBlogTags,
1683
+ countEntries,
1684
+ countLocations,
1685
+ countMatches,
1686
+ countOpprPlayerRankings,
1687
+ countOpprRankingHistory,
703
1688
  countPlayers,
704
- countResults,
1689
+ countPublishedBlogPosts,
1690
+ countRounds,
1691
+ countStandings,
705
1692
  countTournaments,
1693
+ countUserApiKeys,
706
1694
  countUsers,
707
- createManyResults,
1695
+ createApiKey,
1696
+ createBlogPost,
1697
+ createBlogTag,
1698
+ createEntry,
1699
+ createLocation,
1700
+ createManyEntries,
1701
+ createManyMatches,
1702
+ createManyRounds,
1703
+ createManyStandings,
1704
+ createMatch,
1705
+ createOpprPlayerRanking,
1706
+ createOpprRankingHistory,
708
1707
  createPlayer,
709
- createResult,
1708
+ createRound,
1709
+ createStanding,
710
1710
  createTournament,
711
1711
  createUser,
712
1712
  createUserWithPlayer,
1713
+ deleteApiKey,
1714
+ deleteBlogPost,
1715
+ deleteBlogTag,
1716
+ deleteEntriesByMatch,
1717
+ deleteEntry,
1718
+ deleteLocation,
1719
+ deleteMatch,
1720
+ deleteMatchesByRound,
1721
+ deleteMatchesByTournament,
1722
+ deleteOpprPlayerRanking,
713
1723
  deletePlayer,
714
- deleteResult,
715
- deleteResultsByTournament,
1724
+ deleteRound,
1725
+ deleteRoundsByTournament,
1726
+ deleteStanding,
1727
+ deleteStandingsByTournament,
716
1728
  deleteTournament,
717
1729
  deleteUser,
1730
+ deleteUserApiKey,
718
1731
  disconnect,
1732
+ findApiKeyById,
1733
+ findApiKeysByPrefix,
1734
+ findBlogPostById,
1735
+ findBlogPostBySlug,
1736
+ findBlogPosts,
1737
+ findBlogTagById,
1738
+ findBlogTagBySlug,
1739
+ findBlogTags,
1740
+ findEntries,
1741
+ findEntryById,
1742
+ findEntryByMatchAndPlayer,
1743
+ findLocationByExternalId,
1744
+ findLocationById,
1745
+ findLocations,
1746
+ findMatchById,
1747
+ findMatches,
1748
+ findOpprPlayerRankingById,
1749
+ findOpprPlayerRankingByPlayerId,
1750
+ findOpprPlayerRankings,
719
1751
  findPlayerByExternalId,
720
1752
  findPlayerById,
1753
+ findPlayerByPlayerNumber,
721
1754
  findPlayerByUserEmail,
722
1755
  findPlayers,
723
- findResultById,
724
- findResultByPlayerAndTournament,
725
- findResults,
1756
+ findPublishedBlogPosts,
1757
+ findRoundById,
1758
+ findRoundByTournamentAndNumber,
1759
+ findRounds,
1760
+ findStandingById,
1761
+ findStandingByPlayerAndTournament,
1762
+ findStandings,
726
1763
  findTournamentByExternalId,
727
1764
  findTournamentById,
728
1765
  findTournaments,
729
1766
  findUserByEmail,
730
1767
  findUserById,
731
1768
  findUsers,
1769
+ generateUniquePlayerNumber,
1770
+ getBlogTagWithPostCount,
1771
+ getBlogTagsWithPostCounts,
1772
+ getFinalsRounds,
1773
+ getFinalsStandings,
1774
+ getLatestOpprRankingHistory,
1775
+ getLocationWithTournaments,
732
1776
  getMajorTournaments,
733
- getPlayerResults,
1777
+ getMatchEntries,
1778
+ getMatchWithEntries,
1779
+ getMergedStandings,
1780
+ getOpprRankingHistory,
1781
+ getOpprRankingHistoryByDateRange,
1782
+ getOrCreateOpprPlayerRanking,
1783
+ getPlayerEntries,
1784
+ getPlayerEntryStats,
1785
+ getPlayerStandings,
734
1786
  getPlayerStats,
735
1787
  getPlayerTopFinishes,
1788
+ getPlayerTournamentEntries,
1789
+ getPlayerTournamentMatches,
736
1790
  getPlayerWithResults,
737
- getRatedPlayers,
1791
+ getQualifyingRounds,
1792
+ getQualifyingStandings,
1793
+ getRatedOpprPlayers,
738
1794
  getRecentTournaments,
739
- getTopPlayersByRanking,
740
- getTopPlayersByRating,
741
- getTournamentResults,
1795
+ getRoundMatches,
1796
+ getRoundWithMatches,
1797
+ getTopPlayersByOpprRanking,
1798
+ getTopPlayersByOpprRating,
1799
+ getTournamentMatches,
1800
+ getTournamentRounds,
1801
+ getTournamentStandings,
742
1802
  getTournamentStats,
1803
+ getTournamentWithMatches,
743
1804
  getTournamentWithResults,
744
1805
  getTournamentsByBoosterType,
745
1806
  getTournamentsByDateRange,
1807
+ getUserApiKeys,
746
1808
  getUserByEmailWithPlayer,
747
1809
  getUserWithPlayer,
1810
+ isValidPlayerNumber,
748
1811
  linkPlayerToUser,
749
1812
  prisma,
750
1813
  recalculateTimeDecay,
1814
+ searchBlogPosts,
1815
+ searchBlogTags,
1816
+ searchLocations,
751
1817
  searchPlayers,
752
1818
  searchTournaments,
753
1819
  testConnection,
1820
+ updateApiKeyLastUsed,
1821
+ updateBlogPost,
1822
+ updateBlogTag,
1823
+ updateEntry,
1824
+ updateLocation,
1825
+ updateMatch,
1826
+ updateOpprPlayerRanking,
1827
+ updateOpprRatingAfterTournament,
754
1828
  updatePlayer,
755
- updatePlayerRating,
756
- updateResult,
757
- updateResultPoints,
1829
+ updateRound,
1830
+ updateStanding,
1831
+ updateStandingPoints,
758
1832
  updateTournament,
759
1833
  updateUser,
760
- updateUserRefreshToken
1834
+ updateUserRefreshToken,
1835
+ updateWorldRankings
761
1836
  });