-
Notifications
You must be signed in to change notification settings - Fork 140
/
query.helpers.ts
74 lines (67 loc) · 2.49 KB
/
query.helpers.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
import merge from 'lodash.merge';
import { Filter, Query, SortField } from '../interfaces';
import { FilterBuilder } from './filter.builder';
export type QueryFieldMap<From, To> = {
[F in keyof From]?: keyof To;
};
export const transformSort = <From, To>(
sorting: SortField<From>[] | undefined,
fieldMap: QueryFieldMap<From, To>,
): SortField<To>[] | undefined => {
if (!sorting) {
return undefined;
}
return sorting.map((sf) => {
const field = fieldMap[sf.field];
if (!field) {
throw new Error(`No corresponding field found for '${sf.field as string}' when transforming SortField`);
}
return { ...sf, field } as SortField<To>;
});
};
export const transformFilter = <From, To>(
filter: Filter<From> | undefined,
fieldMap: QueryFieldMap<From, To>,
): Filter<To> | undefined => {
if (!filter) {
return undefined;
}
return Object.keys(filter).reduce((newFilter, filterField) => {
if (filterField === 'and' || filterField === 'or') {
return { ...newFilter, [filterField]: filter[filterField]?.map((f) => transformFilter(f, fieldMap)) };
}
const fromField = filterField as keyof From;
const otherKey = fieldMap[fromField];
if (!otherKey) {
throw new Error(`No corresponding field found for '${filterField}' when transforming Filter`);
}
return { ...newFilter, [otherKey as string]: filter[fromField] };
}, {} as Filter<To>);
};
export const transformQuery = <From, To>(query: Query<From>, fieldMap: QueryFieldMap<From, To>): Query<To> => {
return {
filter: transformFilter(query.filter, fieldMap),
paging: query.paging,
sorting: transformSort(query.sorting, fieldMap),
};
};
export const mergeQuery = <T>(base: Query<T>, source: Query<T>): Query<T> => {
return merge(base, source);
};
export const getFilterFields = <DTO>(filter: Filter<DTO>): string[] => {
const fieldSet: Set<string> = Object.keys(filter).reduce((fields: Set<string>, filterField: string): Set<string> => {
if (filterField === 'and' || filterField === 'or') {
const andOrFilters = filter[filterField];
if (andOrFilters !== undefined) {
return andOrFilters.reduce((andOrFields, andOrFilter) => {
return new Set<string>([...andOrFields, ...getFilterFields(andOrFilter)]);
}, fields);
}
} else {
fields.add(filterField);
}
return fields;
}, new Set<string>());
return [...fieldSet];
};
export const applyFilter = <DTO>(dto: DTO, filter: Filter<DTO>): boolean => FilterBuilder.build(filter)(dto);