From d8a5f3c2be985c4fcbedfda09564ae5d02e6e5b4 Mon Sep 17 00:00:00 2001 From: Pieter Vander Vennet Date: Tue, 16 May 2023 01:33:58 +0200 Subject: [PATCH] Fix: correctly optimize 'key=A&key!=B' into 'key=A' --- Logic/Tags/And.ts | 22 ++++++++++++++++++++-- test/Logic/Tags/OptimizeTags.spec.ts | 24 ++++++++++++++++-------- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/Logic/Tags/And.ts b/Logic/Tags/And.ts index 771dffe53..04c79a83c 100644 --- a/Logic/Tags/And.ts +++ b/Logic/Tags/And.ts @@ -243,7 +243,9 @@ export class And extends TagsFilter { properties[opt.key] = opt.value } } - for (const opt of optimized) { + + for (let i = 0; i < optimized.length; i++){ + const opt = optimized[i]; if (opt instanceof Tag) { const k = opt.key const v = properties[k] @@ -264,7 +266,23 @@ export class And extends TagsFilter { if (v === undefined) { continue } - if (v !== opt.value) { + if(opt.invert){ + // We should _not_ match this value + // If 'v' is given, we already know what value it should be + // If 'v' is the not-expected value, we have a conflict and return false + // Otherwise, we can safely drop this value + + const doesMatch = (typeof opt.value === "string" && v === opt.value) || + (v.match( opt.value) !== null) + + if(doesMatch){ + // We have a conflict as 'opt' is inverted + return false + }else{ + optimized.splice(i, 1) + i-- + } + }else if (v !== opt.value) { // detected an internal conflict return false } diff --git a/test/Logic/Tags/OptimizeTags.spec.ts b/test/Logic/Tags/OptimizeTags.spec.ts index ab7127d72..06110eb54 100644 --- a/test/Logic/Tags/OptimizeTags.spec.ts +++ b/test/Logic/Tags/OptimizeTags.spec.ts @@ -1,10 +1,10 @@ -import { TagsFilter } from "../../../Logic/Tags/TagsFilter" -import { And } from "../../../Logic/Tags/And" -import { Tag } from "../../../Logic/Tags/Tag" -import { TagUtils } from "../../../Logic/Tags/TagUtils" -import { Or } from "../../../Logic/Tags/Or" -import { RegexTag } from "../../../Logic/Tags/RegexTag" -import { describe, expect, it } from "vitest" +import {TagsFilter} from "../../../Logic/Tags/TagsFilter" +import {And} from "../../../Logic/Tags/And" +import {Tag} from "../../../Logic/Tags/Tag" +import {TagUtils} from "../../../Logic/Tags/TagUtils" +import {Or} from "../../../Logic/Tags/Or" +import {RegexTag} from "../../../Logic/Tags/RegexTag" +import {describe, expect, it} from "vitest" describe("Tag optimalization", () => { describe("And", () => { @@ -71,6 +71,14 @@ describe("Tag optimalization", () => { expect(TagUtils.toString(opt)).toBe("amenity=binoculars&bicycle=yes") }) + it("should correctly optimize key=A&key!=B into key=A", () => { + const t = new And([new Tag("shop", "sports"), new RegexTag("shop", "mall", true)]) + const opt = t.optimize() + expect(typeof opt !== "boolean").true + expect(TagUtils.toString(opt)).toBe("shop=sports") + + }) + it("should optimize nested ORs", () => { const filter = TagUtils.Tag({ or: [ @@ -263,7 +271,7 @@ describe("Tag optimalization", () => { or: [ "club=climbing", { - and: ["sport=climbing", { or: ["club~*", "office~*"] }], + and: ["sport=climbing", {or: ["club~*", "office~*"]}], }, { and: [