Allow filter string to match without quotes

This commit is contained in:
Zoe Roux 2025-01-24 18:52:58 +01:00
parent 1c0fdf6f89
commit 426665c9d9
3 changed files with 50 additions and 6 deletions

View File

@ -42,10 +42,9 @@ function t<T>(parser: Parjser<T>): Parjser<T> {
return parser.pipe(thenq(string(" ").pipe(many()))); return parser.pipe(thenq(string(" ").pipe(many())));
} }
const str = t(noCharOf(" ").pipe(many1(), stringify()).expects("a string"));
const enumP = t(letter().pipe(many1(), stringify()).expects("an enum value")); const enumP = t(letter().pipe(many1(), stringify()).expects("an enum value"));
const property = str.expects("a property"); const property = t(letter().pipe(many1(), stringify())).expects("a property");
const intVal = t(int().pipe(map((i) => ({ type: "int" as const, value: i })))); const intVal = t(int().pipe(map((i) => ({ type: "int" as const, value: i }))));
const floatVal = t( const floatVal = t(
@ -66,9 +65,11 @@ const dateVal = t(
})), })),
), ),
).expects("a date"); ).expects("a date");
const strVal = str.pipe( const strVal = t(noCharOf('"').pipe(many1(), stringify(), between('"'))).pipe(
between('"'), or(
or(str.pipe(between("'"))), noCharOf("'").pipe(many1(), stringify(), between("'")),
noCharOf(" ").pipe(many1(), stringify()),
),
map((s) => ({ type: "string" as const, value: s })), map((s) => ({ type: "string" as const, value: s })),
); );
const enumVal = enumP.pipe(map((e) => ({ type: "enum" as const, value: e }))); const enumVal = enumP.pipe(map((e) => ({ type: "enum" as const, value: e })));
@ -76,7 +77,7 @@ const value = dateVal
.pipe( .pipe(
// until we get the `-` character, this could be an int or a float. // until we get the `-` character, this could be an int or a float.
recover(() => ({ kind: "Soft" })), recover(() => ({ kind: "Soft" })),
or(intVal, floatVal, strVal, enumVal), or(intVal, floatVal, enumVal, strVal),
) )
.expects("a valid value"); .expects("a valid value");

View File

@ -42,6 +42,11 @@ export const toDrizzle = (expr: Expression, config: FilterDef): SQL => {
); );
} }
if (expr.value.type === "enum" && prop.type === "string") {
// promote enum to string since this is legal
// but parser doesn't know if an enum should be a string
expr.value = { type: "string", value: expr.value.value };
}
if (prop.type !== expr.value.type) { if (prop.type !== expr.value.type) {
throw new KErrorT( throw new KErrorT(
comment` comment`

View File

@ -170,4 +170,42 @@ describe("Parse filter", () => {
}, },
}); });
}); });
it('Handle eq with " string', () => {
const ret = parse('tags eq "magic armor"');
expect(ret).toMatchObject({
ok: true,
value: {
type: "op",
operator: "eq",
property: "tags",
value: { type: "string", value: "magic armor" },
},
});
});
it("Handle eq with ' string", () => {
const ret = parse("tags eq 'magic armor'");
expect(ret).toMatchObject({
ok: true,
value: {
type: "op",
operator: "eq",
property: "tags",
value: { type: "string", value: "magic armor" },
},
});
});
it("Handle eq with string, no quote", () => {
const ret = parse("tags eq magic");
expect(ret).toMatchObject({
ok: true,
value: {
type: "op",
operator: "eq",
property: "tags",
// this is parsed as enum but is handled afterwards
value: { type: "enum", value: "magic" },
},
});
});
}); });