-
Notifications
You must be signed in to change notification settings - Fork 10
/
query-parser.ts
104 lines (84 loc) · 2.32 KB
/
query-parser.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
import { snakeCase } from "./snake-case";
import { Model } from "objection";
import * as Objection from "objection";
export interface QueryFilter {
key: string;
op: string;
value: string;
}
type OrderByDirection = "asc" | "desc" | "ASC" | "DESC";
export interface QueryOrder {
key: string;
direction: OrderByDirection;
}
export interface Query {
limit: number;
page?: number;
filters: QueryFilter[];
orders: QueryOrder[];
}
export const blankQuery = (limit = 10): Query => ({
limit,
filters: [],
orders: [],
});
export function parseQuery(reqQuery: any): Query {
const filters: QueryFilter[] = [];
const orders: QueryOrder[] = [];
// TODO Implement properly
if (reqQuery.after) {
filters.push({ key: "id", op: ">", value: reqQuery.after });
orders.push({ key: "id", direction: "ASC" });
}
if (reqQuery.filter) {
reqQuery.filter.split(":").forEach(f => {
const match = f.replace(/[()]/g, "").match(/(.*),(.*),(.*)/);
if (!match) {
return;
}
filters.push({ key: snakeCase(match[1]), op: match[2], value: match[3] });
});
}
if (reqQuery.orderBy) {
reqQuery.orderBy.split(":").forEach(q => {
const match = q.replace(/[()]/g, "").match(/(.*),(.*)/);
if (!match) {
return;
}
orders.push({ key: snakeCase(match[1]), direction: match[2] });
});
}
const limit = reqQuery.limit ? parseInt(reqQuery.limit) : 20;
const page = reqQuery.page ? parseInt(reqQuery.page) : undefined; // Explicitly undefined
return {
limit,
page,
filters,
orders,
};
}
export function applyQuery<M extends Model, R = M[]>(
query: Query,
dbQuery: Objection.QueryBuilder<M, R>,
): Objection.QueryBuilder<M, R> {
if (query.page) {
const offset = query.page == 1 ? 0 : (query.page - 1) * query.limit;
dbQuery = dbQuery.offset(offset);
}
for (const filter of query.filters) {
if (filter.value === "null") {
if (filter.op === "=") {
dbQuery = dbQuery.whereNull(filter.key);
} else {
dbQuery = dbQuery.whereNotNull(filter.key);
}
} else {
dbQuery = dbQuery.where(filter.key, filter.op, filter.value);
}
}
for (const order of query.orders) {
dbQuery = dbQuery.orderBy(order.key, order.direction);
}
dbQuery = dbQuery.limit(query.limit);
return dbQuery;
}