mirror of
https://github.com/zkldi/Tachi.git
synced 2026-09-30 10:58:07 +03:00
fix: bracketise folder.where queries
This commit is contained in:
@@ -18,7 +18,9 @@ export async function BuildFolderQuery(folderID: string, db: Kysely<Database>) {
|
||||
throw new Error(`Folder with ID '${folderID}' not found.`);
|
||||
}
|
||||
|
||||
const interpolateWhereRaw = sql.raw(folder.where);
|
||||
// Parentheses: `folder.where` is spliced before ANDs on chart.game / versions; without
|
||||
// them, `A OR B AND chart.game = …` parses as `A OR (B AND …)` instead of `(A OR B) AND …`.
|
||||
const interpolateWhereRaw = sql.raw(`(${folder.where})`);
|
||||
|
||||
// JOIN song so predicates can use `song.` (song-type folders from `5-folders-to-sql-queries.ts`).
|
||||
if (folder.version_filter) {
|
||||
|
||||
@@ -124,6 +124,89 @@ describe("BuildFolderQuery", () => {
|
||||
expect((rows[0] as { id: string }).id).toBe(chartB);
|
||||
});
|
||||
|
||||
it("wraps folder.where so OR does not bypass chart.game (and version_filter) ANDs", async () => {
|
||||
const { folderId, folderLegacy, songId, chartA, chartB } = ids("bfq-or");
|
||||
const otherGameChart = `${chartA}-other`;
|
||||
|
||||
await DB.insertInto("song")
|
||||
.values({
|
||||
id: songId,
|
||||
legacy_id: 9_800_010,
|
||||
game_group: "iidx",
|
||||
title: "OR precedence song",
|
||||
artist: "Z",
|
||||
search_terms: [],
|
||||
alt_titles: [],
|
||||
fts_document: "",
|
||||
data: JSON.stringify({}),
|
||||
})
|
||||
.execute();
|
||||
|
||||
await DB.insertInto("chart")
|
||||
.values([
|
||||
{
|
||||
id: chartA,
|
||||
legacy_id: chartA,
|
||||
game: "iidx-sp",
|
||||
song_id: songId,
|
||||
level: "9",
|
||||
level_num: 9,
|
||||
is_primary: true,
|
||||
difficulty: "NORMAL",
|
||||
versions: ["epolis"],
|
||||
data: JSON.stringify({}),
|
||||
},
|
||||
{
|
||||
id: chartB,
|
||||
legacy_id: chartB,
|
||||
game: "iidx-sp",
|
||||
song_id: songId,
|
||||
level: "10",
|
||||
level_num: 10,
|
||||
is_primary: true,
|
||||
difficulty: "HYPER",
|
||||
versions: ["epolis"],
|
||||
data: JSON.stringify({}),
|
||||
},
|
||||
{
|
||||
id: otherGameChart,
|
||||
legacy_id: otherGameChart,
|
||||
game: "sdvx",
|
||||
song_id: songId,
|
||||
level: "9",
|
||||
level_num: 9,
|
||||
is_primary: true,
|
||||
difficulty: "EXHAUST",
|
||||
versions: ["epolis"],
|
||||
data: JSON.stringify({}),
|
||||
},
|
||||
])
|
||||
.execute();
|
||||
|
||||
await DB.insertInto("folder")
|
||||
.values({
|
||||
id: folderId,
|
||||
legacy_id: folderLegacy,
|
||||
game: "iidx-sp",
|
||||
inactive: false,
|
||||
title: "OR game filter",
|
||||
slug: folderId,
|
||||
where: "chart.level_num = 9 OR chart.level_num = 10",
|
||||
version_filter: ["epolis"],
|
||||
search_terms: [],
|
||||
})
|
||||
.execute();
|
||||
|
||||
const { folderQuery: built } = await BuildFolderQuery(folderId);
|
||||
const { rows } = await built.execute(DB);
|
||||
const got = new Set((rows as Array<{ id: string }>).map((r) => r.id));
|
||||
|
||||
expect(got.size).toBe(2);
|
||||
expect(got.has(chartA)).toBe(true);
|
||||
expect(got.has(chartB)).toBe(true);
|
||||
expect(got.has(otherGameChart)).toBe(false);
|
||||
});
|
||||
|
||||
it("with version_filter, requires overlapping chart.versions", async () => {
|
||||
const { folderId, folderLegacy, songId, chartA, chartB } = ids("bfq2");
|
||||
|
||||
|
||||
Reference in New Issue
Block a user