mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-05-31 12:14:46 -04:00
Finish filter parser
This commit is contained in:
parent
df41694811
commit
81b7d5558e
@ -1,4 +1,13 @@
|
|||||||
import { digit, float, int, noCharOf, type Parjser, string } from "parjs";
|
import {
|
||||||
|
anyStringOf,
|
||||||
|
digit,
|
||||||
|
float,
|
||||||
|
int,
|
||||||
|
letter,
|
||||||
|
noCharOf,
|
||||||
|
type Parjser,
|
||||||
|
string,
|
||||||
|
} from "parjs";
|
||||||
import {
|
import {
|
||||||
exactly,
|
exactly,
|
||||||
many,
|
many,
|
||||||
@ -8,7 +17,11 @@ import {
|
|||||||
stringify,
|
stringify,
|
||||||
then,
|
then,
|
||||||
thenq,
|
thenq,
|
||||||
|
qthen,
|
||||||
|
later,
|
||||||
|
between,
|
||||||
} from "parjs/combinators";
|
} from "parjs/combinators";
|
||||||
|
import type { KError } from "../error";
|
||||||
|
|
||||||
export type Filter = {
|
export type Filter = {
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
@ -19,12 +32,14 @@ type Value =
|
|||||||
| { type: "int"; value: number }
|
| { type: "int"; value: number }
|
||||||
| { type: "float"; value: number }
|
| { type: "float"; value: number }
|
||||||
| { type: "date"; value: string }
|
| { type: "date"; value: string }
|
||||||
| { type: "string"; value: string };
|
| { type: "string"; value: string }
|
||||||
type Operator = "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "has" | "in";
|
| { type: "enum"; value: string };
|
||||||
type Expression =
|
const operators = ["eq", "ne", "gt", "ge", "lt", "le", "has", "in"] as const;
|
||||||
|
type Operator = (typeof operators)[number];
|
||||||
|
export type Expression =
|
||||||
| { type: "op"; operator: Operator; property: Property; value: Value }
|
| { type: "op"; operator: Operator; property: Property; value: Value }
|
||||||
| { type: "and"; first: Expression; second: Expression }
|
| { type: "and"; lhs: Expression; rhs: Expression }
|
||||||
| { type: "or"; first: Expression; second: Expression }
|
| { type: "or"; lhs: Expression; rhs: Expression }
|
||||||
| { type: "not"; expression: Expression };
|
| { type: "not"; expression: Expression };
|
||||||
|
|
||||||
function t<T>(parser: Parjser<T>): Parjser<T> {
|
function t<T>(parser: Parjser<T>): Parjser<T> {
|
||||||
@ -32,6 +47,8 @@ function t<T>(parser: Parjser<T>): Parjser<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const str = t(noCharOf(" ")).pipe(many1(), stringify()).expects("a string");
|
const str = t(noCharOf(" ")).pipe(many1(), stringify()).expects("a string");
|
||||||
|
const enumP = t(letter()).pipe(many1(), stringify()).expects("an enum value");
|
||||||
|
|
||||||
const property = str.expects("a property");
|
const property = str.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 }))));
|
||||||
@ -52,11 +69,52 @@ const dateVal = t(
|
|||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
const strVal = t(str.pipe(map((s) => ({ type: "string" as const, value: s }))));
|
const strVal = str.pipe(map((s) => ({ type: "string" as const, value: s })));
|
||||||
|
const enumVal = enumP.pipe(map((e) => ({ type: "enum" as const, value: e })));
|
||||||
const value = intVal
|
const value = intVal
|
||||||
.pipe(or(floatVal, dateVal, strVal))
|
.pipe(or(floatVal, dateVal, strVal, enumVal))
|
||||||
.expects("a valid value");
|
.expects("a valid value");
|
||||||
|
|
||||||
const operator = null;
|
const operator = t(anyStringOf(...operators)).expects("an operator");
|
||||||
|
|
||||||
export const parseFilter = (filter: string, config: Filter) => {};
|
const operation = property
|
||||||
|
.pipe(
|
||||||
|
then(operator, value),
|
||||||
|
map(([property, operator, value]) => ({
|
||||||
|
type: "op" as const,
|
||||||
|
property,
|
||||||
|
operator,
|
||||||
|
value,
|
||||||
|
})),
|
||||||
|
)
|
||||||
|
.expects("an operation");
|
||||||
|
|
||||||
|
export const expression = later<Expression>();
|
||||||
|
|
||||||
|
const not = t(string("not")).pipe(
|
||||||
|
qthen(expression),
|
||||||
|
map((expression) => ({ type: "not" as const, expression })),
|
||||||
|
);
|
||||||
|
|
||||||
|
const andor = operation.pipe(
|
||||||
|
then(anyStringOf("and", "or").pipe(then(expression), many())),
|
||||||
|
map(([first, expr]) =>
|
||||||
|
expr.reduce<Expression>(
|
||||||
|
(lhs, [op, rhs]) => ({ type: op, lhs, rhs }),
|
||||||
|
first,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expression.init(
|
||||||
|
not.pipe(or(operation, expression.pipe(or(andor), between("(", ")")))),
|
||||||
|
);
|
||||||
|
|
||||||
|
export const parseFilter = (
|
||||||
|
filter: string,
|
||||||
|
config: Filter,
|
||||||
|
): Expression | KError => {
|
||||||
|
const ret = expression.parse(filter);
|
||||||
|
if (ret.isOk) return ret.value;
|
||||||
|
return { status: 422, message: `Invalid filter: ${filter}.`, details: ret };
|
||||||
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user