deckhearth/migrations/1781442340000_cleanup-lorcana-orphans.js
Randall Stillwell ec9bb2b93e feat(catalog): unified multi-game bulk sync + schema map update
Ship Pokemon and Lorcana bulk import libs/scripts, unified weekly cron
sync across MTG/Pokemon/Lorcana with per-game error isolation and
catalog_sync_log telemetry. Admin UI adds Unified/Incremental/Bulk MTG modes.

- Rename reconcile migrations to 1781442330* timestamps so they apply
  after bulk-data migrations without node-pg-migrate ordering conflicts
- Add Lorcana set-code normalization + orphan cleanup migrations
- Drop stricter user_cards_user_card_unique (keep 3-column foil unique)
- Update docs/SCHEMA_MAP.md for tags, card_tags, catalog_sync_log, bulk columns

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 08:22:19 -05:00

49 lines
1.8 KiB
JavaScript

/**
* Remove legacy Lorcana catalog rows that predate bulk import normalization.
* Remaps collection_cards to canonical TFC printings where possible.
*/
export const shorthands = undefined;
export const up = (pgm) => {
// Remap collection_cards from orphan Elsa/Mickey rows to canonical TFC printings.
pgm.sql(`
UPDATE collection_cards cc
SET card_id = canonical.id
FROM cards orphan
JOIN cards canonical ON canonical.game = 'Lorcana'
AND canonical.name = orphan.name
AND canonical.set_code = orphan.set_code
AND canonical.scryfall_id ~ '^[A-Za-z]{2,4}-[0-9]{3}$'
WHERE cc.card_id = orphan.id
AND orphan.game = 'Lorcana'
AND (orphan.scryfall_id IS NULL OR orphan.scryfall_id !~ '^[A-Za-z]{2,4}-[0-9]{3}$')
AND NOT EXISTS (
SELECT 1 FROM collection_cards existing
WHERE existing.collection_id = cc.collection_id
AND existing.card_id = canonical.id
);
`);
// Drop collection refs that would duplicate after remap.
pgm.sql(`
DELETE FROM collection_cards cc
USING cards orphan
WHERE cc.card_id = orphan.id
AND orphan.game = 'Lorcana'
AND (orphan.scryfall_id IS NULL OR orphan.scryfall_id !~ '^[A-Za-z]{2,4}-[0-9]{3}$');
`);
// Delete unreferenced legacy rows (variant collector numbers, null external ids).
pgm.sql(`
DELETE FROM cards c
WHERE c.game = 'Lorcana'
AND (c.scryfall_id IS NULL OR c.scryfall_id !~ '^[A-Za-z]{2,4}-[0-9]{3}$')
AND NOT EXISTS (SELECT 1 FROM user_cards uc WHERE uc.card_id = c.id)
AND NOT EXISTS (SELECT 1 FROM deck_cards dc WHERE dc.card_id = c.id)
AND NOT EXISTS (SELECT 1 FROM collection_cards cc WHERE cc.card_id = c.id);
`);
};
export const down = () => {
throw new Error('Irreversible data cleanup');
};