@opprs/db-prisma 2.1.0 → 2.2.1

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.
Files changed (2) hide show
  1. package/package.json +5 -3
  2. package/prisma/seed.ts +166 -109
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opprs/db-prisma",
3
- "version": "2.1.0",
3
+ "version": "2.2.1",
4
4
  "description": "Database backend for OPPR (Open Pinball Player Ranking System) using Prisma and PostgreSQL",
5
5
  "keywords": [
6
6
  "oppr",
@@ -40,7 +40,9 @@
40
40
  },
41
41
  "devDependencies": {
42
42
  "@testcontainers/postgresql": "^11.11.0",
43
+ "@types/bcrypt": "^6.0.0",
43
44
  "@types/node": "^22.10.5",
45
+ "bcrypt": "^6.0.0",
44
46
  "@typescript-eslint/eslint-plugin": "^8.19.1",
45
47
  "@typescript-eslint/parser": "^8.19.1",
46
48
  "@vitest/coverage-v8": "^4.0.16",
@@ -54,10 +56,10 @@
54
56
  "vitest": "^4.0.16"
55
57
  },
56
58
  "peerDependencies": {
57
- "@opprs/core": "^1.1.4"
59
+ "@opprs/core": "^2.2.1"
58
60
  },
59
61
  "engines": {
60
- "node": ">=18.0.0"
62
+ "node": ">=20.9.0"
61
63
  },
62
64
  "prisma": {
63
65
  "seed": "tsx prisma/seed.ts"
package/prisma/seed.ts CHANGED
@@ -1,182 +1,238 @@
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',
13
16
  name: 'Alice Champion',
14
- email: 'alice@example.com',
15
17
  rating: 1850,
16
18
  ratingDeviation: 50,
17
19
  ranking: 5,
18
20
  isRated: true,
19
21
  eventCount: 25,
20
22
  },
