@opprs/db-prisma 2.1.0 → 2.2.1-canary.090cc41

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/prisma/seed.ts CHANGED
@@ -1,189 +1,342 @@
1
1
  import { PrismaClient, EventBoosterType } from '@prisma/client';
2
+ import bcrypt from 'bcrypt';
2
3
 
3
4
  const prisma = new PrismaClient();
4
5
 
6
+ const BCRYPT_SALT_ROUNDS = 12;
7
+
5
8
  async function main() {
6
9
  console.log('🌱 Seeding database...');
7
10
 
8
- // Create sample players
11
+ // Create sample players (using upsert for idempotency)
9
12
  console.log('Creating players...');
10
- const player1 = await prisma.player.create({
11
- data: {
13
+ const playerData = [
14
+ {
12
15
  externalId: 'player-1',
16
+ playerNumber: 10001,
13
17
  name: 'Alice Champion',
14
- email: 'alice@example.com',
15
- rating: 1850,
16
- ratingDeviation: 50,
17
- ranking: 5,
18
- isRated: true,
19
18
  eventCount: 25,
20
19
  },
21
- });
22
-
23
- const player2 = await prisma.player.create({
24
- data: {
20
+ {
25
21
  externalId: 'player-2',
22
+ playerNumber: 10002,
26
23
  name: 'Bob Wizard',
27
- email: 'bob@example.com',
28
- rating: 1750,
29
- ratingDeviation: 60,
30
- ranking: 12,
31
- isRated: true,
32
24
  eventCount: 18,
33
25
  },
34
- });
35
-
36
- const player3 = await prisma.player.create({
37
- data: {
26
+ {
38
27
  externalId: 'player-3',
28
+ playerNumber: 10003,
39
29
  name: 'Charlie Flipper',
40
- email: 'charlie@example.com',
41
- rating: 1650,
42
- ratingDeviation: 75,
43
- ranking: 28,
44
- isRated: true,
45
30
  eventCount: 12,
46
31
  },
47
- });
48
-
49
- const player4 = await prisma.player.create({
50
- data: {
32
+ {
51
33
  externalId: 'player-4',
34
+ playerNumber: 10004,
52
35
  name: 'Diana Tilt',
53
- email: 'diana@example.com',
54
- rating: 1550,
55
- ratingDeviation: 100,
56
- ranking: 45,
57
- isRated: true,
58
36
  eventCount: 8,
59
37
  },
60
- });
61
-
62
- const player5 = await prisma.player.create({
63
- data: {
38
+ {
64
39
  externalId: 'player-5',
40
+ playerNumber: 10005,
65
41
  name: 'Eve Plunger',
66
- email: 'eve@example.com',
67
- rating: 1300,
68
- ratingDeviation: 150,
69
- ranking: null,
70
- isRated: false,
71
42
  eventCount: 3,
72
43
  },
44
+ ];
45
+
46
+ // OPPR ranking data for each player
47
+ const rankingData = [
48
+ { rating: 1850, ratingDeviation: 50, ranking: 5, isRated: true },
49
+ { rating: 1750, ratingDeviation: 60, ranking: 12, isRated: true },
50
+ { rating: 1650, ratingDeviation: 75, ranking: 28, isRated: true },
51
+ { rating: 1550, ratingDeviation: 100, ranking: 45, isRated: true },
52
+ { rating: 1300, ratingDeviation: 150, ranking: null, isRated: false },
53
+ ];
54
+
55
+ const player1 = await prisma.player.upsert({
56
+ where: { externalId: 'player-1' },
57
+ update: playerData[0],
58
+ create: playerData[0],
59
+ });
60
+
61
+ const player2 = await prisma.player.upsert({
62
+ where: { externalId: 'player-2' },
63
+ update: playerData[1],
64
+ create: playerData[1],
65
+ });
66
+
67
+ const player3 = await prisma.player.upsert({
68
+ where: { externalId: 'player-3' },
69
+ update: playerData[2],
70
+ create: playerData[2],
71
+ });
72
+
73
+ const player4 = await prisma.player.upsert({
74
+ where: { externalId: 'player-4' },
75
+ update: playerData[3],
76
+ create: playerData[3],
77
+ });
78
+
79
+ const player5 = await prisma.player.upsert({
80
+ where: { externalId: 'player-5' },
81
+ update: playerData[4],
82
+ create: playerData[4],
73
83
  });
74
84
 
75
85
  console.log(`✓ Created ${await prisma.player.count()} players`);
76
86
 
77
- // Create sample tournaments
87
+ // Create OPPR rankings for each player
88
+ console.log('Creating OPPR rankings...');
89
+ const players = [player1, player2, player3, player4, player5];
90
+ for (let i = 0; i < players.length; i++) {
91
+ await prisma.opprPlayerRanking.upsert({
92
+ where: { playerId: players[i].id },
93
+ update: rankingData[i],
94
+ create: { playerId: players[i].id, ...rankingData[i] },
95
+ });
96
+ }
97
+ console.log(`✓ Created ${await prisma.opprPlayerRanking.count()} OPPR rankings`);
98
+
99
+ // Seed users from environment variables (development only)
100
+ const seedAdminEmail = process.env.SEED_ADMIN_EMAIL;
101
+ const seedAdminPassword = process.env.SEED_ADMIN_PASSWORD;
102
+ const seedTestEmail = process.env.SEED_TEST_EMAIL;
103
+ const seedTestPassword = process.env.SEED_TEST_PASSWORD;
104
+
105
+ // Create admin user if credentials provided
106
+ if (seedAdminEmail && seedAdminPassword) {
107
+ console.log('Creating admin user...');
108
+ const adminPasswordHash = await bcrypt.hash(seedAdminPassword, BCRYPT_SALT_ROUNDS);
109
+ await prisma.user.upsert({
110
+ where: { email: seedAdminEmail },
111
+ update: { passwordHash: adminPasswordHash, role: 'ADMIN' },
112
+ create: { email: seedAdminEmail, passwordHash: adminPasswordHash, role: 'ADMIN' },
113
+ });
114
+ console.log(`✓ Created admin user (${seedAdminEmail})`);
115
+ } else {
116
+ console.log('⏭ Skipping admin user (SEED_ADMIN_EMAIL/SEED_ADMIN_PASSWORD not set)');
117
+ }
118
+
119
+ // Create test user if credentials provided (linked to Alice Champion)
120
+ if (seedTestEmail && seedTestPassword) {
121
+ console.log('Creating test user...');
122
+ const testPasswordHash = await bcrypt.hash(seedTestPassword, BCRYPT_SALT_ROUNDS);
123
+ await prisma.user.upsert({
124
+ where: { email: seedTestEmail },
125
+ update: { passwordHash: testPasswordHash, role: 'USER', playerId: player1.id },
126
+ create: { email: seedTestEmail, passwordHash: testPasswordHash, role: 'USER', playerId: player1.id },
127
+ });
128
+ console.log(`✓ Created test user (${seedTestEmail}) linked to ${player1.name}`);
129
+ } else {
130
+ console.log('⏭ Skipping test user (SEED_TEST_EMAIL/SEED_TEST_PASSWORD not set)');
131
+ }
132
+
133
+ // Create admin user
134
+ console.log('Creating admin user...');
135
+ const adminPassword = 'AdminPassword123!';
136
+ const adminPasswordHash = await bcrypt.hash(adminPassword, BCRYPT_SALT_ROUNDS);
137
+
138
+ await prisma.user.upsert({
139
+ where: { email: 'admin@example.com' },
140
+ update: {
141
+ passwordHash: adminPasswordHash,
142
+ role: 'ADMIN',
143
+ },
144
+ create: {
145
+ email: 'admin@example.com',
146
+ passwordHash: adminPasswordHash,
147
+ role: 'ADMIN',
148
+ },
149
+ });
150
+
151
+ console.log(`✓ Created admin user (admin@example.com / ${adminPassword})`);
152
+
153
+ // Create sample locations (using upsert for idempotency)
154
+ console.log('Creating locations...');
155
+
156
+ const location1 = await prisma.location.upsert({
157
+ where: { externalId: 'location-1' },
158
+ update: {
159
+ name: 'Las Vegas Convention Center',
160
+ city: 'Las Vegas',
161
+ state: 'NV',
162
+ country: 'USA',
163
+ },
164
+ create: {
165
+ externalId: 'location-1',
166
+ name: 'Las Vegas Convention Center',
167
+ city: 'Las Vegas',
168
+ state: 'NV',
169
+ country: 'USA',
170
+ },
171
+ });
172
+
173
+ const location2 = await prisma.location.upsert({
174
+ where: { externalId: 'location-2' },
175
+ update: {
176
+ name: 'Ground Kontrol',
177
+ address: '115 NW 5th Ave',
178
+ city: 'Portland',
179
+ state: 'OR',
180
+ country: 'USA',
181
+ },
182
+ create: {
183
+ externalId: 'location-2',
184
+ name: 'Ground Kontrol',
185
+ address: '115 NW 5th Ave',
186
+ city: 'Portland',
187
+ state: 'OR',
188
+ country: 'USA',
189
+ },
190
+ });
191
+
192
+ const location3 = await prisma.location.upsert({
193
+ where: { externalId: 'location-3' },
194
+ update: {
195
+ name: 'Add-a-Ball Amusements',
196
+ city: 'Seattle',
197
+ state: 'WA',
198
+ country: 'USA',
199
+ },
200
+ create: {
201
+ externalId: 'location-3',
202
+ name: 'Add-a-Ball Amusements',
203
+ city: 'Seattle',
204
+ state: 'WA',
205
+ country: 'USA',
206
+ },
207
+ });
208
+
209
+ console.log(`✓ Created ${await prisma.location.count()} locations`);
210
+
211
+ // Create sample tournaments (using upsert for idempotency)
78
212
  console.log('Creating tournaments...');
79
213
 
80
- // Major Championship Tournament
81
- const tournament1 = await prisma.tournament.create({
82
- data: {
83
- externalId: 'tournament-1',
84
- name: 'World Pinball Championship 2024',
85
- location: 'Las Vegas, NV',
86
- date: new Date('2024-03-15'),
87
- eventBooster: EventBoosterType.MAJOR,
88
- allowsOptOut: false,
89
- tgpConfig: {
90
- qualifying: {
91
- type: 'limited',
92
- meaningfulGames: 12,
93
- fourPlayerGroups: true,
94
- },
95
- finals: {
96
- formatType: 'match-play',
97
- meaningfulGames: 20,
98
- fourPlayerGroups: true,
99
- finalistCount: 16,
100
- },
101
- ballCountAdjustment: 1.0,
214
+ const tournament1Data = {
215
+ externalId: 'tournament-1',
216
+ name: 'World Pinball Championship 2024',
217
+ locationId: location1.id,
218
+ date: new Date('2024-03-15'),
219
+ eventBooster: EventBoosterType.MAJOR,
220
+ allowsOptOut: false,
221
+ tgpConfig: {
222
+ qualifying: {
223
+ type: 'limited',
224
+ meaningfulGames: 12,
225
+ fourPlayerGroups: true,
226
+ },
227
+ finals: {
228
+ formatType: 'match-play',
229
+ meaningfulGames: 20,
230
+ fourPlayerGroups: true,
231
+ finalistCount: 16,
102
232
  },
103
- baseValue: 32.0,
104
- tvaRating: 25.0,
105
- tvaRanking: 50.0,
106
- totalTVA: 75.0,
107
- tgp: 1.92,
108
- eventBoosterMultiplier: 2.0,
109
- firstPlaceValue: 411.84,
233
+ ballCountAdjustment: 1.0,
110
234
  },
235
+ baseValue: 32.0,
236
+ tvaRating: 25.0,
237
+ tvaRanking: 50.0,
238
+ totalTVA: 75.0,
239
+ tgp: 1.92,
240
+ eventBoosterMultiplier: 2.0,
241
+ firstPlaceValue: 411.84,
242
+ };
243
+
244
+ const tournament1 = await prisma.tournament.upsert({
245
+ where: { externalId: 'tournament-1' },
246
+ update: tournament1Data,
247
+ create: tournament1Data,
111
248
  });
112
249
 
113
- // Certified Tournament
114
- const tournament2 = await prisma.tournament.create({
115
- data: {
116
- externalId: 'tournament-2',
117
- name: 'Spring Classics 2024',
118
- location: 'Portland, OR',
119
- date: new Date('2024-04-20'),
120
- eventBooster: EventBoosterType.CERTIFIED,
121
- allowsOptOut: true,
122
- tgpConfig: {
123
- qualifying: {
124
- type: 'limited',
125
- meaningfulGames: 7,
126
- },
127
- finals: {
128
- formatType: 'double-elimination',
129
- meaningfulGames: 15,
130
- fourPlayerGroups: false,
131
- finalistCount: 8,
132
- },
250
+ const tournament2Data = {
251
+ externalId: 'tournament-2',
252
+ name: 'Spring Classics 2024',
253
+ locationId: location2.id,
254
+ date: new Date('2024-04-20'),
255
+ eventBooster: EventBoosterType.CERTIFIED,
256
+ allowsOptOut: true,
257
+ tgpConfig: {
258
+ qualifying: {
259
+ type: 'limited',
260
+ meaningfulGames: 7,
261
+ },
262
+ finals: {
263
+ formatType: 'double-elimination',
264
+ meaningfulGames: 15,
265
+ fourPlayerGroups: false,
266
+ finalistCount: 8,
133
267
  },
134
- baseValue: 28.0,
135
- tvaRating: 18.5,
136
- tvaRanking: 32.0,
137
- totalTVA: 50.5,
138
- tgp: 0.88,
139
- eventBoosterMultiplier: 1.25,
140
- firstPlaceValue: 87.28,
141
268
  },
269
+ baseValue: 28.0,
270
+ tvaRating: 18.5,
271
+ tvaRanking: 32.0,
272
+ totalTVA: 50.5,
273
+ tgp: 0.88,
274
+ eventBoosterMultiplier: 1.25,
275
+ firstPlaceValue: 87.28,
276
+ };
277
+
278
+ const tournament2 = await prisma.tournament.upsert({
279
+ where: { externalId: 'tournament-2' },
280
+ update: tournament2Data,
281
+ create: tournament2Data,
142
282
  });
143
283
 
144
- // Local Tournament
145
- const tournament3 = await prisma.tournament.create({
146
- data: {
147
- externalId: 'tournament-3',
148
- name: 'Monthly League Finals',
149
- location: 'Seattle, WA',
150
- date: new Date('2024-05-10'),
151
- eventBooster: EventBoosterType.NONE,
152
- allowsOptOut: false,
153
- tgpConfig: {
154
- qualifying: {
155
- type: 'none',
156
- meaningfulGames: 0,
157
- },
158
- finals: {
159
- formatType: 'match-play',
160
- meaningfulGames: 10,
161
- fourPlayerGroups: true,
162
- finalistCount: 8,
163
- },
284
+ const tournament3Data = {
285
+ externalId: 'tournament-3',
286
+ name: 'Monthly League Finals',
287
+ locationId: location3.id,
288
+ date: new Date('2024-05-10'),
289
+ eventBooster: EventBoosterType.NONE,
290
+ allowsOptOut: false,
291
+ tgpConfig: {
292
+ qualifying: {
293
+ type: 'none',
294
+ meaningfulGames: 0,
295
+ },
296
+ finals: {
297
+ formatType: 'match-play',
298
+ meaningfulGames: 10,
299
+ fourPlayerGroups: true,
300
+ finalistCount: 8,
164
301
  },
165
- baseValue: 15.0,
166
- tvaRating: 8.5,
167
- tvaRanking: 12.0,
168
- totalTVA: 20.5,
169
- tgp: 0.80,
170
- eventBoosterMultiplier: 1.0,
171
- firstPlaceValue: 28.4,
172
302
  },
303
+ baseValue: 15.0,
304
+ tvaRating: 8.5,
305
+ tvaRanking: 12.0,
306
+ totalTVA: 20.5,
307
+ tgp: 0.80,
308
+ eventBoosterMultiplier: 1.0,
309
+ firstPlaceValue: 28.4,
310
+ };
311
+
312
+ const tournament3 = await prisma.tournament.upsert({
313
+ where: { externalId: 'tournament-3' },
314
+ update: tournament3Data,
315
+ create: tournament3Data,
173
316
  });
174
317
 
175
318
  console.log(`✓ Created ${await prisma.tournament.count()} tournaments`);
176
319
 
177
- // Create tournament results
178
- console.log('Creating tournament results...');
320
+ // Create tournament standings (delete existing first for idempotency)
321
+ console.log('Creating tournament standings...');
322
+
323
+ // Delete existing standings for seeded tournaments
324
+ await prisma.standing.deleteMany({
325
+ where: {
326
+ tournamentId: {
327
+ in: [tournament1.id, tournament2.id, tournament3.id],
328
+ },
329
+ },
330
+ });
179
331
 
180
- // World Championship results
181
- await prisma.tournamentResult.createMany({
332
+ // World Championship standings
333
+ await prisma.standing.createMany({
182
334
  data: [
183
335
  {
184
336
  playerId: player1.id,
185
337
  tournamentId: tournament1.id,
186
338
  position: 1,
339
+ isFinals: true,
187
340
  totalPoints: 411.84,
188
341
  linearPoints: 41.18,
189
342
  dynamicPoints: 370.66,
@@ -196,6 +349,7 @@ async function main() {
196
349
  playerId: player2.id,
197
350
  tournamentId: tournament1.id,
198
351
  position: 2,
352
+ isFinals: true,
199
353
  totalPoints: 298.45,
200
354
  linearPoints: 41.18,
201
355
  dynamicPoints: 257.27,
@@ -208,6 +362,7 @@ async function main() {
208
362
  playerId: player3.id,
209
363
  tournamentId: tournament1.id,
210
364
  position: 3,
365
+ isFinals: true,
211
366
  totalPoints: 215.32,
212
367
  linearPoints: 41.18,
213
368
  dynamicPoints: 174.14,
@@ -220,6 +375,7 @@ async function main() {
220
375
  playerId: player4.id,
221
376
  tournamentId: tournament1.id,
222
377
  position: 5,
378
+ isFinals: true,
223
379
  totalPoints: 125.18,
224
380
  linearPoints: 41.18,
225
381
  dynamicPoints: 84.00,
@@ -231,13 +387,14 @@ async function main() {
231
387
  ],
232
388
  });
233
389
 
234
- // Spring Classics results
235
- await prisma.tournamentResult.createMany({
390
+ // Spring Classics standings
391
+ await prisma.standing.createMany({
236
392
  data: [
237
393
  {
238
394
  playerId: player2.id,
239
395
  tournamentId: tournament2.id,
240
396
  position: 1,
397
+ isFinals: true,
241
398
  totalPoints: 87.28,
242
399
  linearPoints: 8.73,
243
400
  dynamicPoints: 78.55,
@@ -250,6 +407,7 @@ async function main() {
250
407
  playerId: player1.id,
251
408
  tournamentId: tournament2.id,
252
409
  position: 2,
410
+ isFinals: true,
253
411
  totalPoints: 63.25,
254
412
  linearPoints: 8.73,
255
413
  dynamicPoints: 54.52,
@@ -262,6 +420,7 @@ async function main() {
262
420
  playerId: player4.id,
263
421
  tournamentId: tournament2.id,
264
422
  position: 3,
423
+ isFinals: true,
265
424
  totalPoints: 45.67,
266
425
  linearPoints: 8.73,
267
426
  dynamicPoints: 36.94,
@@ -274,6 +433,7 @@ async function main() {
274
433
  playerId: player5.id,
275
434
  tournamentId: tournament2.id,
276
435
  position: 6,
436
+ isFinals: true,
277
437
  totalPoints: 18.52,
278
438
  linearPoints: 8.73,
279
439
  dynamicPoints: 9.79,
@@ -285,13 +445,14 @@ async function main() {
285
445
  ],
286
446
  });
287
447
 
288
- // Monthly League results
289
- await prisma.tournamentResult.createMany({
448
+ // Monthly League standings
449
+ await prisma.standing.createMany({
290
450
  data: [
291
451
  {
292
452
  playerId: player3.id,
293
453
  tournamentId: tournament3.id,
294
454
  position: 1,
455
+ isFinals: true,
295
456
  totalPoints: 28.4,
296
457
  linearPoints: 2.84,
297
458
  dynamicPoints: 25.56,
@@ -304,6 +465,7 @@ async function main() {
304
465
  playerId: player4.id,
305
466
  tournamentId: tournament3.id,
306
467
  position: 2,
468
+ isFinals: true,
307
469
  totalPoints: 20.58,
308
470
  linearPoints: 2.84,
309
471
  dynamicPoints: 17.74,
@@ -316,6 +478,7 @@ async function main() {
316
478
  playerId: player5.id,
317
479
  tournamentId: tournament3.id,
318
480
  position: 3,
481
+ isFinals: true,
319
482
  totalPoints: 14.85,
320
483
  linearPoints: 2.84,
321
484
  dynamicPoints: 12.01,
@@ -327,15 +490,18 @@ async function main() {
327
490
  ],
328
491
  });
329
492
 
330
- console.log(`✓ Created ${await prisma.tournamentResult.count()} tournament results`);
493
+ console.log(`✓ Created ${await prisma.standing.count()} tournament standings`);
331
494
 
332
495
  console.log('');
333
496
  console.log('✅ Database seeded successfully!');
334
497
  console.log('');
335
498
  console.log('Summary:');
336
499
  console.log(` - ${await prisma.player.count()} players`);
500
+ console.log(` - ${await prisma.opprPlayerRanking.count()} OPPR rankings`);
501
+ console.log(` - ${await prisma.user.count()} users`);
502
+ console.log(` - ${await prisma.location.count()} locations`);
337
503
  console.log(` - ${await prisma.tournament.count()} tournaments`);
338
- console.log(` - ${await prisma.tournamentResult.count()} tournament results`);
504
+ console.log(` - ${await prisma.standing.count()} standings`);
339
505
  }
340
506
 
341
507
  main()