refactor(*): Implement CSV-based seeding, dynamic box placement, and enforce forms from pokedex configuration

This commit is contained in:
Josh Creek
2026-01-05 09:44:15 +00:00
parent 19a571e315
commit b9a49686c1
18 changed files with 1054 additions and 1625 deletions
+155
View File
@@ -0,0 +1,155 @@
# Pokémon Data (CSV Format)
This directory contains Pokémon data in CSV format for easy editing and maintenance.
## File Structure
```
/data/pokemon/
├── gen1-kanto.csv # Gen 1 Pokémon (Kanto region, #1-151)
├── gen2-johto.csv # Gen 2 Pokémon (Johto region, #152-251) - Future
├── gen3-hoenn.csv # Gen 3 Pokémon (Hoenn region, #252-386) - Future
├── games.csv # All Pokémon games definitions
└── README.md # This file
```
## CSV Format
### gen{N}-{region}.csv
One CSV file per generation/region containing all Pokémon from that generation.
**Columns:**
- `pokedexNumber` - National Pokédex number (e.g., 1, 25, 151)
- `name` - Pokémon name (e.g., Bulbasaur, Pikachu, Mew)
- `form` - Form name (empty for base form, "Female" for gender differences, "Alolan" for regional forms, etc.)
- `games` - Pipe-separated list of games where this Pokémon can be caught (e.g., "Red|Blue|Yellow")
- `regionalNumber` - Regional Pokédex number for base forms (empty for gender/alternative forms)
**Example (gen1-kanto.csv):**
```csv
pokedexNumber,name,form,games,regionalNumber
1,Bulbasaur,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,1
3,Venusaur,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,3
3,Venusaur,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
25,Pikachu,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,25
151,Mew,,Red|Blue|Yellow,151
```
### games.csv
Defines all Pokémon games.
**Columns:**
- `id` - Unique game identifier (lowercase, hyphenated, e.g., "red", "lg-pikachu")
- `displayName` - Display name for the game (e.g., "Red", "LG: Pikachu")
- `region` - Region/generation the game belongs to (e.g., "Kanto", "Johto")
- `generation` - Generation number (1-9)
**Example:**
```csv
id,displayName,region,generation
red,Red,Kanto,1
blue,Blue,Kanto,1
lg-pikachu,LG: Pikachu,Kanto,7
```
## Editing with Excel/Google Sheets
CSV files are designed to be edited in spreadsheet applications:
1. Open the CSV file in Excel or Google Sheets
2. Use formulas, sorting, and filtering for bulk operations
3. Save as CSV when done
**Example workflows:**
### Adding a new game to existing Pokémon
Find & Replace in the `games` column:
- Find: `Red|Blue`
- Replace: `Red|Blue|NewGame`
### Adding a new Pokémon
Add a new row with all required fields:
```csv
152,Chikorita,,Gold|Silver|Crystal,1
```
### Adding a regional form
Add a new row with the form name:
```csv
19,Rattata,Alolan,Sun|Moon|US|UM,
```
## Generating SQL Migrations
After editing CSV files, generate SQL migrations using npm scripts:
```bash
# Generate migration for Kanto
npm run seed:kanto
# Generate migration for Johto (when ready)
npm run seed:johto
# Custom region
npm run seed:generate <RegionName>
```
Generated migrations will be created in `/supabase/migrations/` with timestamp prefixes.
## Testing Changes
After generating a migration:
```bash
# Reset local database to test
npm run supabase:reset
# Verify the changes loaded correctly
```
## Important Notes
1. **Regional Numbers**: Only base forms (no `form` value) should have `regionalNumber` values. Forms like "Female" or "Alolan" should leave this column empty.
2. **Game Names**: Must exactly match the `displayName` in `games.csv`. Use pipe `|` as separator, no spaces around pipes.
3. **National Dex Numbers**: Must be accurate. Gender forms and regional variants share the same `pokedexNumber` as their base form.
4. **CSV Encoding**: Save files with UTF-8 encoding to support special characters.
5. **Quotes**: Only use quotes around values containing commas. Excel/Google Sheets handles this automatically.
## Common Operations
### Add a new generation (e.g., Gen 2 - Johto)
1. Create `gen2-johto.csv` with the format above
2. Add Johto games to `games.csv`
3. Run `npm run seed:johto`
4. Test with `npm run supabase:reset`
### Add a new game to existing generation
1. Open `games.csv`, add new game row
2. Open the relevant `gen{N}-{region}.csv` file
3. Use Find & Replace to add the new game to the `games` column
4. Regenerate the migration: `npm run seed:{region}`
5. Test with `npm run supabase:reset`
### Add DLC/expansion Pokémon
1. Add new Pokémon rows to the appropriate generation CSV
2. Update the `games` column with the DLC games
3. Regenerate the migration
4. Test
## Database Schema
Generated migrations insert data into two tables:
- **`pokedex_entries`**: Pokémon species data (name, form, games, etc.)
- **`regional_dex_numbers`**: Regional Pokédex numbers (separate table for scalability)
This design allows adding new regions without database schema changes.
+6
View File
@@ -0,0 +1,6 @@
id,displayName,region,generation
red,Red,Kanto,1
blue,Blue,Kanto,1
yellow,Yellow,Kanto,1
lg--pikachu,LG: Pikachu,Kanto,7
lg--eevee,LG: Eevee,Kanto,7
1 id displayName region generation
2 red Red Kanto 1
3 blue Blue Kanto 1
4 yellow Yellow Kanto 1
5 lg--pikachu LG: Pikachu Kanto 7
6 lg--eevee LG: Eevee Kanto 7
+175
View File
@@ -0,0 +1,175 @@
pokedexNumber,name,form,games,regionalNumber
1,Bulbasaur,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,1
2,Ivysaur,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,2
3,Venusaur,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,3
3,Venusaur,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
4,Charmander,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,4
5,Charmeleon,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,5
6,Charizard,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,6
7,Squirtle,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,7
8,Wartortle,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,8
9,Blastoise,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,9
10,Caterpie,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,10
11,Metapod,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,11
12,Butterfree,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,12
12,Butterfree,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
13,Weedle,,Red|Blue|LG: Pikachu|LG: Eevee,13
14,Kakuna,,Red|Blue|LG: Pikachu|LG: Eevee,14
15,Beedrill,,Red|Blue|LG: Pikachu|LG: Eevee,15
16,Pidgey,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,16
17,Pidgeotto,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,17
18,Pidgeot,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,18
19,Rattata,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,19
19,Rattata,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
20,Raticate,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,20
20,Raticate,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
21,Spearow,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,21
22,Fearow,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,22
23,Ekans,,Red|Blue|LG: Eevee,23
24,Arbok,,Red|Blue|LG: Eevee,24
25,Pikachu,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,25
25,Pikachu,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
26,Raichu,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,26
26,Raichu,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
27,Sandshrew,,Blue|Yellow|LG: Pikachu,27
28,Sandslash,,Blue|Yellow|LG: Pikachu,28
29,Nidoran♀,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,29
30,Nidorina,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,30
31,Nidoqueen,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,31
32,Nidoran♂,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,32
33,Nidorino,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,33
34,Nidoking,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,34
35,Clefairy,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,35
36,Clefable,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,36
37,Vulpix,,Blue|Yellow|LG: Eevee,37
38,Ninetales,,Blue|Yellow|LG: Eevee,38
39,Jigglypuff,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,39
40,Wigglytuff,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,40
41,Zubat,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,41
41,Zubat,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
42,Golbat,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,42
42,Golbat,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
43,Oddish,,Red|Yellow|LG: Pikachu,43
44,Gloom,,Red|Yellow|LG: Pikachu,44
44,Gloom,Female,Red|Yellow|LG: Pikachu,
45,Vileplume,,Red|Yellow|LG: Pikachu,45
45,Vileplume,Female,Red|Yellow|LG: Pikachu,
46,Paras,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,46
47,Parasect,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,47
48,Venonat,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,48
49,Venomoth,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,49
50,Diglett,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,50
51,Dugtrio,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,51
52,Meowth,,Blue|LG: Eevee,52
53,Persian,,Blue|LG: Eevee,53
54,Psyduck,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,54
55,Golduck,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,55
56,Mankey,,Red|Yellow|LG: Pikachu,56
57,Primeape,,Red|Yellow|LG: Pikachu,57
58,Growlithe,,Red|Yellow|LG: Pikachu,58
59,Arcanine,,Red|Yellow|LG: Pikachu|LG: Eevee,59
60,Poliwag,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,60
61,Poliwhirl,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,61
62,Poliwrath,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,62
63,Abra,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,63
64,Kadabra,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,64
64,Kadabra,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
65,Alakazam,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,65
65,Alakazam,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
66,Machop,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,66
67,Machoke,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,67
68,Machamp,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,68
69,Bellsprout,,Blue|Yellow|LG: Eevee,69
70,Weepinbell,,Blue|Yellow|LG: Eevee,70
71,Victreebel,,Blue|Yellow|LG: Eevee,71
72,Tentacool,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,72
73,Tentacruel,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,73
74,Geodude,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,74
75,Graveler,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,75
76,Golem,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,76
77,Ponyta,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,77
78,Rapidash,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,78
79,Slowpoke,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,79
80,Slowbro,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,80
81,Magnemite,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,81
82,Magneton,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,82
83,Farfetchd,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,83
84,Doduo,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,84
84,Doduo,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
85,Dodrio,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,85
85,Dodrio,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
86,Seel,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,86
87,Dewgong,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,87
88,Grimer,,Red|Blue|Yellow|LG: Pikachu,88
89,Muk,,Red|Blue|Yellow|LG: Pikachu,89
90,Shellder,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,90
91,Cloyster,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,91
92,Gastly,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,92
93,Haunter,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,93
94,Gengar,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,94
95,Onix,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,95
96,Drowzee,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,96
97,Hypno,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,97
97,Hypno,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
98,Krabby,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,98
99,Kingler,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,99
100,Voltorb,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,100
101,Electrode,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,101
102,Exeggcute,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,102
103,Exeggutor,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,103
104,Cubone,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,104
105,Marowak,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,105
106,Hitmonlee,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,106
107,Hitmonchan,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,107
108,Lickitung,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,108
109,Koffing,,Red|Blue|LG: Eevee,109
110,Weezing,,Red|Blue|LG: Eevee,110
111,Rhyhorn,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,111
111,Rhyhorn,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
112,Rhydon,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,112
112,Rhydon,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
113,Chansey,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,113
114,Tangela,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,114
115,Kangaskhan,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,115
116,Horsea,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,116
117,Seadra,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,117
118,Goldeen,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,118
118,Goldeen,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
119,Seaking,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,119
119,Seaking,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
120,Staryu,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,120
121,Starmie,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,121
122,Mr. Mime,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,122
123,Scyther,,Red|Yellow|LG: Pikachu,123
123,Scyther,Female,Red|Yellow|LG: Pikachu,
124,Jynx,,Red|Blue|LG: Pikachu|LG: Eevee,124
125,Electabuzz,,Red|LG: Pikachu|LG: Eevee,125
126,Magmar,,Blue|LG: Pikachu|LG: Eevee,126
127,Pinsir,,Blue|Yellow|LG: Eevee,127
128,Tauros,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,128
129,Magikarp,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,129
129,Magikarp,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
130,Gyarados,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,130
130,Gyarados,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
131,Lapras,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,131
132,Ditto,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,132
133,Eevee,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,133
133,Eevee,Female,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,
134,Vaporeon,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,134
135,Jolteon,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,135
136,Flareon,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,136
137,Porygon,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,137
138,Omanyte,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,138
139,Omastar,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,139
140,Kabuto,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,140
141,Kabutops,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,141
142,Aerodactyl,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,142
143,Snorlax,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,143
144,Articuno,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,144
145,Zapdos,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,145
146,Moltres,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,146
147,Dratini,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,147
148,Dragonair,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,148
149,Dragonite,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,149
150,Mewtwo,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,150
151,Mew,,Red|Blue|Yellow|LG: Pikachu|LG: Eevee,151
1 pokedexNumber name form games regionalNumber
2 1 Bulbasaur Red|Blue|Yellow|LG: Pikachu|LG: Eevee 1
3 2 Ivysaur Red|Blue|Yellow|LG: Pikachu|LG: Eevee 2
4 3 Venusaur Red|Blue|Yellow|LG: Pikachu|LG: Eevee 3
5 3 Venusaur Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
6 4 Charmander Red|Blue|Yellow|LG: Pikachu|LG: Eevee 4
7 5 Charmeleon Red|Blue|Yellow|LG: Pikachu|LG: Eevee 5
8 6 Charizard Red|Blue|Yellow|LG: Pikachu|LG: Eevee 6
9 7 Squirtle Red|Blue|Yellow|LG: Pikachu|LG: Eevee 7
10 8 Wartortle Red|Blue|Yellow|LG: Pikachu|LG: Eevee 8
11 9 Blastoise Red|Blue|Yellow|LG: Pikachu|LG: Eevee 9
12 10 Caterpie Red|Blue|Yellow|LG: Pikachu|LG: Eevee 10
13 11 Metapod Red|Blue|Yellow|LG: Pikachu|LG: Eevee 11
14 12 Butterfree Red|Blue|Yellow|LG: Pikachu|LG: Eevee 12
15 12 Butterfree Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
16 13 Weedle Red|Blue|LG: Pikachu|LG: Eevee 13
17 14 Kakuna Red|Blue|LG: Pikachu|LG: Eevee 14
18 15 Beedrill Red|Blue|LG: Pikachu|LG: Eevee 15
19 16 Pidgey Red|Blue|Yellow|LG: Pikachu|LG: Eevee 16
20 17 Pidgeotto Red|Blue|Yellow|LG: Pikachu|LG: Eevee 17
21 18 Pidgeot Red|Blue|Yellow|LG: Pikachu|LG: Eevee 18
22 19 Rattata Red|Blue|Yellow|LG: Pikachu|LG: Eevee 19
23 19 Rattata Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
24 20 Raticate Red|Blue|Yellow|LG: Pikachu|LG: Eevee 20
25 20 Raticate Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
26 21 Spearow Red|Blue|Yellow|LG: Pikachu|LG: Eevee 21
27 22 Fearow Red|Blue|Yellow|LG: Pikachu|LG: Eevee 22
28 23 Ekans Red|Blue|LG: Eevee 23
29 24 Arbok Red|Blue|LG: Eevee 24
30 25 Pikachu Red|Blue|Yellow|LG: Pikachu|LG: Eevee 25
31 25 Pikachu Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
32 26 Raichu Red|Blue|Yellow|LG: Pikachu|LG: Eevee 26
33 26 Raichu Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
34 27 Sandshrew Blue|Yellow|LG: Pikachu 27
35 28 Sandslash Blue|Yellow|LG: Pikachu 28
36 29 Nidoran♀ Red|Blue|Yellow|LG: Pikachu|LG: Eevee 29
37 30 Nidorina Red|Blue|Yellow|LG: Pikachu|LG: Eevee 30
38 31 Nidoqueen Red|Blue|Yellow|LG: Pikachu|LG: Eevee 31
39 32 Nidoran♂ Red|Blue|Yellow|LG: Pikachu|LG: Eevee 32
40 33 Nidorino Red|Blue|Yellow|LG: Pikachu|LG: Eevee 33
41 34 Nidoking Red|Blue|Yellow|LG: Pikachu|LG: Eevee 34
42 35 Clefairy Red|Blue|Yellow|LG: Pikachu|LG: Eevee 35
43 36 Clefable Red|Blue|Yellow|LG: Pikachu|LG: Eevee 36
44 37 Vulpix Blue|Yellow|LG: Eevee 37
45 38 Ninetales Blue|Yellow|LG: Eevee 38
46 39 Jigglypuff Red|Blue|Yellow|LG: Pikachu|LG: Eevee 39
47 40 Wigglytuff Red|Blue|Yellow|LG: Pikachu|LG: Eevee 40
48 41 Zubat Red|Blue|Yellow|LG: Pikachu|LG: Eevee 41
49 41 Zubat Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
50 42 Golbat Red|Blue|Yellow|LG: Pikachu|LG: Eevee 42
51 42 Golbat Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
52 43 Oddish Red|Yellow|LG: Pikachu 43
53 44 Gloom Red|Yellow|LG: Pikachu 44
54 44 Gloom Female Red|Yellow|LG: Pikachu
55 45 Vileplume Red|Yellow|LG: Pikachu 45
56 45 Vileplume Female Red|Yellow|LG: Pikachu
57 46 Paras Red|Blue|Yellow|LG: Pikachu|LG: Eevee 46
58 47 Parasect Red|Blue|Yellow|LG: Pikachu|LG: Eevee 47
59 48 Venonat Red|Blue|Yellow|LG: Pikachu|LG: Eevee 48
60 49 Venomoth Red|Blue|Yellow|LG: Pikachu|LG: Eevee 49
61 50 Diglett Red|Blue|Yellow|LG: Pikachu|LG: Eevee 50
62 51 Dugtrio Red|Blue|Yellow|LG: Pikachu|LG: Eevee 51
63 52 Meowth Blue|LG: Eevee 52
64 53 Persian Blue|LG: Eevee 53
65 54 Psyduck Red|Blue|Yellow|LG: Pikachu|LG: Eevee 54
66 55 Golduck Red|Blue|Yellow|LG: Pikachu|LG: Eevee 55
67 56 Mankey Red|Yellow|LG: Pikachu 56
68 57 Primeape Red|Yellow|LG: Pikachu 57
69 58 Growlithe Red|Yellow|LG: Pikachu 58
70 59 Arcanine Red|Yellow|LG: Pikachu|LG: Eevee 59
71 60 Poliwag Red|Blue|Yellow|LG: Pikachu|LG: Eevee 60
72 61 Poliwhirl Red|Blue|Yellow|LG: Pikachu|LG: Eevee 61
73 62 Poliwrath Red|Blue|Yellow|LG: Pikachu|LG: Eevee 62
74 63 Abra Red|Blue|Yellow|LG: Pikachu|LG: Eevee 63
75 64 Kadabra Red|Blue|Yellow|LG: Pikachu|LG: Eevee 64
76 64 Kadabra Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
77 65 Alakazam Red|Blue|Yellow|LG: Pikachu|LG: Eevee 65
78 65 Alakazam Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
79 66 Machop Red|Blue|Yellow|LG: Pikachu|LG: Eevee 66
80 67 Machoke Red|Blue|Yellow|LG: Pikachu|LG: Eevee 67
81 68 Machamp Red|Blue|Yellow|LG: Pikachu|LG: Eevee 68
82 69 Bellsprout Blue|Yellow|LG: Eevee 69
83 70 Weepinbell Blue|Yellow|LG: Eevee 70
84 71 Victreebel Blue|Yellow|LG: Eevee 71
85 72 Tentacool Red|Blue|Yellow|LG: Pikachu|LG: Eevee 72
86 73 Tentacruel Red|Blue|Yellow|LG: Pikachu|LG: Eevee 73
87 74 Geodude Red|Blue|Yellow|LG: Pikachu|LG: Eevee 74
88 75 Graveler Red|Blue|Yellow|LG: Pikachu|LG: Eevee 75
89 76 Golem Red|Blue|Yellow|LG: Pikachu|LG: Eevee 76
90 77 Ponyta Red|Blue|Yellow|LG: Pikachu|LG: Eevee 77
91 78 Rapidash Red|Blue|Yellow|LG: Pikachu|LG: Eevee 78
92 79 Slowpoke Red|Blue|Yellow|LG: Pikachu|LG: Eevee 79
93 80 Slowbro Red|Blue|Yellow|LG: Pikachu|LG: Eevee 80
94 81 Magnemite Red|Blue|Yellow|LG: Pikachu|LG: Eevee 81
95 82 Magneton Red|Blue|Yellow|LG: Pikachu|LG: Eevee 82
96 83 Farfetch’d Red|Blue|Yellow|LG: Pikachu|LG: Eevee 83
97 84 Doduo Red|Blue|Yellow|LG: Pikachu|LG: Eevee 84
98 84 Doduo Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
99 85 Dodrio Red|Blue|Yellow|LG: Pikachu|LG: Eevee 85
100 85 Dodrio Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
101 86 Seel Red|Blue|Yellow|LG: Pikachu|LG: Eevee 86
102 87 Dewgong Red|Blue|Yellow|LG: Pikachu|LG: Eevee 87
103 88 Grimer Red|Blue|Yellow|LG: Pikachu 88
104 89 Muk Red|Blue|Yellow|LG: Pikachu 89
105 90 Shellder Red|Blue|Yellow|LG: Pikachu|LG: Eevee 90
106 91 Cloyster Red|Blue|Yellow|LG: Pikachu|LG: Eevee 91
107 92 Gastly Red|Blue|Yellow|LG: Pikachu|LG: Eevee 92
108 93 Haunter Red|Blue|Yellow|LG: Pikachu|LG: Eevee 93
109 94 Gengar Red|Blue|Yellow|LG: Pikachu|LG: Eevee 94
110 95 Onix Red|Blue|Yellow|LG: Pikachu|LG: Eevee 95
111 96 Drowzee Red|Blue|Yellow|LG: Pikachu|LG: Eevee 96
112 97 Hypno Red|Blue|Yellow|LG: Pikachu|LG: Eevee 97
113 97 Hypno Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
114 98 Krabby Red|Blue|Yellow|LG: Pikachu|LG: Eevee 98
115 99 Kingler Red|Blue|Yellow|LG: Pikachu|LG: Eevee 99
116 100 Voltorb Red|Blue|Yellow|LG: Pikachu|LG: Eevee 100
117 101 Electrode Red|Blue|Yellow|LG: Pikachu|LG: Eevee 101
118 102 Exeggcute Red|Blue|Yellow|LG: Pikachu|LG: Eevee 102
119 103 Exeggutor Red|Blue|Yellow|LG: Pikachu|LG: Eevee 103
120 104 Cubone Red|Blue|Yellow|LG: Pikachu|LG: Eevee 104
121 105 Marowak Red|Blue|Yellow|LG: Pikachu|LG: Eevee 105
122 106 Hitmonlee Red|Blue|Yellow|LG: Pikachu|LG: Eevee 106
123 107 Hitmonchan Red|Blue|Yellow|LG: Pikachu|LG: Eevee 107
124 108 Lickitung Red|Blue|Yellow|LG: Pikachu|LG: Eevee 108
125 109 Koffing Red|Blue|LG: Eevee 109
126 110 Weezing Red|Blue|LG: Eevee 110
127 111 Rhyhorn Red|Blue|Yellow|LG: Pikachu|LG: Eevee 111
128 111 Rhyhorn Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
129 112 Rhydon Red|Blue|Yellow|LG: Pikachu|LG: Eevee 112
130 112 Rhydon Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
131 113 Chansey Red|Blue|Yellow|LG: Pikachu|LG: Eevee 113
132 114 Tangela Red|Blue|Yellow|LG: Pikachu|LG: Eevee 114
133 115 Kangaskhan Red|Blue|Yellow|LG: Pikachu|LG: Eevee 115
134 116 Horsea Red|Blue|Yellow|LG: Pikachu|LG: Eevee 116
135 117 Seadra Red|Blue|Yellow|LG: Pikachu|LG: Eevee 117
136 118 Goldeen Red|Blue|Yellow|LG: Pikachu|LG: Eevee 118
137 118 Goldeen Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
138 119 Seaking Red|Blue|Yellow|LG: Pikachu|LG: Eevee 119
139 119 Seaking Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
140 120 Staryu Red|Blue|Yellow|LG: Pikachu|LG: Eevee 120
141 121 Starmie Red|Blue|Yellow|LG: Pikachu|LG: Eevee 121
142 122 Mr. Mime Red|Blue|Yellow|LG: Pikachu|LG: Eevee 122
143 123 Scyther Red|Yellow|LG: Pikachu 123
144 123 Scyther Female Red|Yellow|LG: Pikachu
145 124 Jynx Red|Blue|LG: Pikachu|LG: Eevee 124
146 125 Electabuzz Red|LG: Pikachu|LG: Eevee 125
147 126 Magmar Blue|LG: Pikachu|LG: Eevee 126
148 127 Pinsir Blue|Yellow|LG: Eevee 127
149 128 Tauros Red|Blue|Yellow|LG: Pikachu|LG: Eevee 128
150 129 Magikarp Red|Blue|Yellow|LG: Pikachu|LG: Eevee 129
151 129 Magikarp Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
152 130 Gyarados Red|Blue|Yellow|LG: Pikachu|LG: Eevee 130
153 130 Gyarados Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
154 131 Lapras Red|Blue|Yellow|LG: Pikachu|LG: Eevee 131
155 132 Ditto Red|Blue|Yellow|LG: Pikachu|LG: Eevee 132
156 133 Eevee Red|Blue|Yellow|LG: Pikachu|LG: Eevee 133
157 133 Eevee Female Red|Blue|Yellow|LG: Pikachu|LG: Eevee
158 134 Vaporeon Red|Blue|Yellow|LG: Pikachu|LG: Eevee 134
159 135 Jolteon Red|Blue|Yellow|LG: Pikachu|LG: Eevee 135
160 136 Flareon Red|Blue|Yellow|LG: Pikachu|LG: Eevee 136
161 137 Porygon Red|Blue|Yellow|LG: Pikachu|LG: Eevee 137
162 138 Omanyte Red|Blue|Yellow|LG: Pikachu|LG: Eevee 138
163 139 Omastar Red|Blue|Yellow|LG: Pikachu|LG: Eevee 139
164 140 Kabuto Red|Blue|Yellow|LG: Pikachu|LG: Eevee 140
165 141 Kabutops Red|Blue|Yellow|LG: Pikachu|LG: Eevee 141
166 142 Aerodactyl Red|Blue|Yellow|LG: Pikachu|LG: Eevee 142
167 143 Snorlax Red|Blue|Yellow|LG: Pikachu|LG: Eevee 143
168 144 Articuno Red|Blue|Yellow|LG: Pikachu|LG: Eevee 144
169 145 Zapdos Red|Blue|Yellow|LG: Pikachu|LG: Eevee 145
170 146 Moltres Red|Blue|Yellow|LG: Pikachu|LG: Eevee 146
171 147 Dratini Red|Blue|Yellow|LG: Pikachu|LG: Eevee 147
172 148 Dragonair Red|Blue|Yellow|LG: Pikachu|LG: Eevee 148
173 149 Dragonite Red|Blue|Yellow|LG: Pikachu|LG: Eevee 149
174 150 Mewtwo Red|Blue|Yellow|LG: Pikachu|LG: Eevee 150
175 151 Mew Red|Blue|Yellow|LG: Pikachu|LG: Eevee 151
+180
View File
@@ -0,0 +1,180 @@
#!/usr/bin/env node
/**
* Generates SQL migration from CSV files
* Usage: node csv-to-migration.js <Region>
* Example: node csv-to-migration.js Kanto
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/**
* Parse CSV file into array of objects
*/
function parseCSV(filePath) {
const content = fs.readFileSync(filePath, 'utf-8');
const lines = content.split('\n').filter(line => line.trim());
const headers = lines[0].split(',');
return lines.slice(1).map(line => {
const values = parseCSVLine(line);
const obj = {};
headers.forEach((header, i) => {
obj[header] = values[i] || null;
});
return obj;
});
}
/**
* Parse a single CSV line, handling quoted values
*/
function parseCSVLine(line) {
const values = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i++) {
const char = line[i];
if (char === '"') {
inQuotes = !inQuotes;
} else if (char === ',' && !inQuotes) {
values.push(current);
current = '';
} else {
current += char;
}
}
values.push(current);
return values;
}
/**
* Generate migration SQL from CSV data
*/
function generateMigration(region) {
console.log(`\nGenerating migration for ${region}...`);
// Determine generation number from region
const regionToGen = {
'Kanto': 1, 'Johto': 2, 'Hoenn': 3, 'Sinnoh': 4,
'Unova': 5, 'Kalos': 6, 'Alola': 7, 'Galar': 8,
'Hisui': 8, 'Paldea': 9
};
const gen = regionToGen[region] || 1;
// 1. Load CSV files
const pokemonPath = path.join(__dirname, '..', 'data', 'pokemon', `gen${gen}-${region.toLowerCase()}.csv`);
const gamesPath = path.join(__dirname, '..', 'data', 'pokemon', 'games.csv');
if (!fs.existsSync(pokemonPath)) {
console.error(`Error: Pokemon CSV not found at ${pokemonPath}`);
process.exit(1);
}
const pokemon = parseCSV(pokemonPath);
const games = parseCSV(gamesPath);
// 2. Filter for this region
const regionGames = games.filter(g => g.region === region);
if (regionGames.length === 0) {
console.error(`Error: No games found for region ${region} in games.csv`);
process.exit(1);
}
// 3. Generate SQL
let sql = `-- Seed ${region} region Pokémon (Gen ${gen})\n`;
sql += `-- Auto-generated from CSV files\n\n`;
// Region-game mappings
sql += `-- Insert ${region} region-game mappings\n`;
sql += `INSERT INTO region_game_mappings (region, game) VALUES\n`;
sql += regionGames.map(g => ` ('${region}', '${g.displayName}')`).join(',\n');
sql += `\nON CONFLICT (region, game) DO NOTHING;\n\n`;
// Pokemon entries (without regional dex number)
sql += `-- Insert ${region} Pokémon entries\n`;
sql += `INSERT INTO pokedex_entries (\n`;
sql += ` "pokedexNumber",\n`;
sql += ` pokemon,\n`;
sql += ` form,\n`;
sql += ` "canGigantamax",\n`;
sql += ` "regionToCatchIn",\n`;
sql += ` "gamesToCatchIn"\n`;
sql += `) VALUES\n`;
const rows = pokemon.map(p => {
const form = p.form ? `'${p.form}'` : 'NULL';
const gamesList = p.games.split('|');
const gamesArray = `ARRAY[${gamesList.map(g => `'${g}'`).join(', ')}]`;
return `(${p.pokedexNumber}, '${p.name}', ${form}, false, '${region}', ${gamesArray})`;
});
sql += rows.join(',\n');
sql += '\nON CONFLICT ON CONSTRAINT unique_pokemon_form DO NOTHING;\n\n';
// Regional dex numbers (separate table)
sql += `-- Insert ${region} regional dex numbers\n`;
sql += `INSERT INTO regional_dex_numbers (\n`;
sql += ` pokedex_entry_id,\n`;
sql += ` region,\n`;
sql += ` dex_number\n`;
sql += `) VALUES\n`;
const dexRows = pokemon
.filter(p => p.regionalNumber) // Only entries with regional dex numbers
.map(p => {
const formCondition = p.form
? `form = '${p.form}'`
: `form IS NULL`;
return ` ((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = ${p.pokedexNumber} AND ${formCondition}), '${region}', ${p.regionalNumber})`;
});
if (dexRows.length > 0) {
sql += dexRows.join(',\n');
sql += ';\n\n';
} else {
sql += ' -- No regional dex numbers for this region\n\n';
}
// Add metadata
sql += `-- Add metadata\n`;
sql += `INSERT INTO metadata (key, value) VALUES\n`;
sql += ` ('${region.toLowerCase()}_seeded', 'true'),\n`;
sql += ` ('${region.toLowerCase()}_seed_date', NOW()::TEXT),\n`;
sql += ` ('${region.toLowerCase()}_pokemon_count', '${pokemon.filter(p => !p.form).length}');\n`;
// 4. Write file
const timestamp = new Date().toISOString().replace(/[-:.]/g, '').slice(0, 14);
const filename = `${timestamp}_seed_${region.toLowerCase()}.sql`;
const outputPath = path.join(__dirname, '..', 'supabase', 'migrations', filename);
fs.writeFileSync(outputPath, sql);
console.log(`✓ Generated ${filename}`);
console.log(` - ${pokemon.length} Pokemon entries`);
console.log(` - ${dexRows.length} regional dex numbers`);
console.log(` - ${regionGames.length} games\n`);
return filename;
}
// Run
const region = process.argv[2];
if (!region) {
console.error('Usage: node csv-to-migration.js <Region>');
console.error('Example: node csv-to-migration.js Kanto');
process.exit(1);
}
generateMigration(region);
+87
View File
@@ -0,0 +1,87 @@
#!/usr/bin/env node
/**
* Converts Kanto seed SQL migration to CSV format
* Parses 20260104000001_seed_kanto.sql and generates:
* - data/pokemon/gen1-kanto.csv
* - data/pokemon/games.csv
*/
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
// Read the SQL migration file
const sqlPath = path.join(__dirname, '..', 'supabase', 'migrations', '20260104000001_seed_kanto.sql');
const sqlContent = fs.readFileSync(sqlPath, 'utf-8');
// Extract games from region_game_mappings section
const gameMatches = [...sqlContent.matchAll(/\('Kanto', '([^']+)'\)/g)];
const games = gameMatches.map(m => m[1]);
console.log(`Found ${games.length} Kanto games:`, games);
// Extract Pokemon entries from INSERT statement
// Match pattern: (number, 'name', form, boolean, 'region', ARRAY[games], ...)
const valuePattern = /\((\d+),\s*'([^']+)',\s*(NULL|'[^']+'),\s*(true|false),\s*'[^']+',\s*ARRAY\[([^\]]+)\][^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,[^,]*,\s*(NULL|\d+)\)/g;
const pokemon = [];
let match;
while ((match = valuePattern.exec(sqlContent)) !== null) {
const [_, pokedexNumber, name, formRaw, canGigantamax, gamesRaw, regionalNumberRaw] = match;
// Parse form (NULL or 'Female')
const form = formRaw === 'NULL' ? '' : formRaw.replace(/'/g, '');
// Parse games array - extract game names from ARRAY['Red', 'Blue', ...]
const gamesList = gamesRaw.match(/'([^']+)'/g).map(g => g.replace(/'/g, ''));
const gamesStr = gamesList.join('|');
// Parse regional number
const regionalNumber = regionalNumberRaw === 'NULL' ? '' : regionalNumberRaw;
pokemon.push({
pokedexNumber,
name,
form,
games: gamesStr,
regionalNumber
});
}
console.log(`Extracted ${pokemon.length} Pokemon entries`);
// Generate gen1-kanto.csv
const kantoCSV = [
'pokedexNumber,name,form,games,regionalNumber',
...pokemon.map(p => {
const form = p.form.includes(',') ? `"${p.form}"` : p.form;
const games = p.games.includes(',') ? `"${p.games}"` : p.games;
return `${p.pokedexNumber},${p.name},${form},${games},${p.regionalNumber}`;
})
].join('\n');
const kantoPath = path.join(__dirname, '..', 'data', 'pokemon', 'gen1-kanto.csv');
fs.writeFileSync(kantoPath, kantoCSV);
console.log(`✓ Created ${kantoPath}`);
// Generate games.csv
const gamesCSV = [
'id,displayName,region,generation',
...games.map((game, idx) => {
const id = game.toLowerCase().replace(/[^a-z0-9]/g, '-');
const generation = game.startsWith('LG:') ? 7 : 1;
return `${id},${game},Kanto,${generation}`;
})
].join('\n');
const gamesPath = path.join(__dirname, '..', 'data', 'pokemon', 'games.csv');
fs.writeFileSync(gamesPath, gamesCSV);
console.log(`✓ Created ${gamesPath}`);
console.log('\n✅ Conversion complete!');
console.log(` gen1-kanto.csv: ${pokemon.length} entries`);
console.log(` games.csv: ${games.length} games`);
@@ -60,17 +60,6 @@
{/if} {/if}
<div class="bg-white text-black rounded-lg p-4"> <div class="bg-white text-black rounded-lg p-4">
{#if showForms}
<p><strong>Box:</strong> {pokedexEntry.boxPlacementForms.box}</p>
<p><strong>Row:</strong> {pokedexEntry.boxPlacementForms.row}</p>
<p><strong>Column:</strong> {pokedexEntry.boxPlacementForms.column}</p>
<p><strong>Can Gigantamax:</strong> {pokedexEntry.canGigantamax ? 'Yes' : 'No'}</p>
{:else}
<p><strong>Box:</strong> {pokedexEntry.boxPlacement.box}</p>
<p><strong>Row:</strong> {pokedexEntry.boxPlacement.row}</p>
<p><strong>Column:</strong> {pokedexEntry.boxPlacement.column}</p>
{/if}
{#if pokedexEntry.evolutionInformation} {#if pokedexEntry.evolutionInformation}
<p><strong>How to evolve: </strong>{pokedexEntry.evolutionInformation}</p> <p><strong>How to evolve: </strong>{pokedexEntry.evolutionInformation}</p>
{:else} {:else}
@@ -7,12 +7,10 @@
export let currentPage = 1; export let currentPage = 1;
export let itemsPerPage = 20; export let itemsPerPage = 20;
export let totalPages = 0; export let totalPages = 0;
export let showForms = true;
export let showOrigins = true; export let showOrigins = true;
export let showShiny = false; export let showShiny = false;
export let catchRegion = ''; export let catchRegion = '';
export let catchGame = ''; export let catchGame = '';
export let toggleForms = () => {};
export let toggleOrigins = () => {}; export let toggleOrigins = () => {};
export let toggleShiny = () => {}; export let toggleShiny = () => {};
export let getData = () => {}; export let getData = () => {};
@@ -57,11 +55,6 @@
</ul> </ul>
<h2 class="text-2xl font-semibold mb-4">Filters</h2> <h2 class="text-2xl font-semibold mb-4">Filters</h2>
<ul> <ul>
<li class="mb-2">
<button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleForms}>
Toggle Forms (Currently {showForms ? 'On' : 'Off'})
</button>
</li>
<li class="mb-2"> <li class="mb-2">
<button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleOrigins}> <button class="block p-2 hover:bg-gray-700 rounded" on:click={toggleOrigins}>
Toggle Origins (Currently {showOrigins ? 'On' : 'Off'}) Toggle Origins (Currently {showOrigins ? 'On' : 'Off'})
@@ -9,7 +9,6 @@
export let showForms = true; export let showForms = true;
export let combinedData: CombinedData[] | null; export let combinedData: CombinedData[] | null;
export let boxNumbers: number[] = []; export let boxNumbers: number[] = [];
export let currentPlacement = 'boxPlacementForms';
export let creatingRecords = false; export let creatingRecords = false;
export let totalRecordsCreated = 0; export let totalRecordsCreated = 0;
export let failedToLoad = false; export let failedToLoad = false;
-6
View File
@@ -43,12 +43,6 @@ export interface PokedexEntryDB {
regionToEvolveIn: string | null; regionToEvolveIn: string | null;
evolutionInformation: string | null; evolutionInformation: string | null;
catchInformation: string[] | null; catchInformation: string[] | null;
boxPlacementFormsBox: number | null;
boxPlacementFormsRow: number | null;
boxPlacementFormsColumn: number | null;
boxPlacementBox: number | null;
boxPlacementRow: number | null;
boxPlacementColumn: number | null;
// Regional dex numbers - snake_case to match database // Regional dex numbers - snake_case to match database
kanto_dex_number: number | null; kanto_dex_number: number | null;
johto_dex_number: number | null; johto_dex_number: number | null;
+16 -45
View File
@@ -3,6 +3,7 @@ import { type CatchRecord, type CatchRecordDB } from '$lib/models/CatchRecord';
import { type CombinedData } from '$lib/models/CombinedData'; import { type CombinedData } from '$lib/models/CombinedData';
import type { SupabaseClient } from '@supabase/supabase-js'; import type { SupabaseClient } from '@supabase/supabase-js';
import { getRegionalDexColumnName } from '$lib/utils/regionalDexMapping'; import { getRegionalDexColumnName } from '$lib/utils/regionalDexMapping';
import { calculateBoxPlacement } from '$lib/utils/boxPlacement';
class CombinedDataRepository { class CombinedDataRepository {
constructor( constructor(
@@ -24,16 +25,9 @@ class CombinedDataRepository {
regionToEvolveIn: entry.regionToEvolveIn || '', regionToEvolveIn: entry.regionToEvolveIn || '',
evolutionInformation: entry.evolutionInformation || '', evolutionInformation: entry.evolutionInformation || '',
catchInformation: entry.catchInformation || [], catchInformation: entry.catchInformation || [],
boxPlacementForms: { // Box placement will be calculated dynamically after sorting
box: entry.boxPlacementFormsBox || 0, boxPlacementForms: { box: 0, row: 0, column: 0 },
row: entry.boxPlacementFormsRow || 0, boxPlacement: { box: 0, row: 0, column: 0 },
column: entry.boxPlacementFormsColumn || 0
},
boxPlacement: {
box: entry.boxPlacementBox || 0,
row: entry.boxPlacementRow || 0,
column: entry.boxPlacementColumn || 0
},
kantoDexNumber: entry.kanto_dex_number ?? undefined, kantoDexNumber: entry.kanto_dex_number ?? undefined,
johtoDexNumber: entry.johto_dex_number ?? undefined, johtoDexNumber: entry.johto_dex_number ?? undefined,
hoennDexNumber: entry.hoenn_dex_number ?? undefined, hoennDexNumber: entry.hoenn_dex_number ?? undefined,
@@ -77,7 +71,8 @@ class CombinedDataRepository {
// Apply filters // Apply filters
if (!enableForms) { if (!enableForms) {
query = query.not('boxPlacementBox', 'is', null); // Filter to only base forms (form is NULL)
query = query.is('form', null);
} }
if (region) { if (region) {
@@ -101,18 +96,8 @@ class CombinedDataRepository {
query = query.order('pokedexNumber', { ascending: true }); query = query.order('pokedexNumber', { ascending: true });
} }
} else { } else {
// No game filter - use pre-calculated box placement (national dex order) // No game filter - order by national dex number
if (enableForms) { query = query.order('pokedexNumber', { ascending: true });
query = query
.order('boxPlacementFormsBox', { ascending: true })
.order('boxPlacementFormsRow', { ascending: true })
.order('boxPlacementFormsColumn', { ascending: true });
} else {
query = query
.order('boxPlacementBox', { ascending: true })
.order('boxPlacementRow', { ascending: true })
.order('boxPlacementColumn', { ascending: true });
}
} }
const { data: entries, error: entriesError } = await query; const { data: entries, error: entriesError } = await query;
@@ -158,12 +143,9 @@ class CombinedDataRepository {
}; };
}); });
// Recalculate box placement if using regional dex ordering // Always recalculate box placement based on current sort order
if (game && getRegionalDexColumnName(game)) {
return this.recalculateBoxPlacement(combinedData, enableForms); return this.recalculateBoxPlacement(combinedData, enableForms);
} }
return combinedData;
}
async findCombinedData( async findCombinedData(
userId: string, userId: string,
@@ -180,7 +162,8 @@ class CombinedDataRepository {
// Apply filters // Apply filters
if (!enableForms) { if (!enableForms) {
query = query.not('boxPlacementBox', 'is', null); // Filter to only base forms (form is NULL)
query = query.is('form', null);
} }
if (region) { if (region) {
@@ -204,18 +187,8 @@ class CombinedDataRepository {
query = query.order('pokedexNumber', { ascending: true }); query = query.order('pokedexNumber', { ascending: true });
} }
} else { } else {
// No game filter - use pre-calculated box placement (national dex order) // No game filter - order by national dex number
if (enableForms) { query = query.order('pokedexNumber', { ascending: true });
query = query
.order('boxPlacementFormsBox', { ascending: true })
.order('boxPlacementFormsRow', { ascending: true })
.order('boxPlacementFormsColumn', { ascending: true });
} else {
query = query
.order('boxPlacementBox', { ascending: true })
.order('boxPlacementRow', { ascending: true })
.order('boxPlacementColumn', { ascending: true });
}
} }
const { data: entries, error: entriesError } = await query; const { data: entries, error: entriesError } = await query;
@@ -261,12 +234,9 @@ class CombinedDataRepository {
}; };
}); });
// Recalculate box placement if using regional dex ordering // Always recalculate box placement based on current sort order
if (game && getRegionalDexColumnName(game)) {
return this.recalculateBoxPlacement(combinedData, enableForms); return this.recalculateBoxPlacement(combinedData, enableForms);
} }
return combinedData;
}
async countCombinedData( async countCombinedData(
enableForms: boolean, enableForms: boolean,
@@ -277,7 +247,8 @@ class CombinedDataRepository {
// Apply same filters as in findCombinedData // Apply same filters as in findCombinedData
if (!enableForms) { if (!enableForms) {
query = query.not('boxPlacementBox', 'is', null); // Filter to only base forms (form is NULL)
query = query.is('form', null);
} }
if (region) { if (region) {
+5 -32
View File
@@ -17,16 +17,9 @@ class PokedexEntryRepository {
regionToEvolveIn: entry.regionToEvolveIn || '', regionToEvolveIn: entry.regionToEvolveIn || '',
evolutionInformation: entry.evolutionInformation || '', evolutionInformation: entry.evolutionInformation || '',
catchInformation: entry.catchInformation || [], catchInformation: entry.catchInformation || [],
boxPlacementForms: { // Box placement is calculated dynamically - not stored in database
box: entry.boxPlacementFormsBox || 0, boxPlacementForms: { box: 0, row: 0, column: 0 },
row: entry.boxPlacementFormsRow || 0, boxPlacement: { box: 0, row: 0, column: 0 },
column: entry.boxPlacementFormsColumn || 0
},
boxPlacement: {
box: entry.boxPlacementBox || 0,
row: entry.boxPlacementRow || 0,
column: entry.boxPlacementColumn || 0
},
kantoDexNumber: entry.kanto_dex_number ?? undefined, kantoDexNumber: entry.kanto_dex_number ?? undefined,
johtoDexNumber: entry.johto_dex_number ?? undefined, johtoDexNumber: entry.johto_dex_number ?? undefined,
hoennDexNumber: entry.hoenn_dex_number ?? undefined, hoennDexNumber: entry.hoenn_dex_number ?? undefined,
@@ -80,17 +73,7 @@ class PokedexEntryRepository {
if (data.evolutionInformation !== undefined) if (data.evolutionInformation !== undefined)
dbData.evolutionInformation = data.evolutionInformation; dbData.evolutionInformation = data.evolutionInformation;
if (data.catchInformation !== undefined) dbData.catchInformation = data.catchInformation; if (data.catchInformation !== undefined) dbData.catchInformation = data.catchInformation;
if (data.boxPlacementForms?.box !== undefined) // Box placement is calculated dynamically - not stored in database
dbData.boxPlacementFormsBox = data.boxPlacementForms.box;
if (data.boxPlacementForms?.row !== undefined)
dbData.boxPlacementFormsRow = data.boxPlacementForms.row;
if (data.boxPlacementForms?.column !== undefined)
dbData.boxPlacementFormsColumn = data.boxPlacementForms.column;
if (data.boxPlacement?.box !== undefined) dbData.boxPlacementBox = data.boxPlacement.box;
if (data.boxPlacement?.row !== undefined) dbData.boxPlacementRow = data.boxPlacement.row;
if (data.boxPlacement?.column !== undefined)
dbData.boxPlacementColumn = data.boxPlacement.column;
if (data.regionalDexNumbers !== undefined) dbData.regionalDexNumbers = data.regionalDexNumbers;
const { data: result, error } = await this.supabase const { data: result, error } = await this.supabase
.from('pokedex_entries') .from('pokedex_entries')
@@ -115,17 +98,7 @@ class PokedexEntryRepository {
if (data.evolutionInformation !== undefined) if (data.evolutionInformation !== undefined)
dbData.evolutionInformation = data.evolutionInformation; dbData.evolutionInformation = data.evolutionInformation;
if (data.catchInformation !== undefined) dbData.catchInformation = data.catchInformation; if (data.catchInformation !== undefined) dbData.catchInformation = data.catchInformation;
if (data.boxPlacementForms?.box !== undefined) // Box placement is calculated dynamically - not stored in database
dbData.boxPlacementFormsBox = data.boxPlacementForms.box;
if (data.boxPlacementForms?.row !== undefined)
dbData.boxPlacementFormsRow = data.boxPlacementForms.row;
if (data.boxPlacementForms?.column !== undefined)
dbData.boxPlacementFormsColumn = data.boxPlacementForms.column;
if (data.boxPlacement?.box !== undefined) dbData.boxPlacementBox = data.boxPlacement.box;
if (data.boxPlacement?.row !== undefined) dbData.boxPlacementRow = data.boxPlacement.row;
if (data.boxPlacement?.column !== undefined)
dbData.boxPlacementColumn = data.boxPlacement.column;
if (data.regionalDexNumbers !== undefined) dbData.regionalDexNumbers = data.regionalDexNumbers;
const { data: result, error } = await this.supabase const { data: result, error } = await this.supabase
.from('pokedex_entries') .from('pokedex_entries')
+41
View File
@@ -0,0 +1,41 @@
/**
* Calculate box placement for Pokémon based on their position in a sorted list
*
* Box layout: 6 columns × 5 rows = 30 Pokémon per box
*
* @param index - Zero-based index in the sorted list
* @returns Box placement with box number, row, and column (1-indexed)
*/
export function calculateBoxPlacement(index: number): {
box: number;
row: number;
column: number;
} {
const POKEMON_PER_BOX = 30;
const COLUMNS_PER_BOX = 6;
const ROWS_PER_BOX = 5;
// Calculate which box this Pokémon belongs to (1-indexed)
const box = Math.floor(index / POKEMON_PER_BOX) + 1;
// Calculate position within the box (0-indexed)
const positionInBox = index % POKEMON_PER_BOX;
// Calculate row and column (1-indexed)
const row = Math.floor(positionInBox / COLUMNS_PER_BOX) + 1;
const column = (positionInBox % COLUMNS_PER_BOX) + 1;
return { box, row, column };
}
/**
* Calculate all unique box numbers needed for a list of Pokémon
*
* @param count - Total number of Pokémon
* @returns Array of box numbers (1-indexed)
*/
export function calculateBoxNumbers(count: number): number[] {
const POKEMON_PER_BOX = 30;
const totalBoxes = Math.ceil(count / POKEMON_PER_BOX);
return Array.from({ length: totalBoxes }, (_, i) => i + 1);
}
+5 -21
View File
@@ -27,11 +27,9 @@
let catchGame = ''; let catchGame = '';
let localUser: User | null; let localUser: User | null;
let showOrigins = true; let showOrigins = true;
let showForms = true;
let showShiny = false; let showShiny = false;
let drawerOpen = false; let drawerOpen = false;
let viewAsBoxes = false; let viewAsBoxes = false;
let currentPlacement = 'boxPlacementForms';
let boxNumbers: number[] = []; let boxNumbers: number[] = [];
const unsubscribe = user.subscribe((value) => { const unsubscribe = user.subscribe((value) => {
@@ -43,17 +41,8 @@
showOrigins = !showOrigins; showOrigins = !showOrigins;
} }
async function toggleForms() {
showForms = !showForms;
await getData();
}
async function toggleShiny() { async function toggleShiny() {
showShiny = !showShiny; showShiny = !showShiny;
if (showShiny) {
showForms = false;
}
await getData(); await getData();
} }
@@ -67,7 +56,7 @@
combinedData = null; combinedData = null;
} }
// Use new pokédex-scoped endpoint // Use new pokédex-scoped endpoint
let endpoint = `/api/pokedexes/${pokedexId}/combined-data?page=${currentPage}&limit=${viewAsBoxes ? 9999 : itemsPerPage}&enableForms=${showForms}&region=${catchRegion}&game=${catchGame}`; let endpoint = `/api/pokedexes/${pokedexId}/combined-data?page=${currentPage}&limit=${viewAsBoxes ? 9999 : itemsPerPage}&enableForms=${pokedex.isFormDex}&region=${catchRegion}&game=${catchGame}`;
const response = await fetch(endpoint); const response = await fetch(endpoint);
const fetchedData = await response.json(); const fetchedData = await response.json();
@@ -81,7 +70,7 @@
boxNumbers = [ boxNumbers = [
...new Set( ...new Set(
combinedData.map(({ pokedexEntry }) => combinedData.map(({ pokedexEntry }) =>
showForms ? pokedexEntry.boxPlacementForms.box : pokedexEntry.boxPlacement.box pokedex.isFormDex ? pokedexEntry.boxPlacementForms.box : pokedexEntry.boxPlacement.box
) )
) )
].filter(Boolean); ].filter(Boolean);
@@ -129,7 +118,7 @@
) { ) {
let catchRecordsToUpdate = combinedData let catchRecordsToUpdate = combinedData
.filter(({ pokedexEntry }) => .filter(({ pokedexEntry }) =>
(showForms ? pokedexEntry.boxPlacementForms.box : pokedexEntry.boxPlacement.box) === (pokedex.isFormDex ? pokedexEntry.boxPlacementForms.box : pokedexEntry.boxPlacement.box) ===
boxNumber boxNumber
) )
.map(({ pokedexEntry, catchRecord }) => { .map(({ pokedexEntry, catchRecord }) => {
@@ -262,8 +251,6 @@
currentPage, itemsPerPage, getData(); currentPage, itemsPerPage, getData();
} }
} }
$: currentPlacement = showForms ? 'boxPlacementForms' : 'boxPlacement';
</script> </script>
<svelte:head> <svelte:head>
@@ -286,10 +273,9 @@
{#if viewAsBoxes} {#if viewAsBoxes}
<PokedexViewBoxes <PokedexViewBoxes
bind:showShiny bind:showShiny
bind:showForms showForms={pokedex.isFormDex}
bind:combinedData bind:combinedData
bind:boxNumbers bind:boxNumbers
bind:currentPlacement
bind:creatingRecords bind:creatingRecords
bind:failedToLoad bind:failedToLoad
{markBoxAsNotCaught} {markBoxAsNotCaught}
@@ -301,7 +287,7 @@
{:else} {:else}
<PokedexViewList <PokedexViewList
bind:showOrigins bind:showOrigins
bind:showForms showForms={pokedex.isFormDex}
bind:showShiny bind:showShiny
bind:combinedData bind:combinedData
bind:creatingRecords bind:creatingRecords
@@ -322,13 +308,11 @@
bind:currentPage bind:currentPage
bind:itemsPerPage bind:itemsPerPage
bind:totalPages bind:totalPages
bind:showForms
bind:showOrigins bind:showOrigins
bind:showShiny bind:showShiny
bind:catchRegion bind:catchRegion
bind:catchGame bind:catchGame
{getData} {getData}
{toggleForms}
{toggleOrigins} {toggleOrigins}
{toggleShiny} {toggleShiny}
{toggleViewAsBoxes} {toggleViewAsBoxes}
@@ -10,16 +10,6 @@ CREATE TABLE pokedex_entries (
"evolutionInformation" TEXT, "evolutionInformation" TEXT,
"catchInformation" TEXT[], "catchInformation" TEXT[],
-- Box placement for forms view
"boxPlacementFormsBox" INTEGER,
"boxPlacementFormsRow" INTEGER,
"boxPlacementFormsColumn" INTEGER,
-- Box placement for no-forms view
"boxPlacementBox" INTEGER,
"boxPlacementRow" INTEGER,
"boxPlacementColumn" INTEGER,
"createdAt" TIMESTAMPTZ DEFAULT NOW(), "createdAt" TIMESTAMPTZ DEFAULT NOW(),
"updatedAt" TIMESTAMPTZ DEFAULT NOW() "updatedAt" TIMESTAMPTZ DEFAULT NOW()
); );
@@ -65,8 +55,6 @@ CREATE TABLE metadata (
-- Create indexes for better performance -- Create indexes for better performance
CREATE INDEX idx_pokedex_entries_pokedex_number ON pokedex_entries("pokedexNumber"); CREATE INDEX idx_pokedex_entries_pokedex_number ON pokedex_entries("pokedexNumber");
CREATE INDEX idx_pokedex_entries_pokemon ON pokedex_entries(pokemon); CREATE INDEX idx_pokedex_entries_pokemon ON pokedex_entries(pokemon);
CREATE INDEX idx_pokedex_entries_box_placement_forms ON pokedex_entries("boxPlacementFormsBox", "boxPlacementFormsRow", "boxPlacementFormsColumn");
CREATE INDEX idx_pokedex_entries_box_placement ON pokedex_entries("boxPlacementBox", "boxPlacementRow", "boxPlacementColumn");
CREATE INDEX idx_catch_records_user_id ON catch_records("userId"); CREATE INDEX idx_catch_records_user_id ON catch_records("userId");
CREATE INDEX idx_catch_records_pokedex_entry_id ON catch_records("pokedexEntryId"); CREATE INDEX idx_catch_records_pokedex_entry_id ON catch_records("pokedexEntryId");
File diff suppressed because it is too large Load Diff
@@ -1,25 +0,0 @@
-- Add regional dex number columns to pokedex_entries table
-- Each region gets its own integer column for better query performance
ALTER TABLE pokedex_entries
ADD COLUMN IF NOT EXISTS kanto_dex_number INT,
ADD COLUMN IF NOT EXISTS johto_dex_number INT,
ADD COLUMN IF NOT EXISTS hoenn_dex_number INT,
ADD COLUMN IF NOT EXISTS sinnoh_dex_number INT,
ADD COLUMN IF NOT EXISTS unova_bw_dex_number INT,
ADD COLUMN IF NOT EXISTS unova_b2w2_dex_number INT,
ADD COLUMN IF NOT EXISTS kalos_central_dex_number INT,
ADD COLUMN IF NOT EXISTS kalos_coastal_dex_number INT,
ADD COLUMN IF NOT EXISTS kalos_mountain_dex_number INT,
ADD COLUMN IF NOT EXISTS alola_sm_dex_number INT,
ADD COLUMN IF NOT EXISTS alola_usum_dex_number INT,
ADD COLUMN IF NOT EXISTS galar_dex_number INT,
ADD COLUMN IF NOT EXISTS galar_isle_of_armor_dex_number INT,
ADD COLUMN IF NOT EXISTS galar_crown_tundra_dex_number INT,
ADD COLUMN IF NOT EXISTS hisui_dex_number INT,
ADD COLUMN IF NOT EXISTS paldea_dex_number INT;
-- Create indexes for better query performance when filtering/ordering by regional dex
-- Only indexing Kanto and Johto for now (other regions to be added incrementally)
CREATE INDEX IF NOT EXISTS idx_pokedex_entries_kanto_dex ON pokedex_entries(kanto_dex_number) WHERE kanto_dex_number IS NOT NULL;
CREATE INDEX IF NOT EXISTS idx_pokedex_entries_johto_dex ON pokedex_entries(johto_dex_number) WHERE johto_dex_number IS NOT NULL;
@@ -0,0 +1,21 @@
-- Create regional_dex_numbers table for generic regional dex number storage
-- This table replaces region-specific columns (kanto_dex_number, johto_dex_number, etc.)
-- and allows adding new regions without schema changes
CREATE TABLE IF NOT EXISTS regional_dex_numbers (
id SERIAL PRIMARY KEY,
pokedex_entry_id INT NOT NULL REFERENCES pokedex_entries(id) ON DELETE CASCADE,
region TEXT NOT NULL,
dex_number INT NOT NULL,
UNIQUE(pokedex_entry_id, region)
);
-- Create indexes for better query performance
CREATE INDEX IF NOT EXISTS idx_regional_dex_numbers_region ON regional_dex_numbers(region, dex_number);
CREATE INDEX IF NOT EXISTS idx_regional_dex_numbers_entry ON regional_dex_numbers(pokedex_entry_id);
-- RLS policies (read-only reference data, same pattern as pokedex_entries)
ALTER TABLE regional_dex_numbers ENABLE ROW LEVEL SECURITY;
CREATE POLICY "Allow public read access" ON regional_dex_numbers
FOR SELECT USING (true);
@@ -0,0 +1,360 @@
-- Seed Kanto region Pokémon (Gen 1)
-- Auto-generated from CSV files
-- Insert Kanto region-game mappings
INSERT INTO region_game_mappings (region, game) VALUES
('Kanto', 'Red'),
('Kanto', 'Blue'),
('Kanto', 'Yellow'),
('Kanto', 'LG: Pikachu'),
('Kanto', 'LG: Eevee')
ON CONFLICT (region, game) DO NOTHING;
-- Insert Kanto Pokémon entries
INSERT INTO pokedex_entries (
"pokedexNumber",
pokemon,
form,
"canGigantamax",
"regionToCatchIn",
"gamesToCatchIn"
) VALUES
(1, 'Bulbasaur', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(2, 'Ivysaur', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(3, 'Venusaur', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(3, 'Venusaur', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(4, 'Charmander', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(5, 'Charmeleon', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(6, 'Charizard', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(7, 'Squirtle', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(8, 'Wartortle', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(9, 'Blastoise', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(10, 'Caterpie', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(11, 'Metapod', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(12, 'Butterfree', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(12, 'Butterfree', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(13, 'Weedle', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Pikachu', 'LG: Eevee']),
(14, 'Kakuna', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Pikachu', 'LG: Eevee']),
(15, 'Beedrill', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Pikachu', 'LG: Eevee']),
(16, 'Pidgey', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(17, 'Pidgeotto', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(18, 'Pidgeot', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(19, 'Rattata', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(19, 'Rattata', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(20, 'Raticate', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(20, 'Raticate', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(21, 'Spearow', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(22, 'Fearow', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(23, 'Ekans', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Eevee']),
(24, 'Arbok', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Eevee']),
(25, 'Pikachu', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(25, 'Pikachu', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(26, 'Raichu', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(26, 'Raichu', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(27, 'Sandshrew', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Pikachu']),
(28, 'Sandslash', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Pikachu']),
(29, 'Nidoran♀', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(30, 'Nidorina', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(31, 'Nidoqueen', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(32, 'Nidoran♂', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(33, 'Nidorino', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(34, 'Nidoking', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(35, 'Clefairy', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(36, 'Clefable', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(37, 'Vulpix', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Eevee']),
(38, 'Ninetales', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Eevee']),
(39, 'Jigglypuff', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(40, 'Wigglytuff', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(41, 'Zubat', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(41, 'Zubat', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(42, 'Golbat', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(42, 'Golbat', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(43, 'Oddish', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(44, 'Gloom', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(44, 'Gloom', 'Female', false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(45, 'Vileplume', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(45, 'Vileplume', 'Female', false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(46, 'Paras', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(47, 'Parasect', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(48, 'Venonat', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(49, 'Venomoth', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(50, 'Diglett', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(51, 'Dugtrio', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(52, 'Meowth', NULL, false, 'Kanto', ARRAY['Blue', 'LG: Eevee']),
(53, 'Persian', NULL, false, 'Kanto', ARRAY['Blue', 'LG: Eevee']),
(54, 'Psyduck', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(55, 'Golduck', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(56, 'Mankey', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(57, 'Primeape', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(58, 'Growlithe', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(59, 'Arcanine', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(60, 'Poliwag', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(61, 'Poliwhirl', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(62, 'Poliwrath', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(63, 'Abra', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(64, 'Kadabra', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(64, 'Kadabra', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(65, 'Alakazam', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(65, 'Alakazam', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(66, 'Machop', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(67, 'Machoke', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(68, 'Machamp', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(69, 'Bellsprout', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Eevee']),
(70, 'Weepinbell', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Eevee']),
(71, 'Victreebel', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Eevee']),
(72, 'Tentacool', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(73, 'Tentacruel', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(74, 'Geodude', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(75, 'Graveler', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(76, 'Golem', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(77, 'Ponyta', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(78, 'Rapidash', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(79, 'Slowpoke', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(80, 'Slowbro', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(81, 'Magnemite', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(82, 'Magneton', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(83, 'Farfetchd', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(84, 'Doduo', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(84, 'Doduo', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(85, 'Dodrio', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(85, 'Dodrio', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(86, 'Seel', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(87, 'Dewgong', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(88, 'Grimer', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu']),
(89, 'Muk', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu']),
(90, 'Shellder', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(91, 'Cloyster', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(92, 'Gastly', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(93, 'Haunter', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(94, 'Gengar', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(95, 'Onix', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(96, 'Drowzee', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(97, 'Hypno', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(97, 'Hypno', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(98, 'Krabby', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(99, 'Kingler', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(100, 'Voltorb', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(101, 'Electrode', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(102, 'Exeggcute', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(103, 'Exeggutor', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(104, 'Cubone', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(105, 'Marowak', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(106, 'Hitmonlee', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(107, 'Hitmonchan', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(108, 'Lickitung', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(109, 'Koffing', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Eevee']),
(110, 'Weezing', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Eevee']),
(111, 'Rhyhorn', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(111, 'Rhyhorn', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(112, 'Rhydon', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(112, 'Rhydon', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(113, 'Chansey', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(114, 'Tangela', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(115, 'Kangaskhan', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(116, 'Horsea', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(117, 'Seadra', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(118, 'Goldeen', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(118, 'Goldeen', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(119, 'Seaking', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(119, 'Seaking', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(120, 'Staryu', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(121, 'Starmie', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(122, 'Mr. Mime', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(123, 'Scyther', NULL, false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(123, 'Scyther', 'Female', false, 'Kanto', ARRAY['Red', 'Yellow', 'LG: Pikachu']),
(124, 'Jynx', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'LG: Pikachu', 'LG: Eevee']),
(125, 'Electabuzz', NULL, false, 'Kanto', ARRAY['Red', 'LG: Pikachu', 'LG: Eevee']),
(126, 'Magmar', NULL, false, 'Kanto', ARRAY['Blue', 'LG: Pikachu', 'LG: Eevee']),
(127, 'Pinsir', NULL, false, 'Kanto', ARRAY['Blue', 'Yellow', 'LG: Eevee']),
(128, 'Tauros', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(129, 'Magikarp', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(129, 'Magikarp', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(130, 'Gyarados', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(130, 'Gyarados', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(131, 'Lapras', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(132, 'Ditto', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(133, 'Eevee', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(133, 'Eevee', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(134, 'Vaporeon', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(135, 'Jolteon', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(136, 'Flareon', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(137, 'Porygon', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(138, 'Omanyte', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(139, 'Omastar', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(140, 'Kabuto', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(141, 'Kabutops', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(142, 'Aerodactyl', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(143, 'Snorlax', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(144, 'Articuno', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(145, 'Zapdos', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(146, 'Moltres', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(147, 'Dratini', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(148, 'Dragonair', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(149, 'Dragonite', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(150, 'Mewtwo', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
(151, 'Mew', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee'])
ON CONFLICT ON CONSTRAINT unique_pokemon_form DO NOTHING;
-- Insert Kanto regional dex numbers
INSERT INTO regional_dex_numbers (
pokedex_entry_id,
region,
dex_number
) VALUES
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 1 AND form IS NULL), 'Kanto', 1),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 2 AND form IS NULL), 'Kanto', 2),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 3 AND form IS NULL), 'Kanto', 3),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 4 AND form IS NULL), 'Kanto', 4),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 5 AND form IS NULL), 'Kanto', 5),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 6 AND form IS NULL), 'Kanto', 6),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 7 AND form IS NULL), 'Kanto', 7),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 8 AND form IS NULL), 'Kanto', 8),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 9 AND form IS NULL), 'Kanto', 9),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 10 AND form IS NULL), 'Kanto', 10),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 11 AND form IS NULL), 'Kanto', 11),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 12 AND form IS NULL), 'Kanto', 12),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 13 AND form IS NULL), 'Kanto', 13),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 14 AND form IS NULL), 'Kanto', 14),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 15 AND form IS NULL), 'Kanto', 15),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 16 AND form IS NULL), 'Kanto', 16),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 17 AND form IS NULL), 'Kanto', 17),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 18 AND form IS NULL), 'Kanto', 18),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 19 AND form IS NULL), 'Kanto', 19),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 20 AND form IS NULL), 'Kanto', 20),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 21 AND form IS NULL), 'Kanto', 21),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 22 AND form IS NULL), 'Kanto', 22),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 23 AND form IS NULL), 'Kanto', 23),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 24 AND form IS NULL), 'Kanto', 24),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 25 AND form IS NULL), 'Kanto', 25),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 26 AND form IS NULL), 'Kanto', 26),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 27 AND form IS NULL), 'Kanto', 27),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 28 AND form IS NULL), 'Kanto', 28),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 29 AND form IS NULL), 'Kanto', 29),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 30 AND form IS NULL), 'Kanto', 30),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 31 AND form IS NULL), 'Kanto', 31),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 32 AND form IS NULL), 'Kanto', 32),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 33 AND form IS NULL), 'Kanto', 33),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 34 AND form IS NULL), 'Kanto', 34),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 35 AND form IS NULL), 'Kanto', 35),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 36 AND form IS NULL), 'Kanto', 36),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 37 AND form IS NULL), 'Kanto', 37),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 38 AND form IS NULL), 'Kanto', 38),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 39 AND form IS NULL), 'Kanto', 39),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 40 AND form IS NULL), 'Kanto', 40),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 41 AND form IS NULL), 'Kanto', 41),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 42 AND form IS NULL), 'Kanto', 42),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 43 AND form IS NULL), 'Kanto', 43),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 44 AND form IS NULL), 'Kanto', 44),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 45 AND form IS NULL), 'Kanto', 45),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 46 AND form IS NULL), 'Kanto', 46),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 47 AND form IS NULL), 'Kanto', 47),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 48 AND form IS NULL), 'Kanto', 48),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 49 AND form IS NULL), 'Kanto', 49),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 50 AND form IS NULL), 'Kanto', 50),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 51 AND form IS NULL), 'Kanto', 51),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 52 AND form IS NULL), 'Kanto', 52),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 53 AND form IS NULL), 'Kanto', 53),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 54 AND form IS NULL), 'Kanto', 54),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 55 AND form IS NULL), 'Kanto', 55),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 56 AND form IS NULL), 'Kanto', 56),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 57 AND form IS NULL), 'Kanto', 57),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 58 AND form IS NULL), 'Kanto', 58),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 59 AND form IS NULL), 'Kanto', 59),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 60 AND form IS NULL), 'Kanto', 60),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 61 AND form IS NULL), 'Kanto', 61),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 62 AND form IS NULL), 'Kanto', 62),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 63 AND form IS NULL), 'Kanto', 63),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 64 AND form IS NULL), 'Kanto', 64),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 65 AND form IS NULL), 'Kanto', 65),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 66 AND form IS NULL), 'Kanto', 66),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 67 AND form IS NULL), 'Kanto', 67),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 68 AND form IS NULL), 'Kanto', 68),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 69 AND form IS NULL), 'Kanto', 69),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 70 AND form IS NULL), 'Kanto', 70),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 71 AND form IS NULL), 'Kanto', 71),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 72 AND form IS NULL), 'Kanto', 72),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 73 AND form IS NULL), 'Kanto', 73),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 74 AND form IS NULL), 'Kanto', 74),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 75 AND form IS NULL), 'Kanto', 75),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 76 AND form IS NULL), 'Kanto', 76),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 77 AND form IS NULL), 'Kanto', 77),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 78 AND form IS NULL), 'Kanto', 78),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 79 AND form IS NULL), 'Kanto', 79),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 80 AND form IS NULL), 'Kanto', 80),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 81 AND form IS NULL), 'Kanto', 81),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 82 AND form IS NULL), 'Kanto', 82),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 83 AND form IS NULL), 'Kanto', 83),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 84 AND form IS NULL), 'Kanto', 84),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 85 AND form IS NULL), 'Kanto', 85),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 86 AND form IS NULL), 'Kanto', 86),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 87 AND form IS NULL), 'Kanto', 87),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 88 AND form IS NULL), 'Kanto', 88),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 89 AND form IS NULL), 'Kanto', 89),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 90 AND form IS NULL), 'Kanto', 90),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 91 AND form IS NULL), 'Kanto', 91),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 92 AND form IS NULL), 'Kanto', 92),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 93 AND form IS NULL), 'Kanto', 93),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 94 AND form IS NULL), 'Kanto', 94),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 95 AND form IS NULL), 'Kanto', 95),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 96 AND form IS NULL), 'Kanto', 96),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 97 AND form IS NULL), 'Kanto', 97),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 98 AND form IS NULL), 'Kanto', 98),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 99 AND form IS NULL), 'Kanto', 99),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 100 AND form IS NULL), 'Kanto', 100),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 101 AND form IS NULL), 'Kanto', 101),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 102 AND form IS NULL), 'Kanto', 102),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 103 AND form IS NULL), 'Kanto', 103),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 104 AND form IS NULL), 'Kanto', 104),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 105 AND form IS NULL), 'Kanto', 105),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 106 AND form IS NULL), 'Kanto', 106),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 107 AND form IS NULL), 'Kanto', 107),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 108 AND form IS NULL), 'Kanto', 108),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 109 AND form IS NULL), 'Kanto', 109),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 110 AND form IS NULL), 'Kanto', 110),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 111 AND form IS NULL), 'Kanto', 111),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 112 AND form IS NULL), 'Kanto', 112),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 113 AND form IS NULL), 'Kanto', 113),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 114 AND form IS NULL), 'Kanto', 114),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 115 AND form IS NULL), 'Kanto', 115),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 116 AND form IS NULL), 'Kanto', 116),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 117 AND form IS NULL), 'Kanto', 117),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 118 AND form IS NULL), 'Kanto', 118),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 119 AND form IS NULL), 'Kanto', 119),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 120 AND form IS NULL), 'Kanto', 120),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 121 AND form IS NULL), 'Kanto', 121),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 122 AND form IS NULL), 'Kanto', 122),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 123 AND form IS NULL), 'Kanto', 123),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 124 AND form IS NULL), 'Kanto', 124),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 125 AND form IS NULL), 'Kanto', 125),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 126 AND form IS NULL), 'Kanto', 126),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 127 AND form IS NULL), 'Kanto', 127),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 128 AND form IS NULL), 'Kanto', 128),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 129 AND form IS NULL), 'Kanto', 129),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 130 AND form IS NULL), 'Kanto', 130),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 131 AND form IS NULL), 'Kanto', 131),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 132 AND form IS NULL), 'Kanto', 132),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 133 AND form IS NULL), 'Kanto', 133),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 134 AND form IS NULL), 'Kanto', 134),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 135 AND form IS NULL), 'Kanto', 135),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 136 AND form IS NULL), 'Kanto', 136),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 137 AND form IS NULL), 'Kanto', 137),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 138 AND form IS NULL), 'Kanto', 138),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 139 AND form IS NULL), 'Kanto', 139),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 140 AND form IS NULL), 'Kanto', 140),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 141 AND form IS NULL), 'Kanto', 141),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 142 AND form IS NULL), 'Kanto', 142),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 143 AND form IS NULL), 'Kanto', 143),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 144 AND form IS NULL), 'Kanto', 144),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 145 AND form IS NULL), 'Kanto', 145),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 146 AND form IS NULL), 'Kanto', 146),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 147 AND form IS NULL), 'Kanto', 147),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 148 AND form IS NULL), 'Kanto', 148),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 149 AND form IS NULL), 'Kanto', 149),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 150 AND form IS NULL), 'Kanto', 150),
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 151 AND form IS NULL), 'Kanto', 151);
-- Add metadata
INSERT INTO metadata (key, value) VALUES
('kanto_seeded', 'true'),
('kanto_seed_date', NOW()::TEXT),
('kanto_pokemon_count', '151');