21
- });
22
-
23
- const player2 = await prisma.player.create({
24
- data: {
23
+ {
25
24
  externalId: 'player-2',
26
25
  name: 'Bob Wizard',
27
- email: 'bob@example.com',
28
26
  rating: 1750,
29
27
  ratingDeviation: 60,
30
28
  ranking: 12,
31
29
  isRated: true,
32
30
  eventCount: 18,
33
31
  },
34
- });
35
-
36
- const player3 = await prisma.player.create({
37
- data: {
32
+ {
38
33
  externalId: 'player-3',
39
34
  name: 'Charlie Flipper',
40
- email: 'charlie@example.com',
41
35
  rating: 1650,
42
36
  ratingDeviation: 75,
43
37
  ranking: 28,
44
38
  isRated: true,
45
39
  eventCount: 12,
46
40
  },
47
- });
48
-
49
- const player4 = await prisma.player.create({
50
- data: {
41
+ {
51
42
  externalId: 'player-4',
52
43
  name: 'Diana Tilt',
53
- email: 'diana@example.com',
54
44
  rating: 1550,
55
45
  ratingDeviation: 100,
56
46
  ranking: 45,
57
47
  isRated: true,
58
48
  eventCount: 8,
59
49
  },
60
- });
61
-
62
- const player5 = await prisma.player.create({
63
- data: {
50
+ {
64
51
  externalId: 'player-5',
65
52
  name: 'Eve Plunger',
66
- email: 'eve@example.com',
67
53
  rating: 1300,
68
54
  ratingDeviation: 150,
69
55
  ranking: null,
70
56
  isRated: false,
71
57
  eventCount: 3,
72
58
  },
59
+ ];
60
+
61
+ const player1 = await prisma.player.upsert({
62
+ where: { externalId: 'player-1' },
63
+ update: playerData[0],
64
+ create: playerData[0],
65
+ });
66
+
67
+ const player2 = await prisma.player.upsert({
68
+ where: { externalId: 'player-2' },
69
+ update: playerData[1],
70
+ create: playerData[1],
71
+ });
72
+
73
+ const player3 = await prisma.player.upsert({
74
+ where: { externalId: 'player-3' },
75
+ update: playerData[2],
76
+ create: playerData[2],
77
+ });
78
+
79
+ const player4 = await prisma.player.upsert({
80
+ where: { externalId: 'player-4' },
81
+ update: playerData[3],
82
+ create: playerData[3],
83
+ });
84
+
85
+ const player5 = await prisma.player.upsert({
86
+ where: { externalId: 'player-5' },
87
+ update: playerData[4],
88
+ create: playerData[4],
73
89
  });
74
90
 
75
91
  console.log(`✓ Created ${await prisma.player.count()} players`);
76
92
 
77
- // Create sample tournaments
93
+ // Create test user for e2e tests (linked to Alice Champion)
94
+ console.log('Creating test user...');
95
+ const testPassword = 'TestPassword123!';
96
+ const passwordHash = await bcrypt.hash(testPassword, BCRYPT_SALT_ROUNDS);
97
+
98
+ await prisma.user.upsert({
99
+ where: { email: 'e2e-test@example.com' },
100
+ update: {
101
+ passwordHash,
102
+ role: 'USER',
103
+ playerId: player1.id,
104
+ },
105
+ create: {
106
+ email: 'e2e-test@example.com',
107
+ passwordHash,
108
+ role: 'USER',
109
+ playerId: player1.id,
110
+ },
111
+ });
112
+
113
+ console.log(`✓ Created test user (e2e-test@example.com / ${testPassword})`);
114
+
115
+ // Create sample tournaments (using upsert for idempotency)
78
116
  console.log('Creating tournaments...');
79
117
 
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,
118
+ const tournament1Data = {
119
+ externalId: 'tournament-1',
120
+ name: 'World Pinball Championship 2024',
121
+ location: 'Las Vegas, NV',
122
+ date: new Date('2024-03-15'),
123
+ eventBooster: EventBoosterType.MAJOR,
124
+ allowsOptOut: false,
125
+ tgpConfig: {
126
+ qualifying: {
127
+ type: 'limited',
128
+ meaningfulGames: 12,
129
+ fourPlayerGroups: true,
102
130
  },
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,
131
+ finals: {
132
+ formatType: 'match-play',
133
+ meaningfulGames: 20,
134
+ fourPlayerGroups: true,
135
+ finalistCount: 16,
136
+ },
137
+ ballCountAdjustment: 1.0,
110
138
  },
139
+ baseValue: 32.0,
140
+ tvaRating: 25.0,
141
+ tvaRanking: 50.0,
142
+ totalTVA: 75.0,
143
+ tgp: 1.92,
144
+ eventBoosterMultiplier: 2.0,
145
+ firstPlaceValue: 411.84,
146
+ };
147
+
148
+ const tournament1 = await prisma.tournament.upsert({
149
+ where: { externalId: 'tournament-1' },
150
+ update: tournament1Data,
151
+ create: tournament1Data,
111
152
  });
112
153
 
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
- },
154
+ const tournament2Data = {
155
+ externalId: 'tournament-2',
156
+ name: 'Spring Classics 2024',
157
+ location: 'Portland, OR',
158
+ date: new Date('2024-04-20'),
159
+ eventBooster: EventBoosterType.CERTIFIED,
160
+ allowsOptOut: true,
161
+ tgpConfig: {
162
+ qualifying: {
163
+ type: 'limited',
164
+ meaningfulGames: 7,
165
+ },
166
+ finals: {
167
+ formatType: 'double-elimination',
168
+ meaningfulGames: 15,
169
+ fourPlayerGroups: false,
170
+ finalistCount: 8,
133
171
  },
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
172
  },
173
+ baseValue: 28.0,
174
+ tvaRating: 18.5,
175
+ tvaRanking: 32.0,
176
+ totalTVA: 50.5,
177
+ tgp: 0.88,
178
+ eventBoosterMultiplier: 1.25,
179
+ firstPlaceValue: 87.28,
180
+ };
181
+
182
+ const tournament2 = await prisma.tournament.upsert({
183
+ where: { externalId: 'tournament-2' },
184
+ update: tournament2Data,
185
+ create: tournament2Data,
142
186
  });
143
187
 
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
- },
188
+ const tournament3Data = {
189
+ externalId: 'tournament-3',
190
+ name: 'Monthly League Finals',
191
+ location: 'Seattle, WA',
192
+ date: new Date('2024-05-10'),
193
+ eventBooster: EventBoosterType.NONE,
194
+ allowsOptOut: false,
195
+ tgpConfig: {
196
+ qualifying: {
197
+ type: 'none',
198
+ meaningfulGames: 0,
199
+ },
200
+ finals: {
201
+ formatType: 'match-play',
202
+ meaningfulGames: 10,
203
+ fourPlayerGroups: true,
204
+ finalistCount: 8,
164
205
  },
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
206
  },
207
+ baseValue: 15.0,
208
+ tvaRating: 8.5,
209
+ tvaRanking: 12.0,
210
+ totalTVA: 20.5,
211
+ tgp: 0.80,
212
+ eventBoosterMultiplier: 1.0,
213
+ firstPlaceValue: 28.4,
214
+ };
215
+
216
+ const tournament3 = await prisma.tournament.upsert({
217
+ where: { externalId: 'tournament-3' },
218
+ update: tournament3Data,
219
+ create: tournament3Data,
173
220
  });
174
221
 
175
222
  console.log(`✓ Created ${await prisma.tournament.count()} tournaments`);
176
223
 
177
- // Create tournament results
224
+ // Create tournament results (delete existing first for idempotency)
178
225
  console.log('Creating tournament results...');
179
226
 
227
+ // Delete existing results for seeded tournaments
228
+ await prisma.tournamentResult.deleteMany({
229
+ where: {
230
+ tournamentId: {
231
+ in: [tournament1.id, tournament2.id, tournament3.id],
232
+ },
233
+ },
234
+ });
235
+
180
236
  // World Championship results
181
237
  await prisma.tournamentResult.createMany({
182
238
  data: [
@@ -334,6 +390,7 @@ async function main() {
334
390
  console.log('');
335
391
  console.log('Summary:');
336
392
  console.log(` - ${await prisma.player.count()} players`);
393
+ console.log(` - ${await prisma.user.count()} users`);
337
394
  console.log(` - ${await prisma.tournament.count()} tournaments`);
338
395
  console.log(` - ${await prisma.tournamentResult.count()} tournament results`);
339
396
  }