@opprs/db-prisma 1.2.0 → 2.1.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
@@ -37,9 +37,9 @@ __export(index_exports, {
37
37
  deleteTournament: () => deleteTournament,
38
38
  deleteUser: () => deleteUser,
39
39
  disconnect: () => disconnect,
40
- findPlayerByEmail: () => findPlayerByEmail,
41
40
  findPlayerByExternalId: () => findPlayerByExternalId,
42
41
  findPlayerById: () => findPlayerById,
42
+ findPlayerByUserEmail: () => findPlayerByUserEmail,
43
43
  findPlayers: () => findPlayers,
44
44
  findResultById: () => findResultById,
45
45
  findResultByPlayerAndTournament: () => findResultByPlayerAndTournament,
@@ -66,6 +66,7 @@ __export(index_exports, {
66
66
  getTournamentsByDateRange: () => getTournamentsByDateRange,
67
67
  getUserByEmailWithPlayer: () => getUserByEmailWithPlayer,
68
68
  getUserWithPlayer: () => getUserWithPlayer,
69
+ linkPlayerToUser: () => linkPlayerToUser,
69
70
  prisma: () => prisma,
70
71
  recalculateTimeDecay: () => recalculateTimeDecay,
71
72
  searchPlayers: () => searchPlayers,
@@ -124,11 +125,12 @@ async function findPlayerByExternalId(externalId, include) {
124
125
  include
125
126
  });
126
127
  }
127
- async function findPlayerByEmail(email, include) {
128
- return prisma.player.findUnique({
128
+ async function findPlayerByUserEmail(email, include) {
129
+ const user = await prisma.user.findUnique({
129
130
  where: { email },
130
- include
131
+ include: { player: include ? { include } : true }
131
132
  });
133
+ return user?.player ?? null;
132
134
  }
133
135
  async function findPlayers(options = {}) {
134
136
  return prisma.player.findMany({
@@ -217,10 +219,7 @@ async function searchPlayers(query, limit = 20) {
217
219
  return findPlayers({
218
220
  take: limit,
219
221
  where: {
220
- OR: [
221
- { name: { contains: query, mode: "insensitive" } },
222
- { email: { contains: query, mode: "insensitive" } }
223
- ]
222
+ name: { contains: query, mode: "insensitive" }
224
223
  }
225
224
  });
226
225
  }
@@ -543,8 +542,7 @@ async function createUserWithPlayer(userData, playerData) {
543
542
  return prisma.$transaction(async (tx) => {
544
543
  const player = await tx.player.create({
545
544
  data: {
546
- name: playerData.name,
547
- email: playerData.email
545
+ name: playerData.name
548
546
  }
549
547
  });
550
548
  const user = await tx.user.create({
@@ -667,6 +665,38 @@ async function findUsers(params) {
667
665
  });
668
666
  return users;
669
667
  }
668
+ async function linkPlayerToUser(userId, playerId) {
669
+ return prisma.$transaction(async (tx) => {
670
+ if (playerId) {
671
+ const player = await tx.player.findUnique({ where: { id: playerId } });
672
+ if (!player) {
673
+ throw new Error(`Player with id '${playerId}' not found`);
674
+ }
675
+ await tx.user.updateMany({
676
+ where: { playerId },
677
+ data: { playerId: null }
678
+ });
679
+ }
680
+ const user = await tx.user.update({
681
+ where: { id: userId },
682
+ data: { playerId },
683
+ include: {
684
+ player: {
685
+ select: {
686
+ id: true,
687
+ name: true,
688
+ rating: true,
689
+ ratingDeviation: true,
690
+ ranking: true,
691
+ isRated: true,
692
+ eventCount: true
693
+ }
694
+ }
695
+ }
696
+ });
697
+ return user;
698
+ });
699
+ }
670
700
  // Annotate the CommonJS export names for ESM import in node:
671
701
  0 && (module.exports = {
672
702
  connect,
@@ -686,9 +716,9 @@ async function findUsers(params) {
686
716
  deleteTournament,
687
717
  deleteUser,
688
718
  disconnect,
689
- findPlayerByEmail,
690
719
  findPlayerByExternalId,
691
720
  findPlayerById,
721
+ findPlayerByUserEmail,
692
722
  findPlayers,
693
723
  findResultById,
694
724
  findResultByPlayerAndTournament,
@@ -715,6 +745,7 @@ async function findUsers(params) {
715
745
  getTournamentsByDateRange,
716
746
  getUserByEmailWithPlayer,
717
747
  getUserWithPlayer,
748
+ linkPlayerToUser,
718
749
  prisma,
719
750
  recalculateTimeDecay,
720
751
  searchPlayers,
package/dist/index.d.cts CHANGED
@@ -26,7 +26,6 @@ declare function testConnection(): Promise<boolean>;
26
26
  interface CreatePlayerInput {
27
27
  externalId?: string;
28
28
  name?: string;
29
- email?: string;
30
29
  rating?: number;
31
30
  ratingDeviation?: number;
32
31
  ranking?: number;
@@ -38,7 +37,6 @@ interface CreatePlayerInput {
38
37
  */
39
38
  interface UpdatePlayerInput {
40
39
  name?: string;
41
- email?: string;
42
40
  rating?: number;
43
41
  ratingDeviation?: number;
44
42
  ranking?: number;
@@ -70,9 +68,9 @@ declare function findPlayerById(id: string, include?: Prisma.PlayerInclude): Pro
70
68
  */
71
69
  declare function findPlayerByExternalId(externalId: string, include?: Prisma.PlayerInclude): Promise<Player | null>;
72
70
  /**
73
- * Finds a player by email
71
+ * Finds a player through their linked User's email
74
72
  */
75
- declare function findPlayerByEmail(email: string, include?: Prisma.PlayerInclude): Promise<Player | null>;
73
+ declare function findPlayerByUserEmail(email: string, include?: Prisma.PlayerInclude): Promise<Player | null>;
76
74
  /**
77
75
  * Finds multiple players with optional filters
78
76
  */
@@ -186,7 +184,6 @@ declare function getPlayerWithResults(id: string): Promise<{
186
184
  createdAt: Date;
187
185
  updatedAt: Date;
188
186
  externalId: string | null;
189
- email: string | null;
190
187
  rating: number;
191
188
  ratingDeviation: number;
192
189
  ranking: number | null;
@@ -196,7 +193,7 @@ declare function getPlayerWithResults(id: string): Promise<{
196
193
  lastEventDate: Date | null;
197
194
  } | null>;
198
195
  /**
199
- * Searches players by name or email
196
+ * Searches players by name
200
197
  */
201
198
  declare function searchPlayers(query: string, limit?: number): Promise<Player[]>;
202
199
 
@@ -302,7 +299,6 @@ declare function getTournamentWithResults(id: string): Promise<({
302
299
  createdAt: Date;
303
300
  updatedAt: Date;
304
301
  externalId: string | null;
305
- email: string | null;
306
302
  rating: number;
307
303
  ratingDeviation: number;
308
304
  ranking: number | null;
@@ -362,7 +358,6 @@ declare function getTournamentStats(id: string): Promise<{
362
358
  createdAt: Date;
363
359
  updatedAt: Date;
364
360
  externalId: string | null;
365
- email: string | null;
366
361
  rating: number;
367
362
  ratingDeviation: number;
368
363
  ranking: number | null;
@@ -561,7 +556,7 @@ interface CreateUserInput {
561
556
  interface UpdateUserInput {
562
557
  email?: string;
563
558
  passwordHash?: string;
564
- playerId?: string;
559
+ playerId?: string | null;
565
560
  role?: 'USER' | 'ADMIN';
566
561
  refreshTokenHash?: string | null;
567
562
  }
@@ -593,7 +588,6 @@ declare function createUser(data: CreateUserInput): Promise<User>;
593
588
  */
594
589
  declare function createUserWithPlayer(userData: Omit<CreateUserInput, 'playerId'>, playerData: {
595
590
  name?: string;
596
- email?: string;
597
591
  }): Promise<UserWithPlayer>;
598
592
  /**
599
593
  * Finds a user by ID
@@ -636,6 +630,16 @@ declare function findUsers(params: {
636
630
  where?: Prisma.UserWhereInput;
637
631
  orderBy?: Prisma.UserOrderByWithRelationInput;
638
632
  }): Promise<UserWithPlayer[]>;
633
+ /**
634
+ * Links a player to a user, automatically unlinking from any existing user.
635
+ * Uses a transaction to ensure atomicity.
636
+ *
637
+ * @param userId - The user to link the player to
638
+ * @param playerId - The player to link (null to unlink)
639
+ * @returns The updated user with player data
640
+ * @throws Error if player not found
641
+ */
642
+ declare function linkPlayerToUser(userId: string, playerId: string | null): Promise<UserWithPlayer>;
639
643
 
640
644
  /**
641
645
  * Re-export Prisma generated types
@@ -696,4 +700,4 @@ interface ConnectionStatus {
696
700
  error?: string;
697
701
  }
698
702
 
699
- export { type ConnectionStatus, type CreatePlayerInput, type CreateResultInput, type CreateTournamentInput, type CreateUserInput, type FindPlayersOptions, type FindResultsOptions, type FindTournamentsOptions, type PlayerStatistics, type PlayerWithResults, type TournamentResultWithTournament, type TournamentStatistics, type UpdatePlayerInput, type UpdateResultInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, connect, countPlayers, countResults, countTournaments, countUsers, createManyResults, createPlayer, createResult, createTournament, createUser, createUserWithPlayer, deletePlayer, deleteResult, deleteResultsByTournament, deleteTournament, deleteUser, disconnect, findPlayerByEmail, findPlayerByExternalId, findPlayerById, findPlayers, findResultById, findResultByPlayerAndTournament, findResults, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, getMajorTournaments, getPlayerResults, getPlayerStats, getPlayerTopFinishes, getPlayerWithResults, getRatedPlayers, getRecentTournaments, getTopPlayersByRanking, getTopPlayersByRating, getTournamentResults, getTournamentStats, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserByEmailWithPlayer, getUserWithPlayer, prisma, recalculateTimeDecay, searchPlayers, searchTournaments, testConnection, updatePlayer, updatePlayerRating, updateResult, updateResultPoints, updateTournament, updateUser, updateUserRefreshToken };
703
+ export { type ConnectionStatus, type CreatePlayerInput, type CreateResultInput, type CreateTournamentInput, type CreateUserInput, type FindPlayersOptions, type FindResultsOptions, type FindTournamentsOptions, type PlayerStatistics, type PlayerWithResults, type TournamentResultWithTournament, type TournamentStatistics, type UpdatePlayerInput, type UpdateResultInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, connect, countPlayers, countResults, countTournaments, countUsers, createManyResults, createPlayer, createResult, createTournament, createUser, createUserWithPlayer, deletePlayer, deleteResult, deleteResultsByTournament, deleteTournament, deleteUser, disconnect, findPlayerByExternalId, findPlayerById, findPlayerByUserEmail, findPlayers, findResultById, findResultByPlayerAndTournament, findResults, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, getMajorTournaments, getPlayerResults, getPlayerStats, getPlayerTopFinishes, getPlayerWithResults, getRatedPlayers, getRecentTournaments, getTopPlayersByRanking, getTopPlayersByRating, getTournamentResults, getTournamentStats, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserByEmailWithPlayer, getUserWithPlayer, linkPlayerToUser, prisma, recalculateTimeDecay, searchPlayers, searchTournaments, testConnection, updatePlayer, updatePlayerRating, updateResult, updateResultPoints, updateTournament, updateUser, updateUserRefreshToken };
package/dist/index.d.ts CHANGED
@@ -26,7 +26,6 @@ declare function testConnection(): Promise<boolean>;
26
26
  interface CreatePlayerInput {
27
27
  externalId?: string;
28
28
  name?: string;
29
- email?: string;
30
29
  rating?: number;
31
30
  ratingDeviation?: number;
32
31
  ranking?: number;
@@ -38,7 +37,6 @@ interface CreatePlayerInput {
38
37
  */
39
38
  interface UpdatePlayerInput {
40
39
  name?: string;
41
- email?: string;
42
40
  rating?: number;
43
41
  ratingDeviation?: number;
44
42
  ranking?: number;
@@ -70,9 +68,9 @@ declare function findPlayerById(id: string, include?: Prisma.PlayerInclude): Pro
70
68
  */
71
69
  declare function findPlayerByExternalId(externalId: string, include?: Prisma.PlayerInclude): Promise<Player | null>;
72
70
  /**
73
- * Finds a player by email
71
+ * Finds a player through their linked User's email
74
72
  */
75
- declare function findPlayerByEmail(email: string, include?: Prisma.PlayerInclude): Promise<Player | null>;
73
+ declare function findPlayerByUserEmail(email: string, include?: Prisma.PlayerInclude): Promise<Player | null>;
76
74
  /**
77
75
  * Finds multiple players with optional filters
78
76
  */
@@ -186,7 +184,6 @@ declare function getPlayerWithResults(id: string): Promise<{
186
184
  createdAt: Date;
187
185
  updatedAt: Date;
188
186
  externalId: string | null;
189
- email: string | null;
190
187
  rating: number;
191
188
  ratingDeviation: number;
192
189
  ranking: number | null;
@@ -196,7 +193,7 @@ declare function getPlayerWithResults(id: string): Promise<{
196
193
  lastEventDate: Date | null;
197
194
  } | null>;
198
195
  /**
199
- * Searches players by name or email
196
+ * Searches players by name
200
197
  */
201
198
  declare function searchPlayers(query: string, limit?: number): Promise<Player[]>;
202
199
 
@@ -302,7 +299,6 @@ declare function getTournamentWithResults(id: string): Promise<({
302
299
  createdAt: Date;
303
300
  updatedAt: Date;
304
301
  externalId: string | null;
305
- email: string | null;
306
302
  rating: number;
307
303
  ratingDeviation: number;
308
304
  ranking: number | null;
@@ -362,7 +358,6 @@ declare function getTournamentStats(id: string): Promise<{
362
358
  createdAt: Date;
363
359
  updatedAt: Date;
364
360
  externalId: string | null;
365
- email: string | null;
366
361
  rating: number;
367
362
  ratingDeviation: number;
368
363
  ranking: number | null;
@@ -561,7 +556,7 @@ interface CreateUserInput {
561
556
  interface UpdateUserInput {
562
557
  email?: string;
563
558
  passwordHash?: string;
564
- playerId?: string;
559
+ playerId?: string | null;
565
560
  role?: 'USER' | 'ADMIN';
566
561
  refreshTokenHash?: string | null;
567
562
  }
@@ -593,7 +588,6 @@ declare function createUser(data: CreateUserInput): Promise<User>;
593
588
  */
594
589
  declare function createUserWithPlayer(userData: Omit<CreateUserInput, 'playerId'>, playerData: {
595
590
  name?: string;
596
- email?: string;
597
591
  }): Promise<UserWithPlayer>;
598
592
  /**
599
593
  * Finds a user by ID
@@ -636,6 +630,16 @@ declare function findUsers(params: {
636
630
  where?: Prisma.UserWhereInput;
637
631
  orderBy?: Prisma.UserOrderByWithRelationInput;
638
632
  }): Promise<UserWithPlayer[]>;
633
+ /**
634
+ * Links a player to a user, automatically unlinking from any existing user.
635
+ * Uses a transaction to ensure atomicity.
636
+ *
637
+ * @param userId - The user to link the player to
638
+ * @param playerId - The player to link (null to unlink)
639
+ * @returns The updated user with player data
640
+ * @throws Error if player not found
641
+ */
642
+ declare function linkPlayerToUser(userId: string, playerId: string | null): Promise<UserWithPlayer>;
639
643
 
640
644
  /**
641
645
  * Re-export Prisma generated types
@@ -696,4 +700,4 @@ interface ConnectionStatus {
696
700
  error?: string;
697
701
  }
698
702
 
699
- export { type ConnectionStatus, type CreatePlayerInput, type CreateResultInput, type CreateTournamentInput, type CreateUserInput, type FindPlayersOptions, type FindResultsOptions, type FindTournamentsOptions, type PlayerStatistics, type PlayerWithResults, type TournamentResultWithTournament, type TournamentStatistics, type UpdatePlayerInput, type UpdateResultInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, connect, countPlayers, countResults, countTournaments, countUsers, createManyResults, createPlayer, createResult, createTournament, createUser, createUserWithPlayer, deletePlayer, deleteResult, deleteResultsByTournament, deleteTournament, deleteUser, disconnect, findPlayerByEmail, findPlayerByExternalId, findPlayerById, findPlayers, findResultById, findResultByPlayerAndTournament, findResults, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, getMajorTournaments, getPlayerResults, getPlayerStats, getPlayerTopFinishes, getPlayerWithResults, getRatedPlayers, getRecentTournaments, getTopPlayersByRanking, getTopPlayersByRating, getTournamentResults, getTournamentStats, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserByEmailWithPlayer, getUserWithPlayer, prisma, recalculateTimeDecay, searchPlayers, searchTournaments, testConnection, updatePlayer, updatePlayerRating, updateResult, updateResultPoints, updateTournament, updateUser, updateUserRefreshToken };
703
+ export { type ConnectionStatus, type CreatePlayerInput, type CreateResultInput, type CreateTournamentInput, type CreateUserInput, type FindPlayersOptions, type FindResultsOptions, type FindTournamentsOptions, type PlayerStatistics, type PlayerWithResults, type TournamentResultWithTournament, type TournamentStatistics, type UpdatePlayerInput, type UpdateResultInput, type UpdateTournamentInput, type UpdateUserInput, type UserWithPlayer, connect, countPlayers, countResults, countTournaments, countUsers, createManyResults, createPlayer, createResult, createTournament, createUser, createUserWithPlayer, deletePlayer, deleteResult, deleteResultsByTournament, deleteTournament, deleteUser, disconnect, findPlayerByExternalId, findPlayerById, findPlayerByUserEmail, findPlayers, findResultById, findResultByPlayerAndTournament, findResults, findTournamentByExternalId, findTournamentById, findTournaments, findUserByEmail, findUserById, findUsers, getMajorTournaments, getPlayerResults, getPlayerStats, getPlayerTopFinishes, getPlayerWithResults, getRatedPlayers, getRecentTournaments, getTopPlayersByRanking, getTopPlayersByRating, getTournamentResults, getTournamentStats, getTournamentWithResults, getTournamentsByBoosterType, getTournamentsByDateRange, getUserByEmailWithPlayer, getUserWithPlayer, linkPlayerToUser, prisma, recalculateTimeDecay, searchPlayers, searchTournaments, testConnection, updatePlayer, updatePlayerRating, updateResult, updateResultPoints, updateTournament, updateUser, updateUserRefreshToken };
package/dist/index.js CHANGED
@@ -41,11 +41,12 @@ async function findPlayerByExternalId(externalId, include) {
41
41
  include
42
42
  });
43
43
  }
44
- async function findPlayerByEmail(email, include) {
45
- return prisma.player.findUnique({
44
+ async function findPlayerByUserEmail(email, include) {
45
+ const user = await prisma.user.findUnique({
46
46
  where: { email },
47
- include
47
+ include: { player: include ? { include } : true }
48
48
  });
49
+ return user?.player ?? null;
49
50
  }
50
51
  async function findPlayers(options = {}) {
51
52
  return prisma.player.findMany({
@@ -134,10 +135,7 @@ async function searchPlayers(query, limit = 20) {
134
135
  return findPlayers({
135
136
  take: limit,
136
137
  where: {
137
- OR: [
138
- { name: { contains: query, mode: "insensitive" } },
139
- { email: { contains: query, mode: "insensitive" } }
140
- ]
138
+ name: { contains: query, mode: "insensitive" }
141
139
  }
142
140
  });
143
141
  }
@@ -460,8 +458,7 @@ async function createUserWithPlayer(userData, playerData) {
460
458
  return prisma.$transaction(async (tx) => {
461
459
  const player = await tx.player.create({
462
460
  data: {
463
- name: playerData.name,
464
- email: playerData.email
461
+ name: playerData.name
465
462
  }
466
463
  });
467
464
  const user = await tx.user.create({
@@ -584,6 +581,38 @@ async function findUsers(params) {
584
581
  });
585
582
  return users;
586
583
  }
584
+ async function linkPlayerToUser(userId, playerId) {
585
+ return prisma.$transaction(async (tx) => {
586
+ if (playerId) {
587
+ const player = await tx.player.findUnique({ where: { id: playerId } });
588
+ if (!player) {
589
+ throw new Error(`Player with id '${playerId}' not found`);
590
+ }
591
+ await tx.user.updateMany({
592
+ where: { playerId },
593
+ data: { playerId: null }
594
+ });
595
+ }
596
+ const user = await tx.user.update({
597
+ where: { id: userId },
598
+ data: { playerId },
599
+ include: {
600
+ player: {
601
+ select: {
602
+ id: true,
603
+ name: true,
604
+ rating: true,
605
+ ratingDeviation: true,
606
+ ranking: true,
607
+ isRated: true,
608
+ eventCount: true
609
+ }
610
+ }
611
+ }
612
+ });
613
+ return user;
614
+ });
615
+ }
587
616
  export {
588
617
  connect,
589
618
  countPlayers,
@@ -602,9 +631,9 @@ export {
602
631
  deleteTournament,
603
632
  deleteUser,
604
633
  disconnect,
605
- findPlayerByEmail,
606
634
  findPlayerByExternalId,
607
635
  findPlayerById,
636
+ findPlayerByUserEmail,
608
637
  findPlayers,
609
638
  findResultById,
610
639
  findResultByPlayerAndTournament,
@@ -631,6 +660,7 @@ export {
631
660
  getTournamentsByDateRange,
632
661
  getUserByEmailWithPlayer,
633
662
  getUserWithPlayer,
663
+ linkPlayerToUser,
634
664
  prisma,
635
665
  recalculateTimeDecay,
636
666
  searchPlayers,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opprs/db-prisma",
3
- "version": "1.2.0",
3
+ "version": "2.1.0",
4
4
  "description": "Database backend for OPPR (Open Pinball Player Ranking System) using Prisma and PostgreSQL",
5
5
  "keywords": [
6
6
  "oppr",
@@ -80,6 +80,7 @@
80
80
  "db:migrate:prod": "prisma migrate deploy",
81
81
  "db:studio": "prisma studio",
82
82
  "db:seed": "tsx prisma/seed.ts",
83
- "db:reset": "prisma migrate reset"
83
+ "db:reset": "prisma migrate reset",
84
+ "db:make-admin": "tsx scripts/make-admin.ts"
84
85
  }
85
86
  }
@@ -19,7 +19,6 @@ model Player {
19
19
  // Player identification
20
20
  externalId String? @unique // External ID from OPPR or other systems
21
21
  name String?
22
- email String? @unique
23
22
 
24
23
  // OPPR Rating fields
25
24
  rating Float @default(1500) // Glicko rating
@@ -36,7 +35,6 @@ model Player {
36
35
  tournamentResults TournamentResult[]
37
36
  user User?
38
37
 
39
- @@index([email])
40
38
  @@index([externalId])
41
39
  @@index([rating])
42
40
  @@index([ranking])