-
Notifications
You must be signed in to change notification settings - Fork 1.8k
/
sort.ts
132 lines (115 loc) · 3.5 KB
/
sort.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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import { MongoInvalidArgumentError } from './error';
/** @public */
export type SortDirection =
| 1
| -1
| 'asc'
| 'desc'
| 'ascending'
| 'descending'
| { $meta: string };
/** @public */
export type Sort =
| string
| Exclude<SortDirection, { $meta: string }>
| string[]
| { [key: string]: SortDirection }
| Map<string, SortDirection>
| [string, SortDirection][]
| [string, SortDirection];
/** Below stricter types were created for sort that correspond with type that the cmd takes */
/** @internal */
export type SortDirectionForCmd = 1 | -1 | { $meta: string };
/** @internal */
export type SortForCmd = Map<string, SortDirectionForCmd>;
/** @internal */
type SortPairForCmd = [string, SortDirectionForCmd];
/** @internal */
function prepareDirection(direction: any = 1): SortDirectionForCmd {
const value = `${direction}`.toLowerCase();
if (isMeta(direction)) return direction;
switch (value) {
case 'ascending':
case 'asc':
case '1':
return 1;
case 'descending':
case 'desc':
case '-1':
return -1;
default:
throw new MongoInvalidArgumentError(`Invalid sort direction: ${JSON.stringify(direction)}`);
}
}
/** @internal */
function isMeta(t: SortDirection): t is { $meta: string } {
return typeof t === 'object' && t != null && '$meta' in t && typeof t.$meta === 'string';
}
/** @internal */
function isPair(t: Sort): t is [string, SortDirection] {
if (Array.isArray(t) && t.length === 2) {
try {
prepareDirection(t[1]);
return true;
} catch (e) {
return false;
}
}
return false;
}
function isDeep(t: Sort): t is [string, SortDirection][] {
return Array.isArray(t) && Array.isArray(t[0]);
}
function isMap(t: Sort): t is Map<string, SortDirection> {
return t instanceof Map && t.size > 0;
}
/** @internal */
function pairToMap(v: [string, SortDirection]): SortForCmd {
return new Map([[`${v[0]}`, prepareDirection([v[1]])]]);
}
/** @internal */
function deepToMap(t: [string, SortDirection][]): SortForCmd {
const sortEntries: SortPairForCmd[] = t.map(([k, v]) => [`${k}`, prepareDirection(v)]);
return new Map(sortEntries);
}
/** @internal */
function stringsToMap(t: string[]): SortForCmd {
const sortEntries: SortPairForCmd[] = t.map(key => [`${key}`, 1]);
return new Map(sortEntries);
}
/** @internal */
function objectToMap(t: { [key: string]: SortDirection }): SortForCmd {
const sortEntries: SortPairForCmd[] = Object.entries(t).map(([k, v]) => [
`${k}`,
prepareDirection(v)
]);
return new Map(sortEntries);
}
/** @internal */
function mapToMap(t: Map<string, SortDirection>): SortForCmd {
const sortEntries: SortPairForCmd[] = Array.from(t).map(([k, v]) => [
`${k}`,
prepareDirection(v)
]);
return new Map(sortEntries);
}
/** converts a Sort type into a type that is valid for the server (SortForCmd) */
export function formatSort(
sort: Sort | undefined,
direction?: SortDirection
): SortForCmd | undefined {
if (sort == null) return undefined;
if (typeof sort === 'string') return new Map([[sort, prepareDirection(direction)]]);
if (typeof sort !== 'object') {
throw new MongoInvalidArgumentError(
`Invalid sort format: ${JSON.stringify(sort)} Sort must be a valid object`
);
}
if (!Array.isArray(sort)) {
return isMap(sort) ? mapToMap(sort) : Object.keys(sort).length ? objectToMap(sort) : undefined;
}
if (!sort.length) return undefined;
if (isDeep(sort)) return deepToMap(sort);
if (isPair(sort)) return pairToMap(sort);
return stringsToMap(sort);
}