Shuffle/supabase/catalog/checks.sql
cschlaefke 9dbafbcad7 feat(catalog): add starting-stock tool, vocabulary proposal and CI checks
Deno script validates vocabulary.csv and startbestand.csv and generates the idempotent SQL, key list and checks.sql. startbestand.csv stays header-only; vocabulary.csv is a proposal pending approval (C0). seed.sql no longer inserts genres and mechanics.

Refs #2

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-03 15:38:28 +01:00

86 lines
6.8 KiB
SQL

-- Erzeugt von supabase/catalog/build_startbestand.ts. Nicht von Hand bearbeiten.
-- Prüfabfrage zur Abnahme (KAT-05 Krit. 7 und 10). Im Studio-SQL-Editor oder per psql ausführen.
-- Beschränkt sich auf die Spiele aus startbestand-keys.csv; Spiele, die im Studio angelegt wurden,
-- und das Beispielspiel aus seed.sql zählen nicht mit. Abnahme: kein Verstoß, SB1 mindestens 180.
-- Lokal und in CI ist SB1 nur eine Information, solange noch eingepflegt wird.
with sb(id) as (
select t.value::uuid from jsonb_array_elements_text('[]'::jsonb) as t(value)
), voc(kind, id, name_de) as (
select x.kind, x.id, x.name_de from jsonb_to_recordset('[
{"kind":"genre","id":"91c2b7c9-5a7c-5001-b90f-af05c0a8bc76","name_de":"Strategiespiel"},
{"kind":"genre","id":"ecd63153-af09-5423-8579-483c4f1dc87c","name_de":"Familienspiel"},
{"kind":"genre","id":"39c44fac-9323-5695-a02a-019620057a50","name_de":"Partyspiel"},
{"kind":"genre","id":"7f50e253-41bb-5cde-ad0a-dc48e9c9295f","name_de":"Kooperatives Spiel"},
{"kind":"genre","id":"503248a5-6424-5e06-aa9a-ec1d43fb0e28","name_de":"Kartenspiel"},
{"kind":"genre","id":"963e400e-b6c9-5719-b6f0-2440d93fff7d","name_de":"Abstraktes Spiel"},
{"kind":"genre","id":"aefb13d7-2a29-5901-bb8a-aa3f897a8e20","name_de":"Thematisches Spiel"},
{"kind":"genre","id":"f7418ea2-db50-5e8c-a737-cab1ee15b34b","name_de":"Wirtschaftsspiel"},
{"kind":"genre","id":"1b7da3a2-ace2-503f-b632-f697d651e1d0","name_de":"Kriegsspiel"},
{"kind":"genre","id":"0114584b-4a22-5986-8896-8ee491aad1c7","name_de":"Kinderspiel"},
{"kind":"genre","id":"71b582a5-c53d-5370-920f-cadc03725324","name_de":"Wortspiel"},
{"kind":"genre","id":"693bbe28-03e5-554a-9548-ab54f186bffe","name_de":"Deduktionsspiel"},
{"kind":"genre","id":"72baa1f7-835e-56d7-8341-c1c524148dd4","name_de":"Geschicklichkeitsspiel"},
{"kind":"genre","id":"d8a5a92f-05b5-5dff-b321-baaecb5803bf","name_de":"Quizspiel"},
{"kind":"mechanic","id":"00f902bc-e66b-5976-b235-7cd462ee23b6","name_de":"Arbeitereinsatz"},
{"kind":"mechanic","id":"c7fde702-f7c3-5b81-b2b5-736253974a75","name_de":"Deckbau"},
{"kind":"mechanic","id":"afb217d3-38bb-5989-8383-07fa200ded35","name_de":"Handkartenmanagement"},
{"kind":"mechanic","id":"2ca2b8c5-9604-5186-a037-7386cd3f299b","name_de":"Würfeln"},
{"kind":"mechanic","id":"2d35402f-c714-5cf7-a2e6-b035023ad51a","name_de":"Plättchenlegen"},
{"kind":"mechanic","id":"83b32eef-078a-5822-91e9-d48157476056","name_de":"Sets sammeln"},
{"kind":"mechanic","id":"c4cd186c-401b-5cc2-81cb-fcfd544c8a4d","name_de":"Drafting"},
{"kind":"mechanic","id":"7d327434-bf71-5be2-a659-429c81c54cb5","name_de":"Gebietsmehrheit"},
{"kind":"mechanic","id":"77565f86-d2e0-51c6-908a-dd1d05a08d26","name_de":"Bieten und Versteigern"},
{"kind":"mechanic","id":"96dd12a0-f303-50d4-9baf-f56d9d8aa489","name_de":"Handel"},
{"kind":"mechanic","id":"84019ba4-fc52-5343-97ad-2ea5c4f6ee6e","name_de":"Verhandlung"},
{"kind":"mechanic","id":"6e49822b-dc6b-553f-b9e8-c5685d1e953b","name_de":"Streckenbau"},
{"kind":"mechanic","id":"42521d16-2532-5583-8e41-ade8e0a15679","name_de":"Engine Building"},
{"kind":"mechanic","id":"2d4aac3a-728d-54a2-a2cb-569410a56523","name_de":"Abholen und Liefern"},
{"kind":"mechanic","id":"31d0ed7c-9dad-58da-8390-55786ee1e6c4","name_de":"Stichspiel"},
{"kind":"mechanic","id":"1c83518d-9b9f-512c-a71e-585a5650adea","name_de":"Glück herausfordern"},
{"kind":"mechanic","id":"f53a7662-1580-57e0-87d3-c79ed720a63a","name_de":"Bluffen"},
{"kind":"mechanic","id":"71a4f344-709e-5536-a5a9-325d40732509","name_de":"Verdeckte Rollen"},
{"kind":"mechanic","id":"3c02a90b-9cb3-50f8-950a-9464a2767c28","name_de":"Variable Spielerfähigkeiten"},
{"kind":"mechanic","id":"e49b1223-2605-5c52-98e3-7e0d3e571e98","name_de":"Bewegung auf Raster"},
{"kind":"mechanic","id":"3f98436d-5aab-56dc-b5e9-4d8a7b0cbfa4","name_de":"Muster bauen"},
{"kind":"mechanic","id":"de7d374a-d1c6-506b-a92f-c726b06e0563","name_de":"Echtzeit"},
{"kind":"mechanic","id":"c92e4a17-82f5-5e8a-8932-77dcad0cba29","name_de":"Gedächtnis"},
{"kind":"mechanic","id":"edec6ec8-5b68-5fc0-892b-8fd739285593","name_de":"Würfeln und Notieren"},
{"kind":"mechanic","id":"d7ef7709-0a6a-5cbd-b135-086dba038839","name_de":"Kampagne"},
{"kind":"mechanic","id":"8ed41477-247c-5570-8c61-155e6f827660","name_de":"Aktionspunkte"},
{"kind":"mechanic","id":"b90c9692-ff39-5170-a1ec-003b35d60950","name_de":"Ressourcenmanagement"},
{"kind":"mechanic","id":"ef336193-3cfb-5f69-81c6-d57f8f720871","name_de":"Erzählen"},
{"kind":"mechanic","id":"bc7940fd-3e2f-5932-b99f-31d4f55fd289","name_de":"Gegenseitig ärgern"},
{"kind":"mechanic","id":"8ec5712b-42be-525a-b60d-1b79379d6f40","name_de":"Spieler scheiden aus"}
]'::jsonb) as x(kind text, id uuid, name_de text)
)
select rule, beschreibung, soll, ist, case when ok is null then 'Information' when ok then 'ok' else 'Verstoß' end as status
from (
select 1 as ord, 'SB0' as rule, 'Startbestandsspiele in der Datenbank vorhanden' as beschreibung,
'alle ' || (select count(*) from sb) as soll, n as ist, null::boolean as ok
from (select count(*) as n from public.games g join sb on sb.id = g.id) x
union all
select 2, 'SB1', 'Sichtbare Katalogspiele aus dem Startbestand (Abnahme: mindestens 180)',
'>= 180', n, n >= 180
from (select count(*) as n from public.catalog_games c join sb on sb.id = c.id) x
union all
select 3, 'SB2', 'Spiele ohne Pflicht-Fakt (Jahr, Spielerzahl, Dauer, Alter, Verlag, Genre, Mechanik)', '0', n, n = 0
from (select count(*) as n from public.games g join sb on sb.id = g.id
where g.year is null or g.min_players is null or g.max_players is null
or g.min_minutes is null or g.max_minutes is null or g.min_age is null
or not exists (select 1 from public.game_publishers x where x.game_id = g.id)
or not exists (select 1 from public.game_genres x where x.game_id = g.id)
or not exists (select 1 from public.game_mechanics x where x.game_id = g.id)) x
union all
select 4, 'SB4', 'Spiele ohne deutschen Kurztext', '0', n, n = 0
from (select count(*) as n from public.games g join sb on sb.id = g.id
where g.description is null or g.description_locale is distinct from 'de') x
union all
select 5, 'SB6', 'Spiele mit Cover, Quelle oder BGG-Kennung', '0', n, n = 0
from (select count(*) as n from public.games g join sb on sb.id = g.id
where g.image_path is not null or g.catalog_source_id is not null or g.bgg_id is not null) x
union all
select 6, 'Info', 'Begriffe mit abweichender ID (im Studio angelegt, bitte prüfen)', '-', n, null::boolean
from (select (select count(*) from public.genres t join voc v on v.kind = 'genre' and v.name_de = t.name_de where t.id <> v.id)
+ (select count(*) from public.mechanics t join voc v on v.kind = 'mechanic' and v.name_de = t.name_de where t.id <> v.id) as n) x
) r
order by ord;