Skip to content

Commit 5575067

Browse files
committed
fix(catalog): remove cards without printings
Amp-Thread-ID: https://ampcode.com/threads/T-019fe6e8-e7e4-779a-a885-4bb102e9a711
1 parent db76da7 commit 5575067

3 files changed

Lines changed: 84 additions & 0 deletions

File tree

‎lib/manavault/catalog/scryfall/import.ex‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,12 +394,30 @@ defmodule Manavault.Catalog.Scryfall.Import do
394394
Repo.delete_all(from printing in Printing, where: printing.scryfall_id in ^ids)
395395
end)
396396

397+
delete_cards_without_printings()
398+
397399
{:ok, :reconciled}
398400
end,
399401
timeout: :infinity
400402
)
401403
end
402404

405+
defp delete_cards_without_printings do
406+
orphaned_card_ids =
407+
Repo.all(
408+
from card in Card,
409+
left_join: printing in Printing,
410+
on: printing.oracle_id == card.oracle_id,
411+
where: is_nil(printing.scryfall_id),
412+
select: card.oracle_id
413+
)
414+
415+
Enum.each(Enum.chunk_every(orphaned_card_ids, @batch_size), fn ids ->
416+
Repo.delete_all(from deck_card in DeckCard, where: deck_card.oracle_id in ^ids)
417+
Repo.delete_all(from card in Card, where: card.oracle_id in ^ids)
418+
end)
419+
end
420+
403421
defp replacement_for(_stale, []), do: nil
404422

405423
defp replacement_for(stale, replacements) do
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
defmodule Manavault.Repo.Migrations.DeleteCardsWithoutPrintings do
2+
use Ecto.Migration
3+
4+
import Ecto.Query
5+
6+
@batch_size 200
7+
8+
def up do
9+
orphaned_card_ids =
10+
repo().all(
11+
from(card in "scryfall_cards",
12+
left_join: printing in "scryfall_printings",
13+
on: printing.oracle_id == card.oracle_id,
14+
where: is_nil(printing.scryfall_id),
15+
select: card.oracle_id
16+
)
17+
)
18+
19+
Enum.each(Enum.chunk_every(orphaned_card_ids, @batch_size), fn ids ->
20+
repo().delete_all(from(deck_card in "deck_cards", where: deck_card.oracle_id in ^ids))
21+
repo().delete_all(from(card in "scryfall_cards", where: card.oracle_id in ^ids))
22+
end)
23+
end
24+
25+
def down do
26+
# Deleted catalog and deck-card rows cannot be reconstructed.
27+
:ok
28+
end
29+
end

‎test/manavault/catalog/sync_test.exs‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,43 @@ defmodule Manavault.Catalog.SyncTest do
148148
assert Repo.get!(DeckAllocation, allocation.id).collection_item_id == item.id
149149
end
150150

151+
test "sync_scryfall deletes cards left without paper printings" do
152+
digital_only = %{
153+
@black_lotus
154+
| "id" => "digital-only-printing",
155+
"oracle_id" => "digital-only-oracle",
156+
"name" => "Digital Only Card",
157+
"games" => ["arena"]
158+
}
159+
160+
assert {:ok, %{cards_count: 1, printings_count: 1}} =
161+
Catalog.import_cards([digital_only])
162+
163+
assert {:ok, deck} = Catalog.create_deck(%{"name" => "Digital Only Deck"})
164+
165+
assert {:ok, deck_card} =
166+
Catalog.add_card_to_deck(deck, %{"name" => digital_only["name"], "quantity" => 1})
167+
168+
metadata_url = "https://example.test/orphan-cleanup-metadata"
169+
download_url = "https://example.test/orphan-cleanup-default-cards.jsonl.gz"
170+
171+
fetcher = fn
172+
^metadata_url -> {:ok, Jason.encode!(%{"jsonl_download_uri" => download_url})}
173+
^download_url -> {:ok, gzip_jsonl([@black_lotus])}
174+
end
175+
176+
assert {:ok, %Sync{status: "succeeded"}} =
177+
Catalog.sync_scryfall(
178+
fetcher: fetcher,
179+
bulk_url: metadata_url,
180+
oracle_tags_bulk_url: nil
181+
)
182+
183+
refute Repo.get(Printing, digital_only["id"])
184+
refute Repo.get(Card, digital_only["oracle_id"])
185+
refute Repo.get(DeckCard, deck_card.id)
186+
end
187+
151188
test "sync_scryfall deletes existing memorabilia and token set printings" do
152189
memorabilia =
153190
%{

0 commit comments

Comments
 (0)