mirror of
https://github.com/jcreek/LivingDexTracker.git
synced 2026-07-12 18:43:45 +00:00
feat(*): Change how data is set up
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
game,region,releaseYear
|
||||
Red,Kanto,1996
|
||||
Blue,Kanto,1996
|
||||
Yellow,Kanto,1998
|
||||
Gold,Johto,1999
|
||||
Silver,Johto,1999
|
||||
Crystal,Johto,2000
|
||||
Ruby,Hoenn,2002
|
||||
Sapphire,Hoenn,2002
|
||||
Colosseum,Orre,2003
|
||||
Emerald,Hoenn,2004
|
||||
FireRed,Kanto,2004
|
||||
LeafGreen,Kanto,2004
|
||||
XD: Gale of Darkness,Orre,2005
|
||||
Diamond,Sinnoh,2006
|
||||
Pearl,Sinnoh,2006
|
||||
Platinum,Sinnoh,2008
|
||||
Ranch,Ranch,2008
|
||||
Heart Gold,Johto,2009
|
||||
Soul Silver,Johto,2009
|
||||
Black,Unova,2010
|
||||
White,Unova,2010
|
||||
Black 2,Unova,2012
|
||||
White 2,Unova,2012
|
||||
Dream Radar,Unova,2012
|
||||
X,Kalos,2013
|
||||
Y,Kalos,2013
|
||||
Omega Ruby,Hoenn,2014
|
||||
Alpha Sapphire,Hoenn,2014
|
||||
Sun,Alola,2016
|
||||
Moon,Alola,2016
|
||||
Moon (demo),Alola,2016
|
||||
Go,Go,2016
|
||||
Ultra Sun,Alola,2017
|
||||
Ultra Moon,Alola,2017
|
||||
LG: Pikachu,Kanto,2018
|
||||
LG: Eevee,Kanto,2018
|
||||
Sword,Galar,2019
|
||||
Shield,Galar,2019
|
||||
Home,Home,2020
|
||||
Brilliant Diamond,Sinnoh,2021
|
||||
Shining Pearl,Sinnoh,2021
|
||||
Legends: Arceus,Hisui,2022
|
||||
Scarlet,Paldea,2022
|
||||
Violet,Paldea,2022
|
||||
Legends: Z-A,Kalos,2025
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,15 @@
|
||||
region
|
||||
Kanto
|
||||
Johto
|
||||
Hoenn
|
||||
Sinnoh
|
||||
Unova
|
||||
Galar
|
||||
Alola
|
||||
Kalos
|
||||
Hisui
|
||||
Paldea
|
||||
Go
|
||||
Home
|
||||
Orre
|
||||
Ranch
|
||||
|
@@ -2,8 +2,7 @@
|
||||
export interface CatchRecord {
|
||||
_id: string; // Maps to Supabase 'id' field for frontend compatibility
|
||||
userId: string;
|
||||
pokedexEntryId: string; // String representation of the foreign key
|
||||
pokedexId: string; // NEW: Foreign key to pokedexes table
|
||||
pokemonId: string;
|
||||
haveToEvolve: boolean;
|
||||
caught: boolean;
|
||||
inHome: boolean;
|
||||
@@ -15,7 +14,8 @@ export interface CatchRecord {
|
||||
export interface CatchRecordDB {
|
||||
id: string;
|
||||
userId: string;
|
||||
pokedexEntryId: number; // Numeric foreign key in database
|
||||
/** Numeric foreign key in database (references `pokemon.id`) */
|
||||
pokemonId: number;
|
||||
pokedexId: string; // NEW: Foreign key to pokedexes table
|
||||
haveToEvolve: boolean;
|
||||
caught: boolean;
|
||||
|
||||
@@ -15,8 +15,7 @@ class CatchRecordRepository {
|
||||
return {
|
||||
_id: record.id,
|
||||
userId: record.userId,
|
||||
pokedexEntryId: record.pokedexEntryId.toString(),
|
||||
pokedexId: record.pokedexId,
|
||||
pokemonId: record.pokemonId.toString(),
|
||||
haveToEvolve: record.haveToEvolve,
|
||||
caught: record.caught,
|
||||
inHome: record.inHome,
|
||||
@@ -28,12 +27,12 @@ class CatchRecordRepository {
|
||||
// Transform frontend data to database format (minimal transformation)
|
||||
private transformToDatabase(data: Partial<CatchRecord>): Partial<CatchRecordDB> {
|
||||
const dbData: Partial<CatchRecordDB> = {};
|
||||
if (data.pokedexEntryId !== undefined && data.pokedexEntryId !== null) {
|
||||
const numericId = Number(data.pokedexEntryId);
|
||||
if (data.pokemonId !== undefined && data.pokemonId !== null) {
|
||||
const numericId = Number(data.pokemonId);
|
||||
if (isNaN(numericId)) {
|
||||
throw new Error(`Invalid pokedexEntryId: ${data.pokedexEntryId}`);
|
||||
throw new Error(`Invalid pokemonId: ${data.pokemonId}`);
|
||||
}
|
||||
dbData.pokedexEntryId = numericId;
|
||||
dbData.pokemonId = numericId;
|
||||
}
|
||||
if (data.pokedexId !== undefined) dbData.pokedexId = data.pokedexId;
|
||||
if (data.haveToEvolve !== undefined) dbData.haveToEvolve = data.haveToEvolve;
|
||||
@@ -53,14 +52,14 @@ class CatchRecordRepository {
|
||||
* catch the error and fall back to per-record upserts.
|
||||
*/
|
||||
async bulkUpsert(
|
||||
records: Array<PartialExcept<CatchRecord, 'pokedexEntryId'>>
|
||||
records: Array<PartialExcept<CatchRecord, 'pokemonId'>>
|
||||
): Promise<CatchRecord[]> {
|
||||
if (records.length === 0) return [];
|
||||
|
||||
const dbRows: Partial<CatchRecordDB>[] = records.map((r, index) => {
|
||||
if (r.pokedexEntryId === undefined || r.pokedexEntryId === null || r.pokedexEntryId === '') {
|
||||
if (r.pokemonId === undefined || r.pokemonId === null || r.pokemonId === '') {
|
||||
throw new Error(
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} is missing required field "pokedexEntryId"`
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} is missing required field "pokemonId"`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -81,9 +80,9 @@ class CatchRecordRepository {
|
||||
mapped.userId = this.userId;
|
||||
mapped.pokedexId = this.pokedexId;
|
||||
|
||||
if (mapped.pokedexEntryId === undefined || mapped.pokedexEntryId === null) {
|
||||
if (mapped.pokemonId === undefined || mapped.pokemonId === null) {
|
||||
throw new Error(
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} produced no pokedexEntryId after transform`
|
||||
`CatchRecordRepository.bulkUpsert: record at index ${index} produced no pokemonId after transform`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -93,7 +92,7 @@ class CatchRecordRepository {
|
||||
const { data: result, error } = await this.supabase
|
||||
.from('catch_records')
|
||||
.upsert(dbRows, {
|
||||
onConflict: '"userId","pokedexId","pokedexEntryId"'
|
||||
onConflict: '"userId","pokedexId","pokemonId"'
|
||||
})
|
||||
.select();
|
||||
|
||||
@@ -198,13 +197,9 @@ class CatchRecordRepository {
|
||||
async upsert(data: Partial<CatchRecord>): Promise<CatchRecord | null> {
|
||||
if (data._id) {
|
||||
return this.update(data._id, data);
|
||||
} else if (data.pokedexEntryId) {
|
||||
} else if (data.pokemonId) {
|
||||
// Try to find existing record for this user, pokemon, and pokedex
|
||||
const existing = await this.findByUserAndPokemon(
|
||||
this.userId,
|
||||
data.pokedexEntryId,
|
||||
this.pokedexId
|
||||
);
|
||||
const existing = await this.findByUserAndPokemon(this.userId, data.pokemonId, this.pokedexId);
|
||||
if (existing) {
|
||||
return this.update(existing._id, data);
|
||||
} else {
|
||||
@@ -216,10 +211,10 @@ class CatchRecordRepository {
|
||||
|
||||
async findByUserAndPokemon(
|
||||
userId: string,
|
||||
pokedexEntryId: string,
|
||||
pokemonId: string,
|
||||
pokedexId: string
|
||||
): Promise<CatchRecord | null> {
|
||||
const numericId = Number(pokedexEntryId);
|
||||
const numericId = Number(pokemonId);
|
||||
if (isNaN(numericId)) {
|
||||
return null;
|
||||
}
|
||||
@@ -227,7 +222,7 @@ class CatchRecordRepository {
|
||||
.from('catch_records')
|
||||
.select('*')
|
||||
.eq('userId', userId)
|
||||
.eq('pokedexEntryId', numericId)
|
||||
.eq('pokemonId', numericId)
|
||||
.eq('pokedexId', pokedexId)
|
||||
.single();
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ class CombinedDataRepository {
|
||||
return {
|
||||
_id: record.id,
|
||||
userId: record.userId,
|
||||
pokedexEntryId: record.pokedexEntryId.toString(),
|
||||
// Backwards-compatible field name; DB column is pokemonId
|
||||
pokedexEntryId: record.pokemonId.toString(),
|
||||
pokedexId: record.pokedexId,
|
||||
haveToEvolve: record.haveToEvolve,
|
||||
caught: record.caught,
|
||||
@@ -87,7 +88,7 @@ class CombinedDataRepository {
|
||||
.select('*')
|
||||
.eq('userId', userId)
|
||||
.eq('pokedexId', this.pokedexId)
|
||||
.in('pokedexEntryId', entryIds);
|
||||
.in('pokemonId', entryIds);
|
||||
|
||||
if (!recordsError && records) {
|
||||
catchRecords = records;
|
||||
@@ -96,8 +97,7 @@ class CombinedDataRepository {
|
||||
|
||||
// Combine the data exactly like master branch
|
||||
const combinedData = entries.map((entry) => {
|
||||
const userCatchRecord =
|
||||
catchRecords.find((record) => record.pokedexEntryId === entry.id) || null;
|
||||
const userCatchRecord = catchRecords.find((record) => record.pokemonId === entry.id) || null;
|
||||
|
||||
const transformedEntry = this.transformPokedexEntry(entry);
|
||||
const transformedCatchRecord = userCatchRecord
|
||||
@@ -165,7 +165,7 @@ class CombinedDataRepository {
|
||||
.select('*')
|
||||
.eq('userId', userId)
|
||||
.eq('pokedexId', this.pokedexId)
|
||||
.in('pokedexEntryId', entryIds);
|
||||
.in('pokemonId', entryIds);
|
||||
|
||||
if (!recordsError && records) {
|
||||
catchRecords = records;
|
||||
@@ -174,8 +174,7 @@ class CombinedDataRepository {
|
||||
|
||||
// Combine the data exactly like master branch
|
||||
const combinedData = entries.map((entry) => {
|
||||
const userCatchRecord =
|
||||
catchRecords.find((record) => record.pokedexEntryId === entry.id) || null;
|
||||
const userCatchRecord = catchRecords.find((record) => record.pokemonId === entry.id) || null;
|
||||
|
||||
const transformedEntry = this.transformPokedexEntry(entry);
|
||||
const transformedCatchRecord = userCatchRecord
|
||||
|
||||
@@ -20,11 +20,12 @@ export async function calculateExpectedEntries(
|
||||
|
||||
// Apply region filter: if gameScope is specified, filter by region
|
||||
if (pokedex.gameScope) {
|
||||
// Determine region from gameScope using region_game_mappings
|
||||
// Determine region from gameScope using games table.
|
||||
// We keep games.region as a denormalized convenience column.
|
||||
const { data: regionData, error: regionError } = await supabase
|
||||
.from('region_game_mappings')
|
||||
.from('games')
|
||||
.select('region')
|
||||
.eq('game', pokedex.gameScope)
|
||||
.eq('displayName', pokedex.gameScope)
|
||||
.maybeSingle();
|
||||
|
||||
if (regionError) {
|
||||
@@ -71,17 +72,18 @@ export async function populatePokedexMappings(
|
||||
return;
|
||||
}
|
||||
|
||||
const mappings = expectedEntryIds.map((pokedexEntryId) => ({
|
||||
// New schema writes to pokedex_pokemon_mapping; column is pokemonId
|
||||
const mappings = expectedEntryIds.map((pokemonId) => ({
|
||||
pokedexId,
|
||||
pokedexEntryId
|
||||
pokemonId
|
||||
}));
|
||||
|
||||
// Process in chunks to avoid request size limits
|
||||
const CHUNK_SIZE = 500;
|
||||
for (let i = 0; i < mappings.length; i += CHUNK_SIZE) {
|
||||
const chunk = mappings.slice(i, i + CHUNK_SIZE);
|
||||
const { error } = await supabase.from('pokedex_entries_mapping').upsert(chunk, {
|
||||
onConflict: 'pokedexId,pokedexEntryId',
|
||||
const { error } = await supabase.from('pokedex_pokemon_mapping').upsert(chunk, {
|
||||
onConflict: 'pokedexId,pokemonId',
|
||||
ignoreDuplicates: true
|
||||
});
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ export type FlushOptions = {
|
||||
};
|
||||
|
||||
function keyFor(record: CatchRecord): string {
|
||||
return `${record.userId}:${record.pokedexId}:${record.pokedexEntryId}`;
|
||||
return `${record.userId}:${record.pokedexId}:${record.pokemonId}`;
|
||||
}
|
||||
|
||||
function backoffMs(attempts: number): number {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
-- 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);
|
||||
@@ -1,360 +0,0 @@
|
||||
-- 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', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(14, 'Kakuna', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(15, 'Beedrill', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', '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', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(24, 'Arbok', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', '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['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(28, 'Sandslash', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(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['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(38, 'Ninetales', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', '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', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(44, 'Gloom', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(44, 'Gloom', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(45, 'Vileplume', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(45, 'Vileplume', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(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['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(53, 'Persian', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', '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', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(57, 'Primeape', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(58, 'Growlithe', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(59, 'Arcanine', NULL, false, 'Kanto', ARRAY['Red', 'Blue', '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['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(70, 'Weepinbell', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(71, 'Victreebel', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', '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, 'Farfetch’d', 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', 'LG: Eevee']),
|
||||
(89, 'Muk', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(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', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(110, 'Weezing', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', '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', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(123, 'Scyther', 'Female', false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(124, 'Jynx', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(125, 'Electabuzz', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(126, 'Magmar', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', 'LG: Eevee']),
|
||||
(127, 'Pinsir', NULL, false, 'Kanto', ARRAY['Red', 'Blue', 'Yellow', 'LG: Pikachu', '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');
|
||||
@@ -1,284 +0,0 @@
|
||||
-- Seed Johto region Pokémon (Gen 2)
|
||||
-- Auto-generated from CSV files
|
||||
|
||||
-- Insert Johto region-game mappings
|
||||
INSERT INTO region_game_mappings (region, game) VALUES
|
||||
('Johto', 'Gold'),
|
||||
('Johto', 'Silver'),
|
||||
('Johto', 'Crystal'),
|
||||
('Johto', 'HeartGold'),
|
||||
('Johto', 'SoulSilver')
|
||||
ON CONFLICT (region, game) DO NOTHING;
|
||||
|
||||
-- Insert Johto Pokémon entries
|
||||
INSERT INTO pokedex_entries (
|
||||
"pokedexNumber",
|
||||
pokemon,
|
||||
form,
|
||||
"canGigantamax",
|
||||
"regionToCatchIn",
|
||||
"gamesToCatchIn"
|
||||
) VALUES
|
||||
(152, 'Chikorita', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(153, 'Bayleef', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(154, 'Meganium', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(154, 'Meganium', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(155, 'Cyndaquil', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(156, 'Quilava', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(157, 'Typhlosion', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(158, 'Totodile', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(159, 'Croconaw', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(160, 'Feraligatr', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(161, 'Sentret', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(162, 'Furret', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(163, 'Hoothoot', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(164, 'Noctowl', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(165, 'Ledyba', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(165, 'Ledyba', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(166, 'Ledian', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(166, 'Ledian', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(167, 'Spinarak', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(168, 'Ariados', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(169, 'Crobat', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(170, 'Chinchou', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(171, 'Lanturn', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(172, 'Pichu', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(173, 'Cleffa', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(174, 'Igglybuff', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(175, 'Togepi', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(176, 'Togetic', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(177, 'Natu', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(178, 'Xatu', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(178, 'Xatu', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(179, 'Mareep', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(180, 'Flaaffy', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(181, 'Ampharos', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(182, 'Bellossom', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(183, 'Marill', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(184, 'Azumarill', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(185, 'Sudowoodo', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(185, 'Sudowoodo', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(186, 'Politoed', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(186, 'Politoed', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(187, 'Hoppip', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(188, 'Skiploom', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(189, 'Jumpluff', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(190, 'Aipom', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(190, 'Aipom', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(191, 'Sunkern', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(192, 'Sunflora', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(193, 'Yanma', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(194, 'Wooper', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(194, 'Wooper', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(195, 'Quagsire', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(195, 'Quagsire', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(196, 'Espeon', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(197, 'Umbreon', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(198, 'Murkrow', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(198, 'Murkrow', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(199, 'Slowking', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(200, 'Misdreavus', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'A', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'B', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'C', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'D', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'E', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'F', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'G', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'H', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'I', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'J', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'K', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'L', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'M', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'N', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'O', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'P', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'Q', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'R', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'S', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'T', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'U', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'V', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'W', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'X', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'Y', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', 'Z', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', '!', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(201, 'Unown', '?', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(202, 'Wobbuffet', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(202, 'Wobbuffet', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(203, 'Girafarig', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(203, 'Girafarig', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(204, 'Pineco', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(205, 'Forretress', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(206, 'Dunsparce', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(207, 'Gligar', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(207, 'Gligar', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(208, 'Steelix', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(208, 'Steelix', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(209, 'Snubbull', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(210, 'Granbull', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(211, 'Qwilfish', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(212, 'Scizor', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(212, 'Scizor', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(213, 'Shuckle', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(214, 'Heracross', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(214, 'Heracross', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(215, 'Sneasel', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(215, 'Sneasel', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(216, 'Teddiursa', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(217, 'Ursaring', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(217, 'Ursaring', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(218, 'Slugma', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(219, 'Magcargo', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(220, 'Swinub', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(221, 'Piloswine', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(221, 'Piloswine', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(222, 'Corsola', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(223, 'Remoraid', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(224, 'Octillery', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(224, 'Octillery', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(225, 'Delibird', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(226, 'Mantine', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(227, 'Skarmory', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(228, 'Houndour', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(229, 'Houndoom', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(229, 'Houndoom', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(230, 'Kingdra', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(231, 'Phanpy', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(232, 'Donphan', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(232, 'Donphan', 'Female', false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(233, 'Porygon2', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(234, 'Stantler', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(235, 'Smeargle', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(236, 'Tyrogue', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(237, 'Hitmontop', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(238, 'Smoochum', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(239, 'Elekid', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(240, 'Magby', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(241, 'Miltank', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(242, 'Blissey', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(243, 'Raikou', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(244, 'Entei', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(245, 'Suicune', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(246, 'Larvitar', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(247, 'Pupitar', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(248, 'Tyranitar', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(249, 'Lugia', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(250, 'Ho-Oh', NULL, false, 'Johto', ARRAY['Gold', 'Silver', 'Crystal', 'HeartGold', 'SoulSilver']),
|
||||
(251, 'Celebi', NULL, false, 'Johto', ARRAY['Crystal', 'HeartGold', 'SoulSilver'])
|
||||
ON CONFLICT ON CONSTRAINT unique_pokemon_form DO NOTHING;
|
||||
|
||||
-- Insert Johto regional dex numbers
|
||||
INSERT INTO regional_dex_numbers (
|
||||
pokedex_entry_id,
|
||||
region,
|
||||
dex_number
|
||||
) VALUES
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 152 AND form IS NULL), 'Johto', 1),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 153 AND form IS NULL), 'Johto', 2),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 154 AND form IS NULL), 'Johto', 3),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 155 AND form IS NULL), 'Johto', 4),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 156 AND form IS NULL), 'Johto', 5),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 157 AND form IS NULL), 'Johto', 6),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 158 AND form IS NULL), 'Johto', 7),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 159 AND form IS NULL), 'Johto', 8),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 160 AND form IS NULL), 'Johto', 9),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 161 AND form IS NULL), 'Johto', 10),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 162 AND form IS NULL), 'Johto', 11),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 163 AND form IS NULL), 'Johto', 12),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 164 AND form IS NULL), 'Johto', 13),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 165 AND form IS NULL), 'Johto', 14),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 166 AND form IS NULL), 'Johto', 15),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 167 AND form IS NULL), 'Johto', 16),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 168 AND form IS NULL), 'Johto', 17),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 169 AND form IS NULL), 'Johto', 18),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 170 AND form IS NULL), 'Johto', 19),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 171 AND form IS NULL), 'Johto', 20),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 172 AND form IS NULL), 'Johto', 21),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 173 AND form IS NULL), 'Johto', 22),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 174 AND form IS NULL), 'Johto', 23),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 175 AND form IS NULL), 'Johto', 24),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 176 AND form IS NULL), 'Johto', 25),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 177 AND form IS NULL), 'Johto', 26),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 178 AND form IS NULL), 'Johto', 27),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 179 AND form IS NULL), 'Johto', 28),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 180 AND form IS NULL), 'Johto', 29),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 181 AND form IS NULL), 'Johto', 30),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 182 AND form IS NULL), 'Johto', 31),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 183 AND form IS NULL), 'Johto', 32),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 184 AND form IS NULL), 'Johto', 33),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 185 AND form IS NULL), 'Johto', 34),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 186 AND form IS NULL), 'Johto', 35),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 187 AND form IS NULL), 'Johto', 36),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 188 AND form IS NULL), 'Johto', 37),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 189 AND form IS NULL), 'Johto', 38),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 190 AND form IS NULL), 'Johto', 39),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 191 AND form IS NULL), 'Johto', 40),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 192 AND form IS NULL), 'Johto', 41),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 193 AND form IS NULL), 'Johto', 42),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 194 AND form IS NULL), 'Johto', 43),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 195 AND form IS NULL), 'Johto', 44),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 196 AND form IS NULL), 'Johto', 45),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 197 AND form IS NULL), 'Johto', 46),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 198 AND form IS NULL), 'Johto', 47),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 199 AND form IS NULL), 'Johto', 48),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 200 AND form IS NULL), 'Johto', 49),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 201 AND form = 'A'), 'Johto', 50),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 202 AND form IS NULL), 'Johto', 51),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 203 AND form IS NULL), 'Johto', 52),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 204 AND form IS NULL), 'Johto', 53),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 205 AND form IS NULL), 'Johto', 54),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 206 AND form IS NULL), 'Johto', 55),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 207 AND form IS NULL), 'Johto', 56),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 208 AND form IS NULL), 'Johto', 57),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 209 AND form IS NULL), 'Johto', 58),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 210 AND form IS NULL), 'Johto', 59),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 211 AND form IS NULL), 'Johto', 60),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 212 AND form IS NULL), 'Johto', 61),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 213 AND form IS NULL), 'Johto', 62),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 214 AND form IS NULL), 'Johto', 63),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 215 AND form IS NULL), 'Johto', 64),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 216 AND form IS NULL), 'Johto', 65),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 217 AND form IS NULL), 'Johto', 66),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 218 AND form IS NULL), 'Johto', 67),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 219 AND form IS NULL), 'Johto', 68),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 220 AND form IS NULL), 'Johto', 69),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 221 AND form IS NULL), 'Johto', 70),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 222 AND form IS NULL), 'Johto', 71),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 223 AND form IS NULL), 'Johto', 72),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 224 AND form IS NULL), 'Johto', 73),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 225 AND form IS NULL), 'Johto', 74),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 226 AND form IS NULL), 'Johto', 75),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 227 AND form IS NULL), 'Johto', 76),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 228 AND form IS NULL), 'Johto', 77),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 229 AND form IS NULL), 'Johto', 78),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 230 AND form IS NULL), 'Johto', 79),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 231 AND form IS NULL), 'Johto', 80),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 232 AND form IS NULL), 'Johto', 81),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 233 AND form IS NULL), 'Johto', 82),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 234 AND form IS NULL), 'Johto', 83),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 235 AND form IS NULL), 'Johto', 84),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 236 AND form IS NULL), 'Johto', 85),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 237 AND form IS NULL), 'Johto', 86),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 238 AND form IS NULL), 'Johto', 87),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 239 AND form IS NULL), 'Johto', 88),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 240 AND form IS NULL), 'Johto', 89),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 241 AND form IS NULL), 'Johto', 90),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 242 AND form IS NULL), 'Johto', 91),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 243 AND form IS NULL), 'Johto', 92),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 244 AND form IS NULL), 'Johto', 93),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 245 AND form IS NULL), 'Johto', 94),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 246 AND form IS NULL), 'Johto', 95),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 247 AND form IS NULL), 'Johto', 96),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 248 AND form IS NULL), 'Johto', 97),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 249 AND form IS NULL), 'Johto', 98),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 250 AND form IS NULL), 'Johto', 99),
|
||||
((SELECT id FROM pokedex_entries WHERE "pokedexNumber" = 251 AND form IS NULL), 'Johto', 100);
|
||||
|
||||
-- Add metadata
|
||||
INSERT INTO metadata (key, value) VALUES
|
||||
('johto_seeded', 'true'),
|
||||
('johto_seed_date', NOW()::TEXT),
|
||||
('johto_pokemon_count', '99');
|
||||
@@ -1,217 +0,0 @@
|
||||
-- Fix catch_records uniqueness for multi-pokédex support.
|
||||
--
|
||||
-- Intended invariant:
|
||||
-- one catch record per (userId, pokedexId, pokedexEntryId)
|
||||
--
|
||||
-- This migration is written to be safe to run even if parts of the schema already exist.
|
||||
|
||||
-- 1) Ensure pokedexId column exists
|
||||
ALTER TABLE public.catch_records
|
||||
ADD COLUMN IF NOT EXISTS "pokedexId" UUID;
|
||||
|
||||
-- 1.5) Guards: fail early with diagnostics if the backfill would be unsafe.
|
||||
--
|
||||
-- Why:
|
||||
-- - The backfill below only updates rows for users that have at least one pokedex.
|
||||
-- If any user has catch_records but no pokedexes, those rows would remain NULL
|
||||
-- and the NOT NULL enforcement would fail.
|
||||
-- - The backfill assigns all NULL pokedexId rows to each user's oldest pokedex.
|
||||
-- That can create duplicate (userId, pokedexId, pokedexEntryId) combinations.
|
||||
--
|
||||
-- If either condition is detected, this migration aborts and prints sample IDs.
|
||||
DO $$
|
||||
DECLARE
|
||||
orphan_user_count bigint;
|
||||
orphan_row_count bigint;
|
||||
orphan_user_samples text;
|
||||
|
||||
dup_group_count bigint;
|
||||
dup_group_samples text;
|
||||
BEGIN
|
||||
-- Guard A: Any catch_records with NULL pokedexId for users who have no pokedexes?
|
||||
WITH orphan_users AS (
|
||||
SELECT cr."userId" AS user_id,
|
||||
COUNT(*)::bigint AS null_row_count
|
||||
FROM public.catch_records cr
|
||||
WHERE cr."pokedexId" IS NULL
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM public.pokedexes p
|
||||
WHERE p."userId" = cr."userId"
|
||||
)
|
||||
GROUP BY cr."userId"
|
||||
)
|
||||
SELECT
|
||||
COUNT(*)::bigint,
|
||||
COALESCE(SUM(null_row_count), 0)::bigint,
|
||||
(
|
||||
SELECT string_agg(user_id::text, ', ' ORDER BY user_id::text)
|
||||
FROM (
|
||||
SELECT user_id, null_row_count
|
||||
FROM orphan_users
|
||||
ORDER BY null_row_count DESC, user_id
|
||||
LIMIT 10
|
||||
) s
|
||||
)
|
||||
INTO orphan_user_count, orphan_row_count, orphan_user_samples
|
||||
FROM orphan_users;
|
||||
|
||||
IF orphan_user_count > 0 THEN
|
||||
RAISE EXCEPTION
|
||||
'USAFE MIGRATION: found % user(s) with % catch_records row(s) where "pokedexId" is NULL but the user has no pokedexes. Sample userId(s): %',
|
||||
orphan_user_count,
|
||||
orphan_row_count,
|
||||
COALESCE(orphan_user_samples, '(none)');
|
||||
END IF;
|
||||
|
||||
-- Guard B: Would assigning NULL pokedexId rows to each user''s oldest pokedex create duplicates?
|
||||
WITH primary_pokedex AS (
|
||||
SELECT DISTINCT ON ("userId") id AS pokedex_id, "userId"
|
||||
FROM public.pokedexes
|
||||
ORDER BY "userId", "createdAt" ASC
|
||||
),
|
||||
projected AS (
|
||||
SELECT
|
||||
cr."userId",
|
||||
COALESCE(cr."pokedexId", pp.pokedex_id) AS projected_pokedex_id,
|
||||
cr."pokedexEntryId"
|
||||
FROM public.catch_records cr
|
||||
LEFT JOIN primary_pokedex pp
|
||||
ON pp."userId" = cr."userId"
|
||||
),
|
||||
dup_groups AS (
|
||||
SELECT
|
||||
"userId",
|
||||
projected_pokedex_id,
|
||||
"pokedexEntryId",
|
||||
COUNT(*)::bigint AS row_count
|
||||
FROM projected
|
||||
WHERE projected_pokedex_id IS NOT NULL
|
||||
GROUP BY "userId", projected_pokedex_id, "pokedexEntryId"
|
||||
HAVING COUNT(*) > 1
|
||||
)
|
||||
SELECT
|
||||
COUNT(*)::bigint,
|
||||
(
|
||||
SELECT string_agg(
|
||||
format(
|
||||
'(userId=%s, pokedexId=%s, pokedexEntryId=%s, rows=%s)',
|
||||
"userId"::text,
|
||||
projected_pokedex_id::text,
|
||||
"pokedexEntryId"::text,
|
||||
row_count::text
|
||||
),
|
||||
E'\n'
|
||||
ORDER BY row_count DESC, "userId"::text
|
||||
)
|
||||
FROM (
|
||||
SELECT * FROM dup_groups
|
||||
ORDER BY row_count DESC, "userId"::text
|
||||
LIMIT 10
|
||||
) s
|
||||
)
|
||||
INTO dup_group_count, dup_group_samples
|
||||
FROM dup_groups;
|
||||
|
||||
IF dup_group_count > 0 THEN
|
||||
RAISE EXCEPTION
|
||||
'USAFE MIGRATION: backfill would create % duplicate (userId, pokedexId, pokedexEntryId) group(s) after projecting NULL "pokedexId" to each user''s oldest pokedex. Sample group(s):\n%',
|
||||
dup_group_count,
|
||||
COALESCE(dup_group_samples, '(none)');
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- 2) Best-effort backfill for any NULL pokedexId rows.
|
||||
-- Strategy: assign to the user's oldest pokedex.
|
||||
WITH primary_pokedex AS (
|
||||
SELECT DISTINCT ON ("userId") id AS pokedex_id, "userId"
|
||||
FROM public.pokedexes
|
||||
ORDER BY "userId", "createdAt" ASC
|
||||
)
|
||||
UPDATE public.catch_records cr
|
||||
SET "pokedexId" = pp.pokedex_id
|
||||
FROM primary_pokedex pp
|
||||
WHERE cr."userId" = pp."userId"
|
||||
AND cr."pokedexId" IS NULL;
|
||||
|
||||
-- 3) Enforce NOT NULL + FK
|
||||
ALTER TABLE public.catch_records
|
||||
ALTER COLUMN "pokedexId" SET NOT NULL;
|
||||
|
||||
-- Drop/recreate FK to avoid "already exists" name collisions.
|
||||
ALTER TABLE public.catch_records
|
||||
DROP CONSTRAINT IF EXISTS "catch_records_pokedexId_fkey";
|
||||
|
||||
ALTER TABLE public.catch_records
|
||||
ADD CONSTRAINT "catch_records_pokedexId_fkey"
|
||||
FOREIGN KEY ("pokedexId") REFERENCES public.pokedexes(id) ON DELETE CASCADE;
|
||||
|
||||
-- 4) Replace uniqueness constraint
|
||||
ALTER TABLE public.catch_records
|
||||
DROP CONSTRAINT IF EXISTS "catch_records_userId_pokedexEntryId_key";
|
||||
|
||||
ALTER TABLE public.catch_records
|
||||
DROP CONSTRAINT IF EXISTS "catch_records_user_pokemon_pokedex_unique";
|
||||
|
||||
ALTER TABLE public.catch_records
|
||||
ADD CONSTRAINT "catch_records_user_pokemon_pokedex_unique"
|
||||
UNIQUE ("userId", "pokedexId", "pokedexEntryId");
|
||||
|
||||
-- 5) Helpful index
|
||||
CREATE INDEX IF NOT EXISTS idx_catch_records_pokedex_id ON public.catch_records("pokedexId");
|
||||
|
||||
-- 6) RLS policies (recreate safely)
|
||||
ALTER TABLE public.catch_records ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
DROP POLICY IF EXISTS "Users can view own catch records" ON public.catch_records;
|
||||
DROP POLICY IF EXISTS "Users can insert own catch records" ON public.catch_records;
|
||||
DROP POLICY IF EXISTS "Users can update own catch records" ON public.catch_records;
|
||||
DROP POLICY IF EXISTS "Users can delete own catch records" ON public.catch_records;
|
||||
|
||||
CREATE POLICY "Users can view own catch records" ON public.catch_records
|
||||
FOR SELECT USING (
|
||||
auth.uid() = "userId" AND
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.pokedexes
|
||||
WHERE public.pokedexes.id = public.catch_records."pokedexId"
|
||||
AND public.pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can insert own catch records" ON public.catch_records
|
||||
FOR INSERT WITH CHECK (
|
||||
auth.uid() = "userId" AND
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.pokedexes
|
||||
WHERE public.pokedexes.id = public.catch_records."pokedexId"
|
||||
AND public.pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can update own catch records" ON public.catch_records
|
||||
FOR UPDATE USING (
|
||||
auth.uid() = "userId" AND
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.pokedexes
|
||||
WHERE public.pokedexes.id = public.catch_records."pokedexId"
|
||||
AND public.pokedexes."userId" = auth.uid()
|
||||
)
|
||||
)
|
||||
WITH CHECK (
|
||||
auth.uid() = public.catch_records."userId" AND
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.pokedexes
|
||||
WHERE public.pokedexes.id = public.catch_records."pokedexId"
|
||||
AND public.pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete own catch records" ON public.catch_records
|
||||
FOR DELETE USING (
|
||||
auth.uid() = "userId" AND
|
||||
EXISTS (
|
||||
SELECT 1 FROM public.pokedexes
|
||||
WHERE public.pokedexes.id = public.catch_records."pokedexId"
|
||||
AND public.pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
@@ -1,53 +0,0 @@
|
||||
-- Create function to calculate and update stats in the cache table
|
||||
-- This function runs the expensive queries and stores the results
|
||||
|
||||
CREATE OR REPLACE FUNCTION update_and_get_stats()
|
||||
RETURNS TABLE (
|
||||
pokemon_caught BIGINT,
|
||||
total_users BIGINT,
|
||||
completed_pokedexes BIGINT,
|
||||
updated_at TIMESTAMPTZ
|
||||
)
|
||||
SECURITY DEFINER
|
||||
SET search_path = public, pg_temp
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_pokemon_caught BIGINT;
|
||||
v_total_users BIGINT;
|
||||
v_completed_pokedexes BIGINT;
|
||||
v_updated_at TIMESTAMPTZ := NOW();
|
||||
BEGIN
|
||||
-- Calculate current stats: count of caught Pokémon
|
||||
SELECT COUNT(*) INTO v_pokemon_caught
|
||||
FROM catch_records
|
||||
WHERE caught = true;
|
||||
|
||||
-- Calculate current stats: count of total users
|
||||
SELECT COUNT(*) INTO v_total_users
|
||||
FROM auth.users;
|
||||
|
||||
-- Calculate current stats: count of completed pokedexes
|
||||
-- A pokedex is completed when all its entries have caught = true
|
||||
SELECT COUNT(*) INTO v_completed_pokedexes
|
||||
FROM (
|
||||
SELECT "pokedexId"
|
||||
FROM catch_records
|
||||
GROUP BY "pokedexId"
|
||||
HAVING COUNT(*) = COUNT(*) FILTER (WHERE caught = true)
|
||||
) completed;
|
||||
|
||||
-- Update cache using UPSERT pattern
|
||||
INSERT INTO stats_cache (id, pokemon_caught, total_users, completed_pokedexes, updated_at)
|
||||
VALUES (1, v_pokemon_caught, v_total_users, v_completed_pokedexes, v_updated_at)
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
SET pokemon_caught = EXCLUDED.pokemon_caught,
|
||||
total_users = EXCLUDED.total_users,
|
||||
completed_pokedexes = EXCLUDED.completed_pokedexes,
|
||||
updated_at = v_updated_at;
|
||||
|
||||
-- Return the stats
|
||||
RETURN QUERY
|
||||
SELECT v_pokemon_caught, v_total_users, v_completed_pokedexes, v_updated_at AS updated_at;
|
||||
END;
|
||||
$$;
|
||||
@@ -1,36 +0,0 @@
|
||||
-- Create function to get public stats with caching
|
||||
-- Returns cached stats if fresh (within 24 hours), otherwise refreshes cache
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_public_stats()
|
||||
RETURNS TABLE (
|
||||
pokemon_caught BIGINT,
|
||||
total_users BIGINT,
|
||||
completed_pokedexes BIGINT,
|
||||
updated_at TIMESTAMPTZ
|
||||
)
|
||||
SECURITY DEFINER
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_cache_exists BOOLEAN;
|
||||
BEGIN
|
||||
-- Check if cache exists and is fresh (within 24 hours)
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM stats_cache
|
||||
WHERE stats_cache.updated_at > NOW() - INTERVAL '24 hours'
|
||||
) INTO v_cache_exists;
|
||||
|
||||
IF v_cache_exists THEN
|
||||
-- Return cached stats
|
||||
RETURN QUERY
|
||||
SELECT sc.pokemon_caught, sc.total_users, sc.completed_pokedexes, sc.updated_at
|
||||
FROM stats_cache sc
|
||||
ORDER BY sc.updated_at DESC
|
||||
LIMIT 1;
|
||||
ELSE
|
||||
-- Cache is stale or doesn't exist, update it
|
||||
RETURN QUERY
|
||||
SELECT * FROM update_and_get_stats();
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
@@ -1,46 +0,0 @@
|
||||
-- Add pokedex_entries_mapping table to explicitly define which entries belong to each pokedex
|
||||
-- This fixes the stats functions ambiguity issue by providing an explicit definition of expected entries
|
||||
|
||||
-- Create pokedex_entries_mapping table
|
||||
CREATE TABLE pokedex_entries_mapping (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
"pokedexId" UUID NOT NULL REFERENCES pokedexes(id) ON DELETE CASCADE,
|
||||
"pokedexEntryId" BIGINT NOT NULL REFERENCES pokedex_entries(id) ON DELETE CASCADE,
|
||||
UNIQUE("pokedexId", "pokedexEntryId")
|
||||
);
|
||||
|
||||
-- Create indexes for performance
|
||||
CREATE INDEX idx_pokedex_entries_mapping_pokedex_id ON pokedex_entries_mapping("pokedexId");
|
||||
CREATE INDEX idx_pokedex_entries_mapping_entry_id ON pokedex_entries_mapping("pokedexEntryId");
|
||||
|
||||
-- Enable RLS
|
||||
ALTER TABLE pokedex_entries_mapping ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- RLS Policies
|
||||
|
||||
-- Public read access (mapping is reference data)
|
||||
CREATE POLICY "Anyone can view pokedex entries mapping"
|
||||
ON pokedex_entries_mapping
|
||||
FOR SELECT USING (true);
|
||||
|
||||
-- Users can only insert mappings for their own pokedexes
|
||||
CREATE POLICY "Users can insert own pokedex mappings"
|
||||
ON pokedex_entries_mapping
|
||||
FOR INSERT WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM pokedexes
|
||||
WHERE pokedexes.id = pokedex_entries_mapping."pokedexId"
|
||||
AND pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- Users can only delete mappings for their own pokedexes
|
||||
CREATE POLICY "Users can delete own pokedex mappings"
|
||||
ON pokedex_entries_mapping
|
||||
FOR DELETE USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM pokedexes
|
||||
WHERE pokedexes.id = pokedex_entries_mapping."pokedexId"
|
||||
AND pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
@@ -1,24 +0,0 @@
|
||||
-- Populate pokedex_entries_mapping for existing pokedexes
|
||||
-- This is a one-time migration to backfill data for pokedexes created before the mapping table
|
||||
|
||||
-- Insert mappings for all existing pokedexes
|
||||
-- Apply the same filtering logic that the application uses to determine expected entries
|
||||
INSERT INTO pokedex_entries_mapping ("pokedexId", "pokedexEntryId")
|
||||
SELECT
|
||||
p.id AS "pokedexId",
|
||||
pe.id AS "pokedexEntryId"
|
||||
FROM pokedexes p
|
||||
LEFT JOIN region_game_mappings rg ON rg.game = p."gameScope"
|
||||
CROSS JOIN pokedex_entries pe
|
||||
WHERE
|
||||
-- Form filter: if isFormDex is false, only include base forms
|
||||
-- Base forms have form IS NULL, except Unown which has no base form (use 'A')
|
||||
(p."isFormDex" = true OR (pe.form IS NULL OR (pe.pokemon = 'Unown' AND pe.form = 'A')))
|
||||
-- Game scope filter: if gameScope is specified, filter by game
|
||||
AND (p."gameScope" IS NULL OR pe."gamesToCatchIn" @> ARRAY[p."gameScope"]::TEXT[])
|
||||
-- Region filter: only enforce when a mapping exists
|
||||
AND (p."gameScope" IS NULL OR rg.region IS NULL OR pe."regionToCatchIn" = rg.region)
|
||||
ON CONFLICT ("pokedexId", "pokedexEntryId") DO NOTHING;
|
||||
|
||||
-- Add comment to document this migration
|
||||
COMMENT ON TABLE pokedex_entries_mapping IS 'Junction table defining which pokedex_entries belong to each pokedex. Used for accurate stats calculation.';
|
||||
@@ -1,44 +0,0 @@
|
||||
-- Create function to atomically recalculate pokedex entries mapping
|
||||
-- This function replaces the two-step delete+insert process with a single atomic operation
|
||||
-- to prevent orphaned pokedexes if repopulation fails or yields an empty list
|
||||
|
||||
CREATE OR REPLACE FUNCTION recalculate_pokedex_mappings(
|
||||
p_pokedex_id UUID,
|
||||
p_entry_ids BIGINT[]
|
||||
)
|
||||
RETURNS VOID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public, pg_temp
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_user_id UUID;
|
||||
BEGIN
|
||||
-- Validate that entry_ids is not empty to avoid accidental deletion
|
||||
IF p_entry_ids IS NULL OR array_length(p_entry_ids, 1) IS NULL THEN
|
||||
RAISE EXCEPTION 'entry_ids cannot be null or empty';
|
||||
END IF;
|
||||
|
||||
-- Verify that the caller owns the target pokedex
|
||||
SELECT "userId" INTO v_user_id
|
||||
FROM pokedexes
|
||||
WHERE id = p_pokedex_id;
|
||||
|
||||
IF v_user_id IS NULL THEN
|
||||
RAISE EXCEPTION 'pokedex not found';
|
||||
END IF;
|
||||
|
||||
IF auth.uid() IS NULL OR v_user_id IS DISTINCT FROM auth.uid() THEN
|
||||
RAISE EXCEPTION 'not authorized: you do not own this pokedex';
|
||||
END IF;
|
||||
|
||||
-- Delete old mappings and insert new mappings in a single transaction
|
||||
-- This ensures atomicity - either both operations succeed or both fail
|
||||
DELETE FROM pokedex_entries_mapping
|
||||
WHERE "pokedexId" = p_pokedex_id;
|
||||
|
||||
INSERT INTO pokedex_entries_mapping ("pokedexId", "pokedexEntryId")
|
||||
SELECT p_pokedex_id, unnest(p_entry_ids)
|
||||
ON CONFLICT ("pokedexId", "pokedexEntryId") DO NOTHING;
|
||||
END;
|
||||
$$;
|
||||
@@ -1,16 +0,0 @@
|
||||
-- Fix RLS SELECT policy on pokedex_entries_mapping to restrict reads to owning user
|
||||
-- This prevents exposing all user mappings and ensures consistency with INSERT/DELETE policies
|
||||
|
||||
-- Drop the overly permissive public SELECT policy
|
||||
DROP POLICY IF EXISTS "Anyone can view pokedex entries mapping" ON pokedex_entries_mapping;
|
||||
|
||||
-- Create a new SELECT policy that restricts reads to the owning user
|
||||
CREATE POLICY "Users can view own pokedex entries mapping"
|
||||
ON pokedex_entries_mapping
|
||||
FOR SELECT USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM pokedexes
|
||||
WHERE pokedexes.id = pokedex_entries_mapping."pokedexId"
|
||||
AND pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
@@ -0,0 +1,212 @@
|
||||
-- Normalize reference data schema to match data/csvs/*.csv
|
||||
--
|
||||
-- Target tables (reference data):
|
||||
-- - regions
|
||||
-- - games (add regionId FK, keep existing columns)
|
||||
-- - pokemon (1 row per pokedexNumber + form, matching data/csvs/pokemon.csv)
|
||||
-- - pokemon_origin_games (join table)
|
||||
-- - region_game_mappings (join table)
|
||||
--
|
||||
-- Also migrates user data table catch_records to reference pokemon instead of pokedex_entries.
|
||||
|
||||
-- 1) Drop tables that are being replaced
|
||||
--
|
||||
-- NOTE: We intentionally keep auth.users and user-owned pokedexes.
|
||||
-- Any existing catch_records will be wiped because the foreign key target changes.
|
||||
|
||||
TRUNCATE TABLE catch_records;
|
||||
|
||||
-- Drop old mapping table (depends on pokedex_entries)
|
||||
DROP TABLE IF EXISTS pokedex_entries_mapping;
|
||||
|
||||
-- Drop old regional dex table (per approved plan)
|
||||
DROP TABLE IF EXISTS regional_dex_numbers;
|
||||
|
||||
-- Drop old region-game mappings (string-based)
|
||||
DROP TABLE IF EXISTS region_game_mappings;
|
||||
|
||||
-- Drop old pokedex entries table (legacy, replaced by pokemon)
|
||||
DROP TABLE IF EXISTS pokedex_entries;
|
||||
|
||||
-- 2) Regions
|
||||
CREATE TABLE IF NOT EXISTS regions (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
name TEXT NOT NULL UNIQUE,
|
||||
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
|
||||
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
ALTER TABLE regions ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY "Regions are publicly readable" ON regions
|
||||
FOR SELECT TO public USING (true);
|
||||
|
||||
CREATE TRIGGER update_regions_updated_at
|
||||
BEFORE UPDATE ON regions
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- 3) Games: keep existing id + displayName, add regionId FK
|
||||
ALTER TABLE games
|
||||
ADD COLUMN IF NOT EXISTS "regionId" BIGINT;
|
||||
|
||||
ALTER TABLE games
|
||||
ADD CONSTRAINT games_region_id_fkey
|
||||
FOREIGN KEY ("regionId") REFERENCES regions(id)
|
||||
ON DELETE RESTRICT;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_games_region_id ON games("regionId");
|
||||
|
||||
-- 4) Region ↔ Game mapping (normalized)
|
||||
CREATE TABLE IF NOT EXISTS region_game_mappings (
|
||||
"regionId" BIGINT NOT NULL REFERENCES regions(id) ON DELETE CASCADE,
|
||||
"gameId" TEXT NOT NULL REFERENCES games(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY ("regionId", "gameId")
|
||||
);
|
||||
|
||||
ALTER TABLE region_game_mappings ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY "Region-game mappings are publicly readable" ON region_game_mappings
|
||||
FOR SELECT TO public USING (true);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_region_game_mappings_game_id ON region_game_mappings("gameId");
|
||||
|
||||
-- 5) Pokemon (1 row per pokedexNumber + form)
|
||||
CREATE TABLE IF NOT EXISTS pokemon (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
"pokedexNumber" INTEGER NOT NULL,
|
||||
pokemon TEXT NOT NULL,
|
||||
form TEXT,
|
||||
"originRegionId" BIGINT NOT NULL REFERENCES regions(id) ON DELETE RESTRICT,
|
||||
"canGigantamax" BOOLEAN DEFAULT FALSE,
|
||||
"createdAt" TIMESTAMPTZ DEFAULT NOW(),
|
||||
"updatedAt" TIMESTAMPTZ DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- Uniqueness: exactly one "base" (form IS NULL) per pokedex number
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_pokemon_base_form
|
||||
ON pokemon("pokedexNumber")
|
||||
WHERE form IS NULL;
|
||||
|
||||
-- Uniqueness: for non-null forms, unique per (pokedexNumber, form)
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS uniq_pokemon_number_form
|
||||
ON pokemon("pokedexNumber", form)
|
||||
WHERE form IS NOT NULL;
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_pokemon_pokedex_number ON pokemon("pokedexNumber");
|
||||
CREATE INDEX IF NOT EXISTS idx_pokemon_name ON pokemon(pokemon);
|
||||
CREATE INDEX IF NOT EXISTS idx_pokemon_origin_region_id ON pokemon("originRegionId");
|
||||
|
||||
ALTER TABLE pokemon ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY "Pokemon are publicly readable" ON pokemon
|
||||
FOR SELECT TO public USING (true);
|
||||
|
||||
CREATE TRIGGER update_pokemon_updated_at
|
||||
BEFORE UPDATE ON pokemon
|
||||
FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
|
||||
|
||||
-- 6) Pokemon ↔ origin games (normalized)
|
||||
CREATE TABLE IF NOT EXISTS pokemon_origin_games (
|
||||
"pokemonId" BIGINT NOT NULL REFERENCES pokemon(id) ON DELETE CASCADE,
|
||||
"gameId" TEXT NOT NULL REFERENCES games(id) ON DELETE CASCADE,
|
||||
PRIMARY KEY ("pokemonId", "gameId")
|
||||
);
|
||||
|
||||
ALTER TABLE pokemon_origin_games ENABLE ROW LEVEL SECURITY;
|
||||
CREATE POLICY "Pokemon origin games are publicly readable" ON pokemon_origin_games
|
||||
FOR SELECT TO public USING (true);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_pokemon_origin_games_game_id ON pokemon_origin_games("gameId");
|
||||
|
||||
-- 6.1) Compatibility view: keep the app working while refactoring
|
||||
--
|
||||
-- This view matches the old pokedex_entries shape used by the app:
|
||||
-- - id (BIGINT)
|
||||
-- - "pokedexNumber"
|
||||
-- - pokemon
|
||||
-- - form
|
||||
-- - "canGigantamax"
|
||||
-- - "regionToCatchIn" (region name)
|
||||
-- - "gamesToCatchIn" (TEXT[] of game display names)
|
||||
-- - "createdAt" / "updatedAt"
|
||||
--
|
||||
-- Note: read-only. Inserts/updates should target the new tables.
|
||||
CREATE OR REPLACE VIEW pokedex_entries AS
|
||||
SELECT
|
||||
p.id,
|
||||
p."pokedexNumber",
|
||||
p.pokemon,
|
||||
p.form,
|
||||
p."canGigantamax",
|
||||
r.name AS "regionToCatchIn",
|
||||
COALESCE(
|
||||
ARRAY_AGG(g."displayName" ORDER BY g."displayName") FILTER (WHERE g.id IS NOT NULL),
|
||||
ARRAY[]::TEXT[]
|
||||
) AS "gamesToCatchIn",
|
||||
p."createdAt",
|
||||
p."updatedAt"
|
||||
FROM pokemon p
|
||||
JOIN regions r ON r.id = p."originRegionId"
|
||||
LEFT JOIN pokemon_origin_games pog ON pog."pokemonId" = p.id
|
||||
LEFT JOIN games g ON g.id = pog."gameId"
|
||||
GROUP BY p.id, r.name;
|
||||
|
||||
-- RLS: views respect underlying table policies; keep it explicitly public readable
|
||||
GRANT SELECT ON pokedex_entries TO anon, authenticated;
|
||||
|
||||
-- 7) Recreate pokedex mapping table for expected entries
|
||||
-- (same intent as old pokedex_entries_mapping, but points at pokemon.id)
|
||||
CREATE TABLE IF NOT EXISTS pokedex_pokemon_mapping (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
"pokedexId" UUID NOT NULL REFERENCES pokedexes(id) ON DELETE CASCADE,
|
||||
"pokemonId" BIGINT NOT NULL REFERENCES pokemon(id) ON DELETE CASCADE,
|
||||
UNIQUE("pokedexId", "pokemonId")
|
||||
);
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_pokedex_pokemon_mapping_pokedex_id
|
||||
ON pokedex_pokemon_mapping("pokedexId");
|
||||
CREATE INDEX IF NOT EXISTS idx_pokedex_pokemon_mapping_pokemon_id
|
||||
ON pokedex_pokemon_mapping("pokemonId");
|
||||
|
||||
ALTER TABLE pokedex_pokemon_mapping ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY "Anyone can view pokedex pokemon mapping"
|
||||
ON pokedex_pokemon_mapping
|
||||
FOR SELECT USING (true);
|
||||
|
||||
CREATE POLICY "Users can insert own pokedex pokemon mappings"
|
||||
ON pokedex_pokemon_mapping
|
||||
FOR INSERT WITH CHECK (
|
||||
EXISTS (
|
||||
SELECT 1 FROM pokedexes
|
||||
WHERE pokedexes.id = pokedex_pokemon_mapping."pokedexId"
|
||||
AND pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
CREATE POLICY "Users can delete own pokedex pokemon mappings"
|
||||
ON pokedex_pokemon_mapping
|
||||
FOR DELETE USING (
|
||||
EXISTS (
|
||||
SELECT 1 FROM pokedexes
|
||||
WHERE pokedexes.id = pokedex_pokemon_mapping."pokedexId"
|
||||
AND pokedexes."userId" = auth.uid()
|
||||
)
|
||||
);
|
||||
|
||||
-- 8) Update catch_records to reference pokemon instead of pokedex_entries
|
||||
ALTER TABLE catch_records
|
||||
DROP COLUMN IF EXISTS "pokedexEntryId";
|
||||
|
||||
ALTER TABLE catch_records
|
||||
ADD COLUMN IF NOT EXISTS "pokemonId" BIGINT REFERENCES pokemon(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE catch_records
|
||||
ALTER COLUMN "pokemonId" SET NOT NULL;
|
||||
|
||||
-- Drop old unique constraint (name may vary across environments)
|
||||
ALTER TABLE catch_records
|
||||
DROP CONSTRAINT IF EXISTS catch_records_user_pokemon_pokedex_unique;
|
||||
|
||||
ALTER TABLE catch_records
|
||||
ADD CONSTRAINT catch_records_user_pokemon_pokedex_unique
|
||||
UNIQUE("userId", "pokemonId", "pokedexId");
|
||||
|
||||
CREATE INDEX IF NOT EXISTS idx_catch_records_pokemon_id ON catch_records("pokemonId");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,137 @@
|
||||
-- Seed regions + games + region_game_mappings from CSVs
|
||||
-- Auto-generated from data/csvs/regions.csv and data/csvs/games.csv
|
||||
|
||||
-- Regions
|
||||
INSERT INTO regions (name) VALUES
|
||||
('Kanto'),
|
||||
('Johto'),
|
||||
('Hoenn'),
|
||||
('Sinnoh'),
|
||||
('Unova'),
|
||||
('Galar'),
|
||||
('Alola'),
|
||||
('Kalos'),
|
||||
('Hisui'),
|
||||
('Paldea'),
|
||||
('Go'),
|
||||
('Home'),
|
||||
('Orre'),
|
||||
('Ranch')
|
||||
ON CONFLICT (name) DO UPDATE SET
|
||||
"updatedAt" = NOW();
|
||||
|
||||
-- Games
|
||||
INSERT INTO games (id, "displayName", region, generation, "releaseYear", "regionId") VALUES
|
||||
('red', 'Red', 'Kanto', 1, 1996, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('blue', 'Blue', 'Kanto', 1, 1996, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('yellow', 'Yellow', 'Kanto', 1, 1998, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('gold', 'Gold', 'Johto', 2, 1999, (SELECT id FROM regions WHERE name = 'Johto')),
|
||||
('silver', 'Silver', 'Johto', 2, 1999, (SELECT id FROM regions WHERE name = 'Johto')),
|
||||
('crystal', 'Crystal', 'Johto', 2, 2000, (SELECT id FROM regions WHERE name = 'Johto')),
|
||||
('ruby', 'Ruby', 'Hoenn', 3, 2002, (SELECT id FROM regions WHERE name = 'Hoenn')),
|
||||
('sapphire', 'Sapphire', 'Hoenn', 3, 2002, (SELECT id FROM regions WHERE name = 'Hoenn')),
|
||||
('colosseum', 'Colosseum', 'Orre', 3, 2003, (SELECT id FROM regions WHERE name = 'Orre')),
|
||||
('emerald', 'Emerald', 'Hoenn', 3, 2004, (SELECT id FROM regions WHERE name = 'Hoenn')),
|
||||
('firered', 'FireRed', 'Kanto', 1, 2004, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('leafgreen', 'LeafGreen', 'Kanto', 1, 2004, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('xd-gale-of-darkness', 'XD: Gale of Darkness', 'Orre', 3, 2005, (SELECT id FROM regions WHERE name = 'Orre')),
|
||||
('diamond', 'Diamond', 'Sinnoh', 4, 2006, (SELECT id FROM regions WHERE name = 'Sinnoh')),
|
||||
('pearl', 'Pearl', 'Sinnoh', 4, 2006, (SELECT id FROM regions WHERE name = 'Sinnoh')),
|
||||
('platinum', 'Platinum', 'Sinnoh', 4, 2008, (SELECT id FROM regions WHERE name = 'Sinnoh')),
|
||||
('ranch', 'Ranch', 'Ranch', 4, 2008, (SELECT id FROM regions WHERE name = 'Ranch')),
|
||||
('heart-gold', 'Heart Gold', 'Johto', 2, 2009, (SELECT id FROM regions WHERE name = 'Johto')),
|
||||
('soul-silver', 'Soul Silver', 'Johto', 2, 2009, (SELECT id FROM regions WHERE name = 'Johto')),
|
||||
('black', 'Black', 'Unova', 5, 2010, (SELECT id FROM regions WHERE name = 'Unova')),
|
||||
('white', 'White', 'Unova', 5, 2010, (SELECT id FROM regions WHERE name = 'Unova')),
|
||||
('black-2', 'Black 2', 'Unova', 5, 2012, (SELECT id FROM regions WHERE name = 'Unova')),
|
||||
('white-2', 'White 2', 'Unova', 5, 2012, (SELECT id FROM regions WHERE name = 'Unova')),
|
||||
('dream-radar', 'Dream Radar', 'Unova', 5, 2012, (SELECT id FROM regions WHERE name = 'Unova')),
|
||||
('x', 'X', 'Kalos', 6, 2013, (SELECT id FROM regions WHERE name = 'Kalos')),
|
||||
('y', 'Y', 'Kalos', 6, 2013, (SELECT id FROM regions WHERE name = 'Kalos')),
|
||||
('omega-ruby', 'Omega Ruby', 'Hoenn', 3, 2014, (SELECT id FROM regions WHERE name = 'Hoenn')),
|
||||
('alpha-sapphire', 'Alpha Sapphire', 'Hoenn', 3, 2014, (SELECT id FROM regions WHERE name = 'Hoenn')),
|
||||
('sun', 'Sun', 'Alola', 7, 2016, (SELECT id FROM regions WHERE name = 'Alola')),
|
||||
('moon', 'Moon', 'Alola', 7, 2016, (SELECT id FROM regions WHERE name = 'Alola')),
|
||||
('moon-(demo)', 'Moon (demo)', 'Alola', 7, 2016, (SELECT id FROM regions WHERE name = 'Alola')),
|
||||
('go', 'Go', 'Go', 7, 2016, (SELECT id FROM regions WHERE name = 'Go')),
|
||||
('ultra-sun', 'Ultra Sun', 'Alola', 7, 2017, (SELECT id FROM regions WHERE name = 'Alola')),
|
||||
('ultra-moon', 'Ultra Moon', 'Alola', 7, 2017, (SELECT id FROM regions WHERE name = 'Alola')),
|
||||
('lg-pikachu', 'LG: Pikachu', 'Kanto', 1, 2018, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('lg-eevee', 'LG: Eevee', 'Kanto', 1, 2018, (SELECT id FROM regions WHERE name = 'Kanto')),
|
||||
('sword', 'Sword', 'Galar', 8, 2019, (SELECT id FROM regions WHERE name = 'Galar')),
|
||||
('shield', 'Shield', 'Galar', 8, 2019, (SELECT id FROM regions WHERE name = 'Galar')),
|
||||
('home', 'Home', 'Home', 8, 2020, (SELECT id FROM regions WHERE name = 'Home')),
|
||||
('brilliant-diamond', 'Brilliant Diamond', 'Sinnoh', 4, 2021, (SELECT id FROM regions WHERE name = 'Sinnoh')),
|
||||
('shining-pearl', 'Shining Pearl', 'Sinnoh', 4, 2021, (SELECT id FROM regions WHERE name = 'Sinnoh')),
|
||||
('legends-arceus', 'Legends: Arceus', 'Hisui', 8, 2022, (SELECT id FROM regions WHERE name = 'Hisui')),
|
||||
('scarlet', 'Scarlet', 'Paldea', 9, 2022, (SELECT id FROM regions WHERE name = 'Paldea')),
|
||||
('violet', 'Violet', 'Paldea', 9, 2022, (SELECT id FROM regions WHERE name = 'Paldea')),
|
||||
('legends-z-a', 'Legends: Z-A', 'Kalos', 6, 2025, (SELECT id FROM regions WHERE name = 'Kalos'))
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
"displayName" = EXCLUDED."displayName",
|
||||
region = EXCLUDED.region,
|
||||
generation = EXCLUDED.generation,
|
||||
"releaseYear" = EXCLUDED."releaseYear",
|
||||
"regionId" = EXCLUDED."regionId",
|
||||
"updatedAt" = NOW();
|
||||
|
||||
-- Region ↔ game mappings
|
||||
INSERT INTO region_game_mappings ("regionId", "gameId") VALUES
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'red'),
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'blue'),
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'yellow'),
|
||||
((SELECT id FROM regions WHERE name = 'Johto'), 'gold'),
|
||||
((SELECT id FROM regions WHERE name = 'Johto'), 'silver'),
|
||||
((SELECT id FROM regions WHERE name = 'Johto'), 'crystal'),
|
||||
((SELECT id FROM regions WHERE name = 'Hoenn'), 'ruby'),
|
||||
((SELECT id FROM regions WHERE name = 'Hoenn'), 'sapphire'),
|
||||
((SELECT id FROM regions WHERE name = 'Orre'), 'colosseum'),
|
||||
((SELECT id FROM regions WHERE name = 'Hoenn'), 'emerald'),
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'firered'),
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'leafgreen'),
|
||||
((SELECT id FROM regions WHERE name = 'Orre'), 'xd-gale-of-darkness'),
|
||||
((SELECT id FROM regions WHERE name = 'Sinnoh'), 'diamond'),
|
||||
((SELECT id FROM regions WHERE name = 'Sinnoh'), 'pearl'),
|
||||
((SELECT id FROM regions WHERE name = 'Sinnoh'), 'platinum'),
|
||||
((SELECT id FROM regions WHERE name = 'Ranch'), 'ranch'),
|
||||
((SELECT id FROM regions WHERE name = 'Johto'), 'heart-gold'),
|
||||
((SELECT id FROM regions WHERE name = 'Johto'), 'soul-silver'),
|
||||
((SELECT id FROM regions WHERE name = 'Unova'), 'black'),
|
||||
((SELECT id FROM regions WHERE name = 'Unova'), 'white'),
|
||||
((SELECT id FROM regions WHERE name = 'Unova'), 'black-2'),
|
||||
((SELECT id FROM regions WHERE name = 'Unova'), 'white-2'),
|
||||
((SELECT id FROM regions WHERE name = 'Unova'), 'dream-radar'),
|
||||
((SELECT id FROM regions WHERE name = 'Kalos'), 'x'),
|
||||
((SELECT id FROM regions WHERE name = 'Kalos'), 'y'),
|
||||
((SELECT id FROM regions WHERE name = 'Hoenn'), 'omega-ruby'),
|
||||
((SELECT id FROM regions WHERE name = 'Hoenn'), 'alpha-sapphire'),
|
||||
((SELECT id FROM regions WHERE name = 'Alola'), 'sun'),
|
||||
((SELECT id FROM regions WHERE name = 'Alola'), 'moon'),
|
||||
((SELECT id FROM regions WHERE name = 'Alola'), 'moon-(demo)'),
|
||||
((SELECT id FROM regions WHERE name = 'Go'), 'go'),
|
||||
((SELECT id FROM regions WHERE name = 'Alola'), 'ultra-sun'),
|
||||
((SELECT id FROM regions WHERE name = 'Alola'), 'ultra-moon'),
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'lg-pikachu'),
|
||||
((SELECT id FROM regions WHERE name = 'Kanto'), 'lg-eevee'),
|
||||
((SELECT id FROM regions WHERE name = 'Galar'), 'sword'),
|
||||
((SELECT id FROM regions WHERE name = 'Galar'), 'shield'),
|
||||
((SELECT id FROM regions WHERE name = 'Home'), 'home'),
|
||||
((SELECT id FROM regions WHERE name = 'Sinnoh'), 'brilliant-diamond'),
|
||||
((SELECT id FROM regions WHERE name = 'Sinnoh'), 'shining-pearl'),
|
||||
((SELECT id FROM regions WHERE name = 'Hisui'), 'legends-arceus'),
|
||||
((SELECT id FROM regions WHERE name = 'Paldea'), 'scarlet'),
|
||||
((SELECT id FROM regions WHERE name = 'Paldea'), 'violet'),
|
||||
((SELECT id FROM regions WHERE name = 'Kalos'), 'legends-z-a')
|
||||
ON CONFLICT ("regionId", "gameId") DO NOTHING;
|
||||
|
||||
-- Add metadata
|
||||
INSERT INTO metadata (key, value) VALUES
|
||||
('regions_seeded', 'true'),
|
||||
('regions_seed_date', NOW()::TEXT),
|
||||
('regions_count', '14'),
|
||||
('games_seeded', 'true'),
|
||||
('games_seed_date', NOW()::TEXT),
|
||||
('games_count', '45')
|
||||
ON CONFLICT (key) DO UPDATE SET
|
||||
value = EXCLUDED.value,
|
||||
"updatedAt" = NOW();
|
||||
+53
-19
@@ -1,9 +1,48 @@
|
||||
-- Fix ambiguous column reference errors in stats functions.
|
||||
-- Update stats + mapping functions to use the new normalized schema.
|
||||
--
|
||||
-- If earlier migrations have already been applied, editing them will not update
|
||||
-- the deployed database. This migration re-defines the functions using
|
||||
-- CREATE OR REPLACE so the corrected definitions take effect.
|
||||
-- After [`supabase/migrations/20260116210000_normalize_csv_schema.sql`](supabase/migrations/20260116210000_normalize_csv_schema.sql:1):
|
||||
-- - catch_records references "pokemonId" (not "pokedexEntryId")
|
||||
-- - explicit expected entries table is pokedex_pokemon_mapping (not pokedex_entries_mapping)
|
||||
|
||||
-- 1) Recalculate function: same name/signature, but targets pokedex_pokemon_mapping.
|
||||
CREATE OR REPLACE FUNCTION recalculate_pokedex_mappings(
|
||||
p_pokedex_id UUID,
|
||||
p_entry_ids BIGINT[]
|
||||
)
|
||||
RETURNS VOID
|
||||
SECURITY DEFINER
|
||||
SET search_path = public, pg_temp
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
v_user_id UUID;
|
||||
BEGIN
|
||||
IF p_entry_ids IS NULL OR array_length(p_entry_ids, 1) IS NULL THEN
|
||||
RAISE EXCEPTION 'entry_ids cannot be null or empty';
|
||||
END IF;
|
||||
|
||||
SELECT "userId" INTO v_user_id
|
||||
FROM pokedexes
|
||||
WHERE id = p_pokedex_id;
|
||||
|
||||
IF v_user_id IS NULL THEN
|
||||
RAISE EXCEPTION 'pokedex not found';
|
||||
END IF;
|
||||
|
||||
IF auth.uid() IS NULL OR v_user_id IS DISTINCT FROM auth.uid() THEN
|
||||
RAISE EXCEPTION 'not authorized: you do not own this pokedex';
|
||||
END IF;
|
||||
|
||||
DELETE FROM pokedex_pokemon_mapping
|
||||
WHERE "pokedexId" = p_pokedex_id;
|
||||
|
||||
INSERT INTO pokedex_pokemon_mapping ("pokedexId", "pokemonId")
|
||||
SELECT p_pokedex_id, unnest(p_entry_ids)
|
||||
ON CONFLICT ("pokedexId", "pokemonId") DO NOTHING;
|
||||
END;
|
||||
$$;
|
||||
|
||||
-- 2) Stats functions: completed pokedexes are those where all expected pokemon are caught.
|
||||
CREATE OR REPLACE FUNCTION update_and_get_stats()
|
||||
RETURNS TABLE (
|
||||
pokemon_caught BIGINT,
|
||||
@@ -12,6 +51,7 @@ RETURNS TABLE (
|
||||
updated_at TIMESTAMPTZ
|
||||
)
|
||||
SECURITY DEFINER
|
||||
SET search_path = public, pg_temp
|
||||
LANGUAGE plpgsql
|
||||
AS $$
|
||||
DECLARE
|
||||
@@ -20,31 +60,29 @@ DECLARE
|
||||
v_completed_pokedexes BIGINT;
|
||||
v_updated_at TIMESTAMPTZ := NOW();
|
||||
BEGIN
|
||||
-- Calculate current stats: count of caught Pokémon
|
||||
SELECT COUNT(*) INTO v_pokemon_caught
|
||||
FROM catch_records
|
||||
WHERE caught = true;
|
||||
|
||||
-- Calculate current stats: count of total users
|
||||
SELECT COUNT(*) INTO v_total_users
|
||||
FROM auth.users;
|
||||
|
||||
-- Calculate current stats: count of completed pokedexes
|
||||
-- A pokedex is completed when all its expected entries have caught = true
|
||||
-- Join catch_records to pokedex_entries_mapping to validate against explicit expected entries
|
||||
SELECT COUNT(*) INTO v_completed_pokedexes
|
||||
FROM (
|
||||
SELECT cr."pokedexId"
|
||||
FROM catch_records cr
|
||||
INNER JOIN pokedex_entries_mapping pem
|
||||
ON cr."pokedexId" = pem."pokedexId"
|
||||
AND cr."pokedexEntryId" = pem."pokedexEntryId"
|
||||
INNER JOIN pokedex_pokemon_mapping ppm
|
||||
ON cr."pokedexId" = ppm."pokedexId"
|
||||
AND cr."pokemonId" = ppm."pokemonId"
|
||||
GROUP BY cr."pokedexId"
|
||||
HAVING COUNT(*) = COUNT(*) FILTER (WHERE cr.caught = true)
|
||||
AND COUNT(*) = (SELECT COUNT(*) FROM pokedex_entries_mapping WHERE "pokedexId" = cr."pokedexId")
|
||||
AND COUNT(*) = (
|
||||
SELECT COUNT(*)
|
||||
FROM pokedex_pokemon_mapping
|
||||
WHERE "pokedexId" = cr."pokedexId"
|
||||
)
|
||||
) completed;
|
||||
|
||||
-- Update cache using UPSERT pattern
|
||||
INSERT INTO stats_cache (id, pokemon_caught, total_users, completed_pokedexes, updated_at)
|
||||
VALUES (1, v_pokemon_caught, v_total_users, v_completed_pokedexes, v_updated_at)
|
||||
ON CONFLICT (id) DO UPDATE
|
||||
@@ -53,13 +91,11 @@ BEGIN
|
||||
completed_pokedexes = EXCLUDED.completed_pokedexes,
|
||||
updated_at = v_updated_at;
|
||||
|
||||
-- Return stats
|
||||
RETURN QUERY
|
||||
SELECT v_pokemon_caught, v_total_users, v_completed_pokedexes, v_updated_at AS updated_at;
|
||||
END;
|
||||
$$;
|
||||
|
||||
|
||||
CREATE OR REPLACE FUNCTION get_public_stats()
|
||||
RETURNS TABLE (
|
||||
pokemon_caught BIGINT,
|
||||
@@ -73,23 +109,21 @@ AS $$
|
||||
DECLARE
|
||||
v_cache_exists BOOLEAN;
|
||||
BEGIN
|
||||
-- Check if cache exists and is fresh (within 24 hours)
|
||||
SELECT EXISTS(
|
||||
SELECT 1 FROM stats_cache
|
||||
WHERE stats_cache.updated_at > NOW() - INTERVAL '24 hours'
|
||||
) INTO v_cache_exists;
|
||||
|
||||
IF v_cache_exists THEN
|
||||
-- Return cached stats (qualify updated_at to avoid ambiguity with output parameter)
|
||||
RETURN QUERY
|
||||
SELECT sc.pokemon_caught, sc.total_users, sc.completed_pokedexes, sc.updated_at
|
||||
FROM stats_cache sc
|
||||
ORDER BY sc.updated_at DESC
|
||||
LIMIT 1;
|
||||
ELSE
|
||||
-- Cache is stale or doesn't exist, update it
|
||||
RETURN QUERY
|
||||
SELECT * FROM update_and_get_stats();
|
||||
END IF;
|
||||
END;
|
||||
$$;
|
||||
|
||||
Reference in New Issue
Block a user