From adfaa4e5dbf9e392b9ca7eb9f263a3ad8f80c03d Mon Sep 17 00:00:00 2001 From: Randall Stillwell Date: Wed, 27 May 2026 21:48:22 -0500 Subject: [PATCH] Prioritize newest missing sets in catalog sync queue. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The cron was importing oldest MTG sets first and never reaching recent Pokémon releases like Perfect Order; merge MTG and Pokémon by release date descending instead. Co-authored-by: Cursor --- lib/card-import/discover.js | 11 +++++-- lib/card-import/sync-catalog.js | 36 +++++++++++++++++--- test/lib/card-import-discover.test.js | 16 +++++++-- test/lib/card-import-sync-catalog.test.js | 40 +++++++++++++++++++++++ 4 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 test/lib/card-import-sync-catalog.test.js diff --git a/lib/card-import/discover.js b/lib/card-import/discover.js index f37cc3f..fe0cae0 100644 --- a/lib/card-import/discover.js +++ b/lib/card-import/discover.js @@ -24,7 +24,7 @@ export function filterMissingMtgSets(scryfallSets, knownCodes, now = new Date()) }); } - missing.sort((a, b) => a.releasedAt.localeCompare(b.releasedAt)); + missing.sort((a, b) => b.releasedAt.localeCompare(a.releasedAt)); return missing; } @@ -46,7 +46,14 @@ export function filterMissingPokemonSets(pokemonSets, knownCodes) { }); } - missing.sort((a, b) => (a.releasedAt || '').localeCompare(b.releasedAt || '')); + missing.sort((a, b) => { + const dateA = a.releasedAt || ''; + const dateB = b.releasedAt || ''; + if (!dateA && !dateB) return 0; + if (!dateA) return 1; + if (!dateB) return -1; + return dateB.localeCompare(dateA); + }); return missing; } diff --git a/lib/card-import/sync-catalog.js b/lib/card-import/sync-catalog.js index 577b478..3b431f9 100644 --- a/lib/card-import/sync-catalog.js +++ b/lib/card-import/sync-catalog.js @@ -7,6 +7,37 @@ const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms)); const DEFAULT_MAX_SETS_PER_RUN = 3; const DEFAULT_DELAY_MS = 1500; +/** + * Merge missing MTG + Pokémon sets and pick the newest releases first. + */ +export function buildCatalogSyncQueue(missingMtg, missingPokemon, maxSetsPerRun = DEFAULT_MAX_SETS_PER_RUN) { + const queue = [ + ...missingMtg.map((set) => ({ + game: 'mtg', + setCode: set.code, + name: set.name, + releasedAt: set.releasedAt, + })), + ...missingPokemon.map((set) => ({ + game: 'pokemon', + setCode: set.id, + name: set.name, + releasedAt: set.releasedAt, + })), + ]; + + queue.sort((a, b) => { + const dateA = a.releasedAt || ''; + const dateB = b.releasedAt || ''; + if (!dateA && !dateB) return 0; + if (!dateA) return 1; + if (!dateB) return -1; + return dateB.localeCompare(dateA); + }); + + return queue.slice(0, maxSetsPerRun); +} + /** * Discover missing MTG + Pokémon sets and import up to maxSetsPerRun, paced for upstream APIs. */ @@ -19,10 +50,7 @@ export async function runCatalogSync(options = {}) { discoverMissingPokemonSets(), ]); - const queue = [ - ...missingMtg.map((set) => ({ game: 'mtg', setCode: set.code, name: set.name })), - ...missingPokemon.map((set) => ({ game: 'pokemon', setCode: set.id, name: set.name })), - ].slice(0, maxSetsPerRun); + const queue = buildCatalogSyncQueue(missingMtg, missingPokemon, maxSetsPerRun); const summary = { imported: 0, diff --git a/test/lib/card-import-discover.test.js b/test/lib/card-import-discover.test.js index f29a209..73700e2 100644 --- a/test/lib/card-import-discover.test.js +++ b/test/lib/card-import-discover.test.js @@ -8,12 +8,13 @@ import { describe('filterMissingMtgSets', () => { const now = new Date('2026-05-27T12:00:00.000Z'); - it('returns released paper sets missing from the catalog', () => { + it('returns released paper sets missing from the catalog, newest first', () => { const known = new Set(['lea']); const missing = filterMissingMtgSets( [ { code: 'lea', name: 'Alpha', released_at: '1993-08-05', set_type: 'core', digital: false }, { code: 'fin', name: 'Final Fantasy', released_at: '2026-05-01', set_type: 'expansion', digital: false }, + { code: 'dsk', name: 'Duskmourn', released_at: '2024-09-27', set_type: 'expansion', digital: false }, { code: 'tlea', name: 'Alpha Tokens', released_at: '1993-08-05', set_type: 'token', digital: false }, { code: 'mh3', name: 'Modern Horizons 3', released_at: '2027-01-01', set_type: 'expansion', digital: false }, ], @@ -27,22 +28,33 @@ describe('filterMissingMtgSets', () => { name: 'Final Fantasy', releasedAt: '2026-05-01', }, + { + code: 'dsk', + name: 'Duskmourn', + releasedAt: '2024-09-27', + }, ]); }); }); describe('filterMissingPokemonSets', () => { - it('returns sets whose ids are not in the catalog', () => { + it('returns sets whose ids are not in the catalog, newest first', () => { const known = new Set(['sv1']); const missing = filterMissingPokemonSets( [ { id: 'sv1', name: 'Scarlet & Violet', releaseDate: '2023-03-31' }, { id: 'sv2', name: 'Paldea Evolved', releaseDate: '2023-06-09' }, + { id: 'sv3', name: 'Obsidian Flames', releaseDate: '2023-08-11' }, ], known ); expect(missing).toEqual([ + { + id: 'sv3', + name: 'Obsidian Flames', + releasedAt: '2023-08-11', + }, { id: 'sv2', name: 'Paldea Evolved', diff --git a/test/lib/card-import-sync-catalog.test.js b/test/lib/card-import-sync-catalog.test.js new file mode 100644 index 0000000..b37c269 --- /dev/null +++ b/test/lib/card-import-sync-catalog.test.js @@ -0,0 +1,40 @@ +import { describe, expect, it } from 'vitest'; + +import { buildCatalogSyncQueue } from '../../lib/card-import/sync-catalog.js'; + +describe('buildCatalogSyncQueue', () => { + it('merges MTG and Pokémon missing sets by release date, newest first', () => { + const queue = buildCatalogSyncQueue( + [ + { code: 'fin', name: 'Final Fantasy', releasedAt: '2026-05-01' }, + { code: 'dsk', name: 'Duskmourn', releasedAt: '2024-09-27' }, + ], + [ + { id: 'sv10', name: 'Perfect Order', releasedAt: '2026-03-27' }, + { id: 'sv9', name: 'Journey Together', releasedAt: '2025-03-28' }, + ], + 3 + ); + + expect(queue).toEqual([ + { + game: 'mtg', + setCode: 'fin', + name: 'Final Fantasy', + releasedAt: '2026-05-01', + }, + { + game: 'pokemon', + setCode: 'sv10', + name: 'Perfect Order', + releasedAt: '2026-03-27', + }, + { + game: 'pokemon', + setCode: 'sv9', + name: 'Journey Together', + releasedAt: '2025-03-28', + }, + ]); + }); +});