From a26f38bca19aaab9bacc0798eafcfc445ae7823a Mon Sep 17 00:00:00 2001 From: Josh Creek <8179928+jcreek@users.noreply.github.com> Date: Sat, 17 Jan 2026 21:08:21 +0000 Subject: [PATCH] data(*): Improve ordering of forms --- data/csvs/regions.csv | 30 +++++++------- .../repositories/CombinedDataRepository.ts | 9 +++-- .../migrations/20260118000000_init_schema.sql | 39 ++++++++++++++++++- .../20260118001000_seed_reference_data.sql | 34 ++++++++-------- 4 files changed, 76 insertions(+), 36 deletions(-) diff --git a/data/csvs/regions.csv b/data/csvs/regions.csv index c99f075..3efd6b9 100644 --- a/data/csvs/regions.csv +++ b/data/csvs/regions.csv @@ -1,15 +1,15 @@ -region -Kanto -Johto -Hoenn -Sinnoh -Unova -Galar -Alola -Kalos -Hisui -Paldea -Go -Home -Orre -Ranch \ No newline at end of file +region,releaseOrder +Kanto,1 +Johto,2 +Hoenn,3 +Orre,4 +Sinnoh,5 +Ranch,6 +Unova,7 +Kalos,8 +Alola,9 +Go,10 +Galar,11 +Home,12 +Hisui,13 +Paldea,14 diff --git a/src/lib/repositories/CombinedDataRepository.ts b/src/lib/repositories/CombinedDataRepository.ts index 61988dd..4b239b7 100644 --- a/src/lib/repositories/CombinedDataRepository.ts +++ b/src/lib/repositories/CombinedDataRepository.ts @@ -59,10 +59,14 @@ class CombinedDataRepository { query = query.contains('gamesToCatchIn', [game]); } - // Stable ordering: national dex number, then base form first, then form name. + // Stable ordering from the database: national dex, Unown order, base/female/temporal, then form label. query = query .order('pokedexNumber', { ascending: true }) - .order('form', { ascending: true, nullsFirst: true }); + .order('unownSortOrder', { ascending: true }) + .order('formSortBucket', { ascending: true }) + .order('formSortRegionOrder', { ascending: true }) + .order('formSortRegionalSub', { ascending: true }) + .order('formSortLabel', { ascending: true }); return query; } @@ -220,7 +224,6 @@ class CombinedDataRepository { ): Promise { const from = (page - 1) * limit; const to = from + limit - 1; - const entries = await this.fetchEntriesByRange(from, to, enableForms, region, game); if (!entries || entries.length === 0) { diff --git a/supabase/migrations/20260118000000_init_schema.sql b/supabase/migrations/20260118000000_init_schema.sql index 90dc0f4..c04235f 100644 --- a/supabase/migrations/20260118000000_init_schema.sql +++ b/supabase/migrations/20260118000000_init_schema.sql @@ -16,6 +16,7 @@ $$ LANGUAGE plpgsql; CREATE TABLE regions ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL UNIQUE, + "releaseOrder" INTEGER NOT NULL, "createdAt" TIMESTAMPTZ DEFAULT NOW(), "updatedAt" TIMESTAMPTZ DEFAULT NOW() ); @@ -283,6 +284,7 @@ SELECT p.form, p."canGigantamax", r.name AS "regionToCatchIn", + r."releaseOrder" AS "regionReleaseOrder", COALESCE( ARRAY_AGG(g."displayName" ORDER BY g."displayName") FILTER (WHERE g.id IS NOT NULL), ARRAY[]::TEXT[] @@ -291,12 +293,45 @@ SELECT p."evolutionInformation", p."catchInformation", p."createdAt", - p."updatedAt" + p."updatedAt", + CASE + WHEN p.form IS NULL OR lower(p.form) = 'male' THEN 0 + WHEN lower(p.form) = 'female' THEN 1 + WHEN lower(p.form) LIKE '%alolan%' + OR lower(p.form) LIKE '%galarian%' + OR lower(p.form) LIKE '%hisuian%' + OR lower(p.form) LIKE '%paldean%' + THEN 2 + ELSE 3 + END AS "formSortBucket", + CASE + WHEN lower(p.form) LIKE '%alolan%' + OR lower(p.form) LIKE '%galarian%' + OR lower(p.form) LIKE '%hisuian%' + OR lower(p.form) LIKE '%paldean%' + THEN r."releaseOrder" + ELSE 0 + END AS "formSortRegionOrder", + CASE + WHEN lower(p.form) LIKE 'female-%' THEN 1 + ELSE 0 + END AS "formSortRegionalSub", + COALESCE(lower(p.form), '') AS "formSortLabel", + CASE + WHEN p.pokemon = 'Unown' THEN + CASE + WHEN p.form = '?' THEN 26 + WHEN p.form = '!' THEN 27 + WHEN length(p.form) = 1 AND ascii(upper(p.form)) BETWEEN 65 AND 90 THEN ascii(upper(p.form)) - 65 + ELSE 28 + END + ELSE 0 + END AS "unownSortOrder" 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; +GROUP BY p.id, r.name, r."releaseOrder"; GRANT SELECT ON pokedex_entries TO anon, authenticated; diff --git a/supabase/migrations/20260118001000_seed_reference_data.sql b/supabase/migrations/20260118001000_seed_reference_data.sql index b257cd3..c6bacd1 100644 --- a/supabase/migrations/20260118001000_seed_reference_data.sql +++ b/supabase/migrations/20260118001000_seed_reference_data.sql @@ -1,22 +1,24 @@ -- Seed regions, games, pokemon, and origin game mappings. -- Auto-generated from data/csvs/*.csv -INSERT INTO regions (name) VALUES - ('Kanto'), - ('Johto'), - ('Hoenn'), - ('Sinnoh'), - ('Unova'), - ('Galar'), - ('Alola'), - ('Kalos'), - ('Hisui'), - ('Paldea'), - ('Go'), - ('Home'), - ('Orre'), - ('Ranch') -ON CONFLICT (name) DO NOTHING; +INSERT INTO regions (name, "releaseOrder") VALUES + ('Kanto', 1), + ('Johto', 2), + ('Hoenn', 3), + ('Orre', 4), + ('Sinnoh', 5), + ('Ranch', 6), + ('Unova', 7), + ('Kalos', 8), + ('Alola', 9), + ('Go', 10), + ('Galar', 11), + ('Home', 12), + ('Hisui', 13), + ('Paldea', 14) +ON CONFLICT (name) DO UPDATE SET + "releaseOrder" = EXCLUDED."releaseOrder", + "updatedAt" = NOW(); INSERT INTO games (id, "displayName", "regionId", region, "releaseYear") VALUES ('red', 'Red', (SELECT id FROM regions WHERE name = 'Kanto'), 'Kanto', 1996),