feat(catalog): Katalogsuche Backend – RPC, Normalisierung, alternative Titel (KAT-01, 3a Backend) #64
3 changed files with 123 additions and 45 deletions
|
|
@ -305,6 +305,7 @@ Deno.test("alt_titles: Fehler anderer Art nennen die Zeilennummer", async () =>
|
|||
|
||||
Deno.test("approxNormalize: Marken- und Schutzzeichen, Akzente, ß, Æ, Sonderzeichen", () => {
|
||||
assert.equal(approxNormalize("CATAN®"), "catan");
|
||||
assert.equal(approxNormalize("Spiel™Ding"), "spielding"); // Schutzzeichen werden entfernt, nicht zum Trenner (wie search_normalize)
|
||||
assert.equal(approxNormalize("Café Größe"), "cafe grosse");
|
||||
assert.equal(approxNormalize("Æon’s End"), "aeon s end");
|
||||
assert.equal(approxNormalize("7 Wonders: Duel"), "7 wonders duel");
|
||||
|
|
|
|||
|
|
@ -152,7 +152,8 @@ declare
|
|||
v_offset integer := coalesce(p_offset, 0);
|
||||
v_q text;
|
||||
v_qc text;
|
||||
v_words text[] := '{}';
|
||||
v_words text[] := '{}'::text[];
|
||||
v_patterns text[] := '{}'::text[]; -- '%wort%' je Suchwort, für like all
|
||||
v_has_query boolean := false;
|
||||
v_genres uuid[];
|
||||
v_mechanics uuid[];
|
||||
|
|
@ -189,6 +190,7 @@ begin
|
|||
v_qc := replace(v_q, ' ', '');
|
||||
v_words := coalesce(
|
||||
array(select distinct w from unnest(string_to_array(v_q, ' ')) as w where char_length(w) >= 2), '{}');
|
||||
v_patterns := array(select '%' || w || '%' from unnest(v_words) as w);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
|
|
@ -215,10 +217,10 @@ begin
|
|||
where (p_players is null or (c.min_players <= p_players and p_players <= c.max_players))
|
||||
and (p_max_minutes is null or coalesce(c.max_minutes, c.min_minutes) <= p_max_minutes)
|
||||
and (p_age is null or c.min_age <= p_age)
|
||||
and (v_genre_n = 0 or (select count(*) from public.game_genres gg
|
||||
where gg.game_id = c.id and gg.genre_id = any (v_genres)) = v_genre_n)
|
||||
and (v_mech_n = 0 or (select count(*) from public.game_mechanics gm
|
||||
where gm.game_id = c.id and gm.mechanic_id = any (v_mechanics)) = v_mech_n)
|
||||
and (v_genre_n = 0 or c.id in (select gg.game_id from public.game_genres gg where gg.genre_id = any (v_genres)
|
||||
group by gg.game_id having count(*) = v_genre_n))
|
||||
and (v_mech_n = 0 or c.id in (select gm.game_id from public.game_mechanics gm where gm.mechanic_id = any (v_mechanics)
|
||||
group by gm.game_id having count(*) = v_mech_n))
|
||||
order by g.title_search collate "C", c.id
|
||||
limit v_limit offset v_offset
|
||||
) s
|
||||
|
|
@ -235,10 +237,10 @@ begin
|
|||
where (p_players is null or (c.min_players <= p_players and p_players <= c.max_players))
|
||||
and (p_max_minutes is null or coalesce(c.max_minutes, c.min_minutes) <= p_max_minutes)
|
||||
and (p_age is null or c.min_age <= p_age)
|
||||
and (v_genre_n = 0 or (select count(*) from public.game_genres gg
|
||||
where gg.game_id = c.id and gg.genre_id = any (v_genres)) = v_genre_n)
|
||||
and (v_mech_n = 0 or (select count(*) from public.game_mechanics gm
|
||||
where gm.game_id = c.id and gm.mechanic_id = any (v_mechanics)) = v_mech_n)
|
||||
and (v_genre_n = 0 or c.id in (select gg.game_id from public.game_genres gg where gg.genre_id = any (v_genres)
|
||||
group by gg.game_id having count(*) = v_genre_n))
|
||||
and (v_mech_n = 0 or c.id in (select gm.game_id from public.game_mechanics gm where gm.mechanic_id = any (v_mechanics)
|
||||
group by gm.game_id having count(*) = v_mech_n))
|
||||
),
|
||||
-- Kandidaten-Titel: Haupttitel (alt_title null) und alle alternativen Titel
|
||||
cand as (
|
||||
|
|
@ -247,50 +249,72 @@ begin
|
|||
select b.id, a.title_search, a.title
|
||||
from base b join public.game_alt_titles a on a.game_id = b.id
|
||||
),
|
||||
-- Relevanzstufe je Kandidaten-Titel (null = kein Titeltreffer)
|
||||
-- Relevanzstufe je Kandidaten-Titel (null = kein Titeltreffer). Nur günstige Vergleiche; die teure
|
||||
-- Trigramm-Ähnlichkeit wird erst für die Treffer berechnet (sims, alt_pick).
|
||||
ranked as (
|
||||
select t.id, t.ts, t.alt_title,
|
||||
case
|
||||
when t.ts = v_q or replace(t.ts, ' ', '') = v_qc then 0
|
||||
-- Stufe 0: gleich dem Suchbegriff (auch ohne Leerzeichen gleich; das schließt ts = v_q ein)
|
||||
when replace(t.ts, ' ', '') = v_qc then 0
|
||||
when t.ts like v_q || '%' then 1
|
||||
when t.ts like '% ' || v_q || '%' then 2
|
||||
when replace(t.ts, ' ', '') like '%' || v_qc || '%'
|
||||
or (cardinality(v_words) > 0
|
||||
and not exists (select 1 from unnest(v_words) as w where t.ts not like '%' || w || '%'))
|
||||
or (cardinality(v_patterns) > 0 and t.ts like all (v_patterns))
|
||||
then 3
|
||||
end as rk,
|
||||
extensions.similarity(t.ts, v_q) as sim
|
||||
end as rk
|
||||
from cand t
|
||||
),
|
||||
agg as (
|
||||
select r.id,
|
||||
min(r.rk) as best_rk,
|
||||
min(r.rk) filter (where r.alt_title is null) as main_rk,
|
||||
min(r.rk) filter (where r.alt_title is not null) as alt_rk,
|
||||
(array_agg(r.alt_title order by r.rk, r.sim desc nulls last, r.ts, r.alt_title)
|
||||
filter (where r.alt_title is not null and r.rk is not null))[1] as alt_title,
|
||||
max(r.sim) as sim
|
||||
min(r.rk) filter (where r.alt_title is not null) as alt_rk
|
||||
from ranked r
|
||||
group by r.id
|
||||
),
|
||||
-- der alternative Titel mit der besten Stufe (bei Gleichstand: größte Ähnlichkeit, dann Schreibweise)
|
||||
alt_pick as (
|
||||
select distinct on (r.id) r.id, r.alt_title
|
||||
from ranked r
|
||||
where r.alt_title is not null and r.rk is not null
|
||||
order by r.id, r.rk, extensions.similarity(r.ts, v_q) desc, r.ts, r.alt_title
|
||||
),
|
||||
-- Rang 4: welches Suchwort kommt in welchem Spiel in einem Titel oder einem Verlagsnamen vor?
|
||||
-- (als Mengenoperation statt korrelierter Unterabfrage je Spiel: sonst wächst die Zeit quadratisch)
|
||||
word_hits as (
|
||||
select r.id, w.w from ranked r cross join unnest(v_words) as w(w) where r.ts like '%' || w.w || '%'
|
||||
union
|
||||
select gp.game_id, w.w
|
||||
from public.publishers p
|
||||
join public.game_publishers gp on gp.publisher_id = p.id
|
||||
cross join unnest(v_words) as w(w)
|
||||
where p.name_search like '%' || w.w || '%'
|
||||
),
|
||||
word_cover as (
|
||||
select wh.id, count(*) as n from word_hits wh group by wh.id
|
||||
),
|
||||
hit as (
|
||||
select b.*, a.best_rk, a.main_rk, a.alt_rk, a.alt_title, a.sim
|
||||
select b.*, a.best_rk, a.main_rk, a.alt_rk, ap.alt_title
|
||||
from base b
|
||||
join agg a on a.id = b.id
|
||||
left join alt_pick ap on ap.id = b.id
|
||||
left join word_cover wc on wc.id = b.id
|
||||
where a.best_rk is not null
|
||||
-- Rang 4: jedes Wort kommt in einem Titel oder einem Verlagsnamen des Spiels vor
|
||||
or (cardinality(v_words) > 0
|
||||
and not exists (
|
||||
select 1 from unnest(v_words) as w
|
||||
where not (exists (select 1 from ranked r2 where r2.id = b.id and r2.ts like '%' || w || '%')
|
||||
or exists (select 1 from public.game_publishers gp
|
||||
join public.publishers p on p.id = gp.publisher_id
|
||||
where gp.game_id = b.id and p.name_search like '%' || w || '%'))))
|
||||
or (cardinality(v_words) > 0 and wc.n = cardinality(v_words))
|
||||
),
|
||||
-- Ähnlichkeit (zweites Sortierkriterium): die höchste über Haupttitel und alle alternativen Titel
|
||||
sims as (
|
||||
select r.id, max(extensions.similarity(r.ts, v_q)) as sim
|
||||
from ranked r
|
||||
join hit h on h.id = r.id
|
||||
group by r.id
|
||||
),
|
||||
paged as (
|
||||
select h.*, coalesce(h.best_rk, 4) as rk, count(*) over () as total
|
||||
select h.*, sm.sim, coalesce(h.best_rk, 4) as rk, count(*) over () as total
|
||||
from hit h
|
||||
order by coalesce(h.best_rk, 4), h.sim desc nulls last, h.title_search collate "C", h.id
|
||||
join sims sm on sm.id = h.id
|
||||
order by coalesce(h.best_rk, 4), sm.sim desc nulls last, h.title_search collate "C", h.id
|
||||
limit v_limit offset v_offset
|
||||
)
|
||||
select s.id, s.title, s.year, s.min_players, s.max_players, s.min_minutes, s.max_minutes, s.min_age,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
-- Ohne Suchbegriff wird nur auf Fixture-IDs geprüft (Hilfsfunktion pg_temp.hits blättert durch).
|
||||
-- Die Include-Dateien in ../support/ (\ir) erzeugt supabase/catalog/build_startbestand.ts.
|
||||
begin;
|
||||
select plan(201);
|
||||
select plan(211);
|
||||
|
||||
insert into auth.users (id, email, raw_user_meta_data) values
|
||||
('11111111-1111-1111-1111-111111111111', 'anna@example.com', '{"age_confirmed":"true","terms_accepted":"true","terms_version":"test","display_name":"Anna"}'),
|
||||
|
|
@ -116,13 +116,14 @@ select results_eq($$select polcmd::text, array(select rolname from pg_roles wher
|
|||
insert into public.genres (id, name_de, name_en) values
|
||||
('f9000000-0000-0000-0000-0000000000e1', 'Qxz Genre A', 'Qxz genre A'),
|
||||
('f9000000-0000-0000-0000-0000000000e2', 'Qxz Genre B', 'Qxz genre B'),
|
||||
('f9000000-0000-0000-0000-0000000000e3', 'Qxz Genre Q', 'Qxz genre Q');
|
||||
('f9000000-0000-0000-0000-0000000000e3', 'Qxz Genre Q', 'Qxz genre Q'),
|
||||
('f9000000-0000-0000-0000-0000000000e4', 'Qxz Genre R', 'Qxz genre R');
|
||||
insert into public.mechanics (id, name_de, name_en) values
|
||||
('f9000000-0000-0000-0000-0000000000d1', 'Qxz Mechanik A', 'Qxz mechanic A'),
|
||||
('f9000000-0000-0000-0000-0000000000d2', 'Qxz Mechanik B', 'Qxz mechanic B');
|
||||
insert into public.publishers (id, name) values
|
||||
('f9000000-0000-0000-0000-0000000000b1', 'Qxz Hersteller Eins'),
|
||||
('f9000000-0000-0000-0000-0000000000b2', 'Qxz Hersteller Zwei'),
|
||||
('f9000000-0000-0000-0000-0000000000b2', 'Qxz Hersteller Eins'),
|
||||
('f9000000-0000-0000-0000-0000000000b1', 'Qxz Hersteller Zwei'),
|
||||
('f9000000-0000-0000-0000-0000000000b3', 'Qxz Zorb Verlag');
|
||||
|
||||
insert into public.games (id, title, visibility) values
|
||||
|
|
@ -144,7 +145,18 @@ insert into public.games (id, title, visibility) values
|
|||
('f9000000-0000-0000-0000-000000000016', 'QXZ CATAN®', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'Qxz Doppelspiel', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000041', 'Qxz Einzelspiel', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000060', 'Qxz Cabin', 'catalog');
|
||||
('f9000000-0000-0000-0000-000000000060', 'Qxz Cabin', 'catalog'),
|
||||
-- Sortierung ist binär (collate "C"): "qxz b" kommt vor "qxzab". Hinweis: Mit ICU-Sortierung (wie lokal) gilt das auch
|
||||
-- ohne collate "C"; der Test ist dort nicht mutationsempfindlich und schützt vor libc-Sortierungen, die Leerzeichen ignorieren.
|
||||
('f9000000-0000-0000-0000-000000000081', 'Qxzab', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000095', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000093', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000091', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000094', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000092', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000090', 'Qxz Zwilling', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000017', 'Qxz Wanderer', 'catalog'),
|
||||
('f9000000-0000-0000-0000-000000000080', 'Qxz B', 'catalog');
|
||||
|
||||
-- Filter-Fixtures (20-25); 22 ohne jede Angabe, 23 nur max_minutes, 24 nur min_minutes
|
||||
insert into public.games (id, title, visibility, min_players, max_players, min_minutes, max_minutes, min_age) values
|
||||
|
|
@ -161,7 +173,9 @@ insert into public.game_genres (game_id, genre_id) values
|
|||
('f9000000-0000-0000-0000-000000000022', 'f9000000-0000-0000-0000-0000000000e1'),
|
||||
('f9000000-0000-0000-0000-000000000025', 'f9000000-0000-0000-0000-0000000000e2'),
|
||||
('f9000000-0000-0000-0000-000000000005', 'f9000000-0000-0000-0000-0000000000e3'),
|
||||
('f9000000-0000-0000-0000-000000000060', 'f9000000-0000-0000-0000-0000000000e3');
|
||||
('f9000000-0000-0000-0000-000000000060', 'f9000000-0000-0000-0000-0000000000e3'),
|
||||
('f9000000-0000-0000-0000-000000000080', 'f9000000-0000-0000-0000-0000000000e4'),
|
||||
('f9000000-0000-0000-0000-000000000081', 'f9000000-0000-0000-0000-0000000000e4');
|
||||
insert into public.game_mechanics (game_id, mechanic_id) values
|
||||
('f9000000-0000-0000-0000-000000000020', 'f9000000-0000-0000-0000-0000000000d1'),
|
||||
('f9000000-0000-0000-0000-000000000021', 'f9000000-0000-0000-0000-0000000000d1'),
|
||||
|
|
@ -170,10 +184,10 @@ insert into public.game_mechanics (game_id, mechanic_id) values
|
|||
|
||||
-- Verlage: 01 und 30 bei Eins; 40 bei Eins und Zwei; 41 bei Zwei; 06 bei "Qxz Zorb Verlag"
|
||||
insert into public.game_publishers (game_id, publisher_id) values
|
||||
('f9000000-0000-0000-0000-000000000001', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000001', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000041', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000040', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000041', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000006', 'f9000000-0000-0000-0000-0000000000b3');
|
||||
|
||||
-- Ausgeblendet, zusammengeführt, privat
|
||||
|
|
@ -185,8 +199,8 @@ insert into public.games (id, title, visibility, owner_id) values
|
|||
('f9000000-0000-0000-0000-000000000032', 'Qxz Privat', 'private', '11111111-1111-1111-1111-111111111111'),
|
||||
('f9000000-0000-0000-0000-000000000033', 'QXZ ZORB', 'private', '22222222-2222-2222-2222-222222222222');
|
||||
insert into public.game_publishers (game_id, publisher_id) values
|
||||
('f9000000-0000-0000-0000-000000000030', 'f9000000-0000-0000-0000-0000000000b1'),
|
||||
('f9000000-0000-0000-0000-000000000033', 'f9000000-0000-0000-0000-0000000000b1');
|
||||
('f9000000-0000-0000-0000-000000000030', 'f9000000-0000-0000-0000-0000000000b2'),
|
||||
('f9000000-0000-0000-0000-000000000033', 'f9000000-0000-0000-0000-0000000000b2');
|
||||
|
||||
-- Bilder: 50 mit Quelle ohne Erlaubnis (maskiert), 51 manuell gepflegt, 52 ohne Quelle
|
||||
insert into public.games (id, title, visibility, image_path, catalog_source_id, source_ref) values
|
||||
|
|
@ -211,18 +225,22 @@ insert into public.game_alt_titles (id, game_id, locale, title) values
|
|||
('f9000000-0000-0000-0000-0000000000a6', 'f9000000-0000-0000-0000-000000000030', 'de', 'Qxz Verborgen Alt'),
|
||||
('f9000000-0000-0000-0000-0000000000a7', 'f9000000-0000-0000-0000-000000000031', 'de', 'Qxz Verschmolzen Alt'),
|
||||
('f9000000-0000-0000-0000-0000000000a8', 'f9000000-0000-0000-0000-000000000032', 'de', 'Qxz Privat Alt'),
|
||||
('f9000000-0000-0000-0000-0000000000a9', 'f9000000-0000-0000-0000-000000000033', 'en', 'Qxz Bens Alt');
|
||||
('f9000000-0000-0000-0000-0000000000a9', 'f9000000-0000-0000-0000-000000000033', 'en', 'Qxz Bens Alt'),
|
||||
-- drei Treffer-Titel für "qxz nomad": Stufe 2, Stufe 1 (länger, weniger ähnlich), Stufe 1 (kürzer, ähnlicher)
|
||||
('f9000000-0000-0000-0000-0000000000c1', 'f9000000-0000-0000-0000-000000000017', 'de', 'Stern Qxz Nomad'),
|
||||
('f9000000-0000-0000-0000-0000000000c2', 'f9000000-0000-0000-0000-000000000017', 'en', 'Qxz Nomad Sternenwanderer'),
|
||||
('f9000000-0000-0000-0000-0000000000c3', 'f9000000-0000-0000-0000-000000000017', 'de', 'Qxz Nomadisch');
|
||||
|
||||
select is((select title_search from public.games where id = 'f9000000-0000-0000-0000-000000000014'), 'qxz aeon s end',
|
||||
'KAT-01 Kriterium 1: games.title_search wird beim Anlegen gefüllt');
|
||||
select is((select title_search from public.game_alt_titles where id = 'f9000000-0000-0000-0000-0000000000a5'), 'qxz einzigartig alt',
|
||||
'KAT-01 Kriterium 2: game_alt_titles.title_search wird gefüllt');
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b2'), 'qxz hersteller zwei',
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b1'), 'qxz hersteller zwei',
|
||||
'KAT-01 Kriterium 3: publishers.name_search wird gefüllt');
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei & Söhne' where id = 'f9000000-0000-0000-0000-0000000000b2';
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b2'), 'qxz hersteller zwei sohne',
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei & Söhne' where id = 'f9000000-0000-0000-0000-0000000000b1';
|
||||
select is((select name_search from public.publishers where id = 'f9000000-0000-0000-0000-0000000000b1'), 'qxz hersteller zwei sohne',
|
||||
'KAT-01: publishers.name_search folgt einer Namensänderung');
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei' where id = 'f9000000-0000-0000-0000-0000000000b2';
|
||||
update public.publishers set name = 'Qxz Hersteller Zwei' where id = 'f9000000-0000-0000-0000-0000000000b1';
|
||||
|
||||
-- Hilfsfunktion: alle Fixture-Treffer durchblättern (nur als postgres, für Abfragen ohne Suchbegriff)
|
||||
create function pg_temp.hits(p_query text default null, p_players smallint default null, p_max_minutes smallint default null,
|
||||
|
|
@ -257,6 +275,28 @@ select results_eq($$select id, match_rank::int from public.search_catalog_games(
|
|||
select results_eq($$select id from public.search_catalog_games('qxz twin')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000007'::uuid), ('f9000000-0000-0000-0000-000000000008')$$,
|
||||
'KAT-01 Kriterium 5: bei völligem Gleichstand entscheidet die ID (stabile Reihenfolge)');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 4, 0)$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid), ('f9000000-0000-0000-0000-000000000002'), ('f9000000-0000-0000-0000-000000000003'), ('f9000000-0000-0000-0000-000000000004')$$,
|
||||
'KAT-01 Kriterium 5: die erste Seite enthält die relevantesten Treffer (Stufe, dann Ähnlichkeit), nicht die ersten nach Titel');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 2, 0)
|
||||
union all select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 2, 2)
|
||||
union all select id from public.search_catalog_games('qxz zorb', null, null, null, null, null, 2, 4)$$,
|
||||
$$select id from public.search_catalog_games('qxz zorb')$$,
|
||||
'KAT-01 Kriterium 5: Seiten zu je zwei ergeben dieselbe Reihenfolge wie die ganze Liste');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz twin', null, null, null, null, null, 1, 0)
|
||||
union all select id from public.search_catalog_games('qxz twin', null, null, null, null, null, 1, 1)$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000007'::uuid), ('f9000000-0000-0000-0000-000000000008')$$,
|
||||
'KAT-01 Kriterium 5: bei völligem Gleichstand entscheidet die ID auch über die Seitengrenze hinweg');
|
||||
select results_eq($$select id from public.search_catalog_games('qxz zwilling', null, null, null, null, null, 3, 0)
|
||||
union all select id from public.search_catalog_games('qxz zwilling', null, null, null, null, null, 3, 3)$$,
|
||||
$$select id from public.games where title = 'Qxz Zwilling' order by id$$,
|
||||
'KAT-01 Kriterium 5: sechs gleich gute Treffer erscheinen seitenübergreifend in ID-Reihenfolge');
|
||||
select results_eq($$select id, match_rank::int, matched_alt_title from public.search_catalog_games('qxz nomad')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000017'::uuid, 1, 'Qxz Nomadisch'::text)$$,
|
||||
'KAT-01 Kriterium 2: von mehreren treffenden alternativen Titeln gewinnt die beste Stufe, dann die größte Ähnlichkeit');
|
||||
select results_eq($$select id, match_rank::int, matched_alt_title from public.search_catalog_games('qxz einzig')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000012'::uuid, 1, null::text)$$,
|
||||
'KAT-01 Kriterium 2: bei gleicher Stufe von Haupttitel und alternativem Titel gilt der Haupttitel (matched_alt_title null)');
|
||||
select is((select count(*) from public.search_catalog_games('qxz käse')), 1::bigint, 'KAT-01 Kriterium 1: Umlaut im Suchbegriff findet den Umlaut-Titel');
|
||||
select is((select count(*) from public.search_catalog_games('QXZ KASE GROSSE')), 1::bigint, 'KAT-01 Kriterium 1: ohne Umlaut und ß wird derselbe Titel gefunden');
|
||||
select is((select count(*) from public.search_catalog_games('qxz grösse')), 1::bigint, 'KAT-01 Kriterium 1: ö und ß in der Eingabe');
|
||||
|
|
@ -324,6 +364,9 @@ select results_eq($$select id, match_rank::int, publisher_names from public.sear
|
|||
select results_eq($$select id from public.search_catalog_games('qxz hersteller eins') order by id$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid), ('f9000000-0000-0000-0000-000000000040')$$,
|
||||
'KAT-01 Kriterium 3: der andere Verlag des Spiels findet es ebenfalls; ausgeblendete Spiele des Verlags fehlen');
|
||||
select results_eq($$select id, match_rank::int from public.search_catalog_games('qxz zorb zorb eins')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid, 4)$$,
|
||||
'KAT-01 Kriterium 3: ein doppelt eingegebenes Wort zählt einfach (Verlagstreffer bleibt auffindbar)');
|
||||
select results_eq($$select id, match_rank::int from public.search_catalog_games('qxz zorb eins')$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000001'::uuid, 4)$$,
|
||||
'KAT-01 Kriterium 3: ein Wort aus dem Titel plus ein Wort aus dem Verlag (UND)');
|
||||
|
|
@ -367,6 +410,9 @@ select results_eq($$select h from pg_temp.hits(p_genre_ids := array['f9000000-00
|
|||
select results_eq($$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d2']::uuid[]) h order by 1$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000021'::uuid), ('f9000000-0000-0000-0000-000000000025')$$,
|
||||
'KAT-01 Kriterium 4: Mechanik allein');
|
||||
select results_eq($$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d2', 'f9000000-0000-0000-0000-0000000000d2']::uuid[]) h order by 1$$,
|
||||
$$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d2']::uuid[]) h order by 1$$,
|
||||
'KAT-01 Kriterium 4: Duplikate im Mechanik-Array zählen einfach');
|
||||
select results_eq($$select h from pg_temp.hits(p_mechanic_ids := array['f9000000-0000-0000-0000-0000000000d1', 'f9000000-0000-0000-0000-0000000000d2']::uuid[]) h$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000021'::uuid)$$,
|
||||
'KAT-01 Spec-F1: zwei Mechaniken: nur Spiele mit beiden');
|
||||
|
|
@ -386,6 +432,13 @@ select results_eq($$select id, match_rank::int, matched_alt_title, total_count::
|
|||
$$values ('f9000000-0000-0000-0000-000000000060'::uuid, null::int, null::text, 2),
|
||||
('f9000000-0000-0000-0000-000000000005', null, null, 2)$$,
|
||||
'KAT-01 Kriterium 8: ohne Suchbegriff nach Titel sortiert, match_rank und matched_alt_title null');
|
||||
select results_eq($$select id from public.search_catalog_games(null, null, null, null, array['f9000000-0000-0000-0000-0000000000e3']::uuid[], null, 1, 0)
|
||||
union all select id from public.search_catalog_games(null, null, null, null, array['f9000000-0000-0000-0000-0000000000e3']::uuid[], null, 1, 1)$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000060'::uuid), ('f9000000-0000-0000-0000-000000000005')$$,
|
||||
'KAT-01 Kriterium 5: ohne Suchbegriff bestimmt der Titel (nicht die ID) auch die Seitengrenze');
|
||||
select results_eq($$select id from public.search_catalog_games(null, null, null, null, array['f9000000-0000-0000-0000-0000000000e4']::uuid[])$$,
|
||||
$$values ('f9000000-0000-0000-0000-000000000080'::uuid), ('f9000000-0000-0000-0000-000000000081')$$,
|
||||
'KAT-01 Kriterium 8: ohne Suchbegriff wird binär nach dem normalisierten Titel sortiert (Leerzeichen vor Buchstaben)');
|
||||
select results_eq($$select h from pg_temp.hits() h order by 1$$,
|
||||
$$select id from public.games where id::text like 'f9000000%' and visibility = 'catalog' and hidden_at is null and merged_into_id is null order by id$$,
|
||||
'KAT-01 Kriterium 8: ohne Suchbegriff und ohne Filter erscheinen alle sichtbaren Fixture-Spiele (ohne ausgeblendete, zusammengeführte, private)');
|
||||
|
|
|
|||
Loading…
Reference in a new issue