@feathersjs/adapter-commons 5.0.0-pre.2 → 5.0.0-pre.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +202 -16
- package/LICENSE +1 -1
- package/README.md +2 -2
- package/lib/declarations.d.ts +146 -0
- package/lib/declarations.js +3 -0
- package/lib/declarations.js.map +1 -0
- package/lib/index.d.ts +5 -3
- package/lib/index.js +18 -17
- package/lib/index.js.map +1 -1
- package/lib/query.d.ts +21 -0
- package/lib/query.js +116 -0
- package/lib/query.js.map +1 -0
- package/lib/service.d.ts +86 -62
- package/lib/service.js +129 -65
- package/lib/service.js.map +1 -1
- package/lib/sort.d.ts +6 -4
- package/lib/sort.js +35 -47
- package/lib/sort.js.map +1 -1
- package/package.json +16 -15
- package/src/declarations.ts +153 -0
- package/src/index.ts +10 -13
- package/src/query.ts +138 -0
- package/src/service.ts +205 -151
- package/src/sort.ts +33 -53
- package/lib/filter-query.d.ts +0 -10
- package/lib/filter-query.js +0 -96
- package/lib/filter-query.js.map +0 -1
- package/src/filter-query.ts +0 -116
package/src/service.ts
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
export interface Paginated<T> {
|
|
6
|
-
total: number;
|
|
7
|
-
limit: number;
|
|
8
|
-
skip: number;
|
|
9
|
-
data: T[];
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const callMethod = (self: any, name: any, ...args: any[]) => {
|
|
13
|
-
if (typeof self[name] !== 'function') {
|
|
14
|
-
return Promise.reject(new NotImplemented(`Method ${name} not available`));
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return self[name](...args);
|
|
18
|
-
};
|
|
1
|
+
import { BadRequest, MethodNotAllowed } from '@feathersjs/errors';
|
|
2
|
+
import { Id, NullableId, Paginated, Query } from '@feathersjs/feathers';
|
|
3
|
+
import { AdapterParams, AdapterServiceOptions, InternalServiceMethods, PaginationOptions } from './declarations';
|
|
4
|
+
import { filterQuery } from './query';
|
|
19
5
|
|
|
20
6
|
const alwaysMulti: { [key: string]: boolean } = {
|
|
21
7
|
find: true,
|
|
@@ -23,60 +9,180 @@ const alwaysMulti: { [key: string]: boolean } = {
|
|
|
23
9
|
update: false
|
|
24
10
|
};
|
|
25
11
|
|
|
26
|
-
export interface ServiceOptions {
|
|
27
|
-
events: string[];
|
|
28
|
-
multi: boolean|string[];
|
|
29
|
-
id: string;
|
|
30
|
-
paginate: {
|
|
31
|
-
default?: number;
|
|
32
|
-
max?: number;
|
|
33
|
-
}
|
|
34
|
-
whitelist: string[];
|
|
35
|
-
filters: string[];
|
|
36
|
-
}
|
|
37
|
-
|
|
38
12
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* from the service and don't want to trigger any of its hooks.
|
|
42
|
-
*
|
|
43
|
-
* Important: These methods are only available internally on the server, not on the client
|
|
44
|
-
* side and only for the Feathers database adapters.
|
|
45
|
-
*
|
|
46
|
-
* These methods do not trigger events.
|
|
47
|
-
*
|
|
48
|
-
* @see {@link https://docs.feathersjs.com/guides/migrating.html#hook-less-service-methods}
|
|
13
|
+
* An abstract base class that a database adapter can extend from to implement the
|
|
14
|
+
* `__find`, `__get`, `__update`, `__patch` and `__remove` methods.
|
|
49
15
|
*/
|
|
50
|
-
export
|
|
16
|
+
export abstract class AdapterBase<
|
|
17
|
+
T = any,
|
|
18
|
+
D = Partial<T>,
|
|
19
|
+
P extends AdapterParams = AdapterParams,
|
|
20
|
+
O extends AdapterServiceOptions = AdapterServiceOptions
|
|
21
|
+
> implements InternalServiceMethods<T, D, P> {
|
|
22
|
+
options: O;
|
|
23
|
+
|
|
24
|
+
constructor (options: O) {
|
|
25
|
+
this.options = {
|
|
26
|
+
id: 'id',
|
|
27
|
+
events: [],
|
|
28
|
+
paginate: false,
|
|
29
|
+
multi: false,
|
|
30
|
+
filters: {},
|
|
31
|
+
operators: [],
|
|
32
|
+
...options
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get id () {
|
|
37
|
+
return this.options.id;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get events () {
|
|
41
|
+
return this.options.events;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Check if this adapter allows multiple updates for a method.
|
|
46
|
+
* @param method The method name to check.
|
|
47
|
+
* @param params The service call params.
|
|
48
|
+
* @returns Wether or not multiple updates are allowed.
|
|
49
|
+
*/
|
|
50
|
+
allowsMulti (method: string, params: P = {} as P) {
|
|
51
|
+
const always = alwaysMulti[method];
|
|
52
|
+
|
|
53
|
+
if (typeof always !== 'undefined') {
|
|
54
|
+
return always;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const { multi } = this.getOptions(params);
|
|
58
|
+
|
|
59
|
+
if (multi === true || multi === false) {
|
|
60
|
+
return multi;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return multi.includes(method);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Returns the combined options for a service call. Options will be merged
|
|
68
|
+
* with `this.options` and `params.adapter` for dynamic overrides.
|
|
69
|
+
*
|
|
70
|
+
* @param params The parameters for the service method call
|
|
71
|
+
* @returns The actual options for this call
|
|
72
|
+
*/
|
|
73
|
+
getOptions (params: P): O {
|
|
74
|
+
const paginate = params.paginate !== undefined ? params.paginate : this.options.paginate;
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
...this.options,
|
|
78
|
+
paginate,
|
|
79
|
+
...params.adapter
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Sanitize the incoming data, e.g. removing invalid keywords etc.
|
|
85
|
+
*
|
|
86
|
+
* @param data The data to sanitize
|
|
87
|
+
* @param _params Service call parameters
|
|
88
|
+
* @returns The sanitized data
|
|
89
|
+
*/
|
|
90
|
+
async sanitizeData<X = Partial<D>> (data: X, _params: P) {
|
|
91
|
+
return data;
|
|
92
|
+
}
|
|
51
93
|
|
|
52
94
|
/**
|
|
53
|
-
*
|
|
95
|
+
* Returns a sanitized version of `params.query`, converting filter values
|
|
96
|
+
* (like $limit and $skip) into the expected type. Will throw an error if
|
|
97
|
+
* a `$` prefixed filter or operator value that is not allowed in `filters`
|
|
98
|
+
* or `operators` is encountered.
|
|
99
|
+
*
|
|
100
|
+
* @param params The service call parameter.
|
|
101
|
+
* @returns A new object containing the sanitized query.
|
|
102
|
+
*/
|
|
103
|
+
async sanitizeQuery (params: P = {} as P): Promise<Query> {
|
|
104
|
+
const options = this.getOptions(params);
|
|
105
|
+
const { query, filters } = filterQuery(params.query, options)
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
...filters,
|
|
109
|
+
...query
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
abstract $find(_params?: P & { paginate?: PaginationOptions }): Promise<Paginated<T>>;
|
|
114
|
+
abstract $find(_params?: P & { paginate: false }): Promise<T[]>;
|
|
115
|
+
abstract $find(params?: P): Promise<T[] | Paginated<T>>;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Retrieve all resources from this service, skipping any service-level hooks but sanitize the query
|
|
119
|
+
* with allowed filters and properties by calling `sanitizeQuery`.
|
|
54
120
|
*
|
|
55
121
|
* @param params - Service call parameters {@link Params}
|
|
56
122
|
* @see {@link HookLessServiceMethods}
|
|
57
123
|
* @see {@link https://docs.feathersjs.com/api/services.html#find-params|Feathers API Documentation: .find(params)}
|
|
58
124
|
*/
|
|
59
|
-
_find
|
|
125
|
+
async _find(_params?: P & { paginate?: PaginationOptions }): Promise<Paginated<T>>;
|
|
126
|
+
async _find(_params?: P & { paginate: false }): Promise<T[]>;
|
|
127
|
+
async _find(params?: P): Promise<T | T[] | Paginated<T>>;
|
|
128
|
+
async _find (params?: P): Promise<T | T[] | Paginated<T>> {
|
|
129
|
+
const query = await this.sanitizeQuery(params);
|
|
130
|
+
|
|
131
|
+
return this.$find({
|
|
132
|
+
...params,
|
|
133
|
+
query
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
abstract $get(id: Id, params?: P): Promise<T>;
|
|
60
138
|
|
|
61
139
|
/**
|
|
62
|
-
* Retrieve a single resource matching the given ID, skipping any service-level hooks
|
|
140
|
+
* Retrieve a single resource matching the given ID, skipping any service-level hooks but sanitize the query
|
|
141
|
+
* with allowed filters and properties by calling `sanitizeQuery`.
|
|
63
142
|
*
|
|
64
143
|
* @param id - ID of the resource to locate
|
|
65
144
|
* @param params - Service call parameters {@link Params}
|
|
66
145
|
* @see {@link HookLessServiceMethods}
|
|
67
146
|
* @see {@link https://docs.feathersjs.com/api/services.html#get-id-params|Feathers API Documentation: .get(id, params)}
|
|
68
147
|
*/
|
|
69
|
-
_get (id: Id, params?:
|
|
148
|
+
async _get (id: Id, params?: P): Promise<T> {
|
|
149
|
+
const query = await this.sanitizeQuery(params);
|
|
150
|
+
|
|
151
|
+
return this.$get(id, {
|
|
152
|
+
...params,
|
|
153
|
+
query
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
abstract $create(data: Partial<D>, params?: P): Promise<T>;
|
|
158
|
+
abstract $create(data: Partial<D>[], params?: P): Promise<T[]>;
|
|
159
|
+
abstract $create(data: Partial<D> | Partial<D>[], params?: P): Promise<T | T[]>;
|
|
70
160
|
|
|
71
161
|
/**
|
|
72
|
-
* Create a new resource for this service, skipping any service-level hooks
|
|
162
|
+
* Create a new resource for this service, skipping any service-level hooks, sanitize the data
|
|
163
|
+
* and check if multiple updates are allowed.
|
|
73
164
|
*
|
|
74
165
|
* @param data - Data to insert into this service.
|
|
75
166
|
* @param params - Service call parameters {@link Params}
|
|
76
167
|
* @see {@link HookLessServiceMethods}
|
|
77
168
|
* @see {@link https://docs.feathersjs.com/api/services.html#create-data-params|Feathers API Documentation: .create(data, params)}
|
|
78
169
|
*/
|
|
79
|
-
_create
|
|
170
|
+
async _create(data: Partial<D>, params?: P): Promise<T>;
|
|
171
|
+
async _create(data: Partial<D>[], params?: P): Promise<T[]>;
|
|
172
|
+
async _create(data: Partial<D> | Partial<D>[], params?: P): Promise<T | T[]>;
|
|
173
|
+
async _create (data: Partial<D> | Partial<D>[], params?: P): Promise<T | T[]> {
|
|
174
|
+
if (Array.isArray(data) && !this.allowsMulti('create', params)) {
|
|
175
|
+
throw new MethodNotAllowed('Can not create multiple entries');
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const payload = Array.isArray(data)
|
|
179
|
+
? (await Promise.all(data.map(current => this.sanitizeData(current, params))))
|
|
180
|
+
: (await this.sanitizeData(data, params));
|
|
181
|
+
|
|
182
|
+
return this.$create(payload, params);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
abstract $update(id: Id, data: D, params?: P): Promise<T>;
|
|
80
186
|
|
|
81
187
|
/**
|
|
82
188
|
* Replace any resources matching the given ID with the given data, skipping any service-level hooks.
|
|
@@ -87,10 +193,29 @@ export interface InternalServiceMethods<T = any> {
|
|
|
87
193
|
* @see {@link HookLessServiceMethods}
|
|
88
194
|
* @see {@link https://docs.feathersjs.com/api/services.html#update-id-data-params|Feathers API Documentation: .update(id, data, params)}
|
|
89
195
|
*/
|
|
90
|
-
_update (id: Id, data:
|
|
196
|
+
async _update (id: Id, data: D, params?: P): Promise<T> {
|
|
197
|
+
if (id === null || Array.isArray(data)) {
|
|
198
|
+
throw new BadRequest(
|
|
199
|
+
'You can not replace multiple instances. Did you mean \'patch\'?'
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const payload = await this.sanitizeData(data, params);
|
|
204
|
+
const query = await this.sanitizeQuery(params);
|
|
205
|
+
|
|
206
|
+
return this.$update(id, payload, {
|
|
207
|
+
...params,
|
|
208
|
+
query
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
abstract $patch(id: null, data: Partial<D>, params?: P): Promise<T[]>;
|
|
213
|
+
abstract $patch(id: Id, data: Partial<D>, params?: P): Promise<T>;
|
|
214
|
+
abstract $patch(id: NullableId, data: Partial<D>, params?: P): Promise<T | T[]>;
|
|
91
215
|
|
|
92
216
|
/**
|
|
93
217
|
* Merge any resources matching the given ID with the given data, skipping any service-level hooks.
|
|
218
|
+
* Sanitizes the query and data and checks it multiple updates are allowed.
|
|
94
219
|
*
|
|
95
220
|
* @param id - ID of the resource to be patched
|
|
96
221
|
* @param data - Data to merge with the current resource.
|
|
@@ -98,120 +223,49 @@ export interface InternalServiceMethods<T = any> {
|
|
|
98
223
|
* @see {@link HookLessServiceMethods}
|
|
99
224
|
* @see {@link https://docs.feathersjs.com/api/services.html#patch-id-data-params|Feathers API Documentation: .patch(id, data, params)}
|
|
100
225
|
*/
|
|
101
|
-
_patch
|
|
226
|
+
async _patch(id: null, data: Partial<D>, params?: P): Promise<T[]>;
|
|
227
|
+
async _patch(id: Id, data: Partial<D>, params?: P): Promise<T>;
|
|
228
|
+
async _patch(id: NullableId, data: Partial<D>, params?: P): Promise<T | T[]>;
|
|
229
|
+
async _patch (id: NullableId, data: Partial<D>, params?: P): Promise<T | T[]> {
|
|
230
|
+
if (id === null && !this.allowsMulti('patch', params)) {
|
|
231
|
+
throw new MethodNotAllowed('Can not patch multiple entries');
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const query = await this.sanitizeQuery(params);
|
|
235
|
+
const payload = await this.sanitizeData(data, params);
|
|
236
|
+
|
|
237
|
+
return this.$patch(id, payload, {
|
|
238
|
+
...params,
|
|
239
|
+
query
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
abstract $remove(id: null, params?: P): Promise<T[]>;
|
|
244
|
+
abstract $remove(id: Id, params?: P): Promise<T>;
|
|
245
|
+
abstract $remove(id: NullableId, params?: P): Promise<T | T[]>;
|
|
102
246
|
|
|
103
247
|
/**
|
|
104
248
|
* Remove resources matching the given ID from the this service, skipping any service-level hooks.
|
|
249
|
+
* Sanitized the query and verifies that multiple updates are allowed.
|
|
105
250
|
*
|
|
106
251
|
* @param id - ID of the resource to be removed
|
|
107
252
|
* @param params - Service call parameters {@link Params}
|
|
108
253
|
* @see {@link HookLessServiceMethods}
|
|
109
254
|
* @see {@link https://docs.feathersjs.com/api/services.html#remove-id-params|Feathers API Documentation: .remove(id, params)}
|
|
110
255
|
*/
|
|
111
|
-
_remove
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
constructor (options: Partial<ServiceOptions>) {
|
|
118
|
-
this.options = Object.assign({
|
|
119
|
-
id: 'id',
|
|
120
|
-
events: [],
|
|
121
|
-
paginate: {},
|
|
122
|
-
multi: false,
|
|
123
|
-
filters: [],
|
|
124
|
-
whitelist: []
|
|
125
|
-
}, options);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
get id () {
|
|
129
|
-
return this.options.id;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
get events () {
|
|
133
|
-
return this.options.events;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
filterQuery (params: Params = {}, opts: any = {}) {
|
|
137
|
-
const paginate = typeof params.paginate !== 'undefined'
|
|
138
|
-
? params.paginate : this.options.paginate;
|
|
139
|
-
const { query = {} } = params;
|
|
140
|
-
const options = Object.assign({
|
|
141
|
-
operators: this.options.whitelist || [],
|
|
142
|
-
filters: this.options.filters,
|
|
143
|
-
paginate
|
|
144
|
-
}, opts);
|
|
145
|
-
const result = filterQuery(query, options);
|
|
146
|
-
|
|
147
|
-
return Object.assign(result, { paginate });
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
allowsMulti (method: string) {
|
|
151
|
-
const always = alwaysMulti[method];
|
|
152
|
-
|
|
153
|
-
if (typeof always !== 'undefined') {
|
|
154
|
-
return always;
|
|
256
|
+
async _remove(id: null, params?: P): Promise<T[]>;
|
|
257
|
+
async _remove(id: Id, params?: P): Promise<T>;
|
|
258
|
+
async _remove(id: NullableId, params?: P): Promise<T | T[]>;
|
|
259
|
+
async _remove (id: NullableId, params?: P): Promise<T | T[]> {
|
|
260
|
+
if (id === null && !this.allowsMulti('remove', params)) {
|
|
261
|
+
throw new MethodNotAllowed('Can not remove multiple entries');
|
|
155
262
|
}
|
|
156
263
|
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
if (option === true || option === false) {
|
|
160
|
-
return option;
|
|
161
|
-
} else {
|
|
162
|
-
return option.includes(method);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
264
|
+
const query = await this.sanitizeQuery(params);
|
|
165
265
|
|
|
166
|
-
|
|
167
|
-
|
|
266
|
+
return this.$remove(id, {
|
|
267
|
+
...params,
|
|
268
|
+
query
|
|
269
|
+
});
|
|
168
270
|
}
|
|
169
|
-
|
|
170
|
-
get (id: Id, params?: Params): Promise<T> {
|
|
171
|
-
return callMethod(this, '_get', id, params);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
create (data: Partial<T>, params?: Params): Promise<T>;
|
|
175
|
-
create (data: Partial<T>[], params?: Params): Promise<T[]>;
|
|
176
|
-
create (data: Partial<T> | Partial<T>[], params?: Params): Promise<T | T[]> {
|
|
177
|
-
if (Array.isArray(data) && !this.allowsMulti('create')) {
|
|
178
|
-
return Promise.reject(new MethodNotAllowed('Can not create multiple entries'));
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return callMethod(this, '_create', data, params);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
update (id: Id, data: T, params?: Params): Promise<T> {
|
|
185
|
-
if (id === null || Array.isArray(data)) {
|
|
186
|
-
return Promise.reject(new BadRequest(
|
|
187
|
-
'You can not replace multiple instances. Did you mean \'patch\'?'
|
|
188
|
-
));
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
return callMethod(this, '_update', id, data, params);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
patch (id: Id, data: Partial<T>, params?: Params): Promise<T>;
|
|
195
|
-
patch (id: null, data: Partial<T>, params?: Params): Promise<T[]>;
|
|
196
|
-
patch (id: NullableId, data: Partial<T>, params?: Params): Promise<T | T[]>;
|
|
197
|
-
patch (id: NullableId, data: Partial<T>, params?: Params): Promise<T | T[]> {
|
|
198
|
-
if (id === null && !this.allowsMulti('patch')) {
|
|
199
|
-
return Promise.reject(new MethodNotAllowed('Can not patch multiple entries'));
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
return callMethod(this, '_patch', id, data, params);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
remove (id: Id, params?: Params): Promise<T>;
|
|
206
|
-
remove (id: null, params?: Params): Promise<T[]>;
|
|
207
|
-
remove (id: NullableId, params?: Params): Promise<T | T[]>;
|
|
208
|
-
remove (id: NullableId, params?: Params): Promise<T | T[]> {
|
|
209
|
-
if (id === null && !this.allowsMulti('remove')) {
|
|
210
|
-
return Promise.reject(new MethodNotAllowed('Can not remove multiple entries'));
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
return callMethod(this, '_remove', id, params);
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
async setup () {}
|
|
217
271
|
}
|
package/src/sort.ts
CHANGED
|
@@ -7,60 +7,56 @@ export function compareNSB (a: any, b: any) {
|
|
|
7
7
|
return 0;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
export function compareArrays (a: any, b: any) {
|
|
11
|
-
let i;
|
|
12
|
-
|
|
10
|
+
export function compareArrays (a: any[], b: any[]) {
|
|
11
|
+
for (let i = 0, l = Math.min(a.length, b.length); i < l; i++) {
|
|
12
|
+
const comparison = compare(a[i], b[i]);
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
comp = exports.compare(a[i], b[i]);
|
|
16
|
-
|
|
17
|
-
if (comp !== 0) { return comp; }
|
|
14
|
+
if (comparison !== 0) { return comparison; }
|
|
18
15
|
}
|
|
19
16
|
|
|
20
17
|
// Common section was identical, longest one wins
|
|
21
|
-
return
|
|
18
|
+
return compareNSB(a.length, b.length);
|
|
22
19
|
}
|
|
23
20
|
|
|
24
|
-
export function compare (a: any, b: any, compareStrings: any =
|
|
25
|
-
|
|
21
|
+
export function compare (a: any, b: any, compareStrings: any = compareNSB): 0 | 1 | -1 {
|
|
22
|
+
if (a === b) { return 0; }
|
|
26
23
|
|
|
27
24
|
// undefined
|
|
28
|
-
if (a === undefined) { return
|
|
29
|
-
if (b === undefined) { return
|
|
25
|
+
if (a === undefined) { return -1; }
|
|
26
|
+
if (b === undefined) { return 1; }
|
|
30
27
|
|
|
31
28
|
// null
|
|
32
|
-
if (a === null) { return
|
|
33
|
-
if (b === null) { return
|
|
29
|
+
if (a === null) { return -1; }
|
|
30
|
+
if (b === null) { return 1; }
|
|
34
31
|
|
|
35
32
|
// Numbers
|
|
36
33
|
if (typeof a === 'number') { return typeof b === 'number' ? compareNSB(a, b) : -1; }
|
|
37
|
-
if (typeof b === 'number') { return
|
|
34
|
+
if (typeof b === 'number') { return 1; }
|
|
38
35
|
|
|
39
36
|
// Strings
|
|
40
37
|
if (typeof a === 'string') { return typeof b === 'string' ? compareStrings(a, b) : -1; }
|
|
41
|
-
if (typeof b === 'string') { return
|
|
38
|
+
if (typeof b === 'string') { return 1; }
|
|
42
39
|
|
|
43
40
|
// Booleans
|
|
44
41
|
if (typeof a === 'boolean') { return typeof b === 'boolean' ? compareNSB(a, b) : -1; }
|
|
45
|
-
if (typeof b === 'boolean') { return
|
|
42
|
+
if (typeof b === 'boolean') { return 1; }
|
|
46
43
|
|
|
47
44
|
// Dates
|
|
48
45
|
if (a instanceof Date) { return b instanceof Date ? compareNSB(a.getTime(), b.getTime()) : -1; }
|
|
49
|
-
if (b instanceof Date) { return
|
|
46
|
+
if (b instanceof Date) { return 1; }
|
|
50
47
|
|
|
51
48
|
// Arrays (first element is most significant and so on)
|
|
52
49
|
if (Array.isArray(a)) { return Array.isArray(b) ? compareArrays(a, b) : -1; }
|
|
53
|
-
if (Array.isArray(b)) { return
|
|
50
|
+
if (Array.isArray(b)) { return 1; }
|
|
54
51
|
|
|
55
52
|
// Objects
|
|
56
53
|
const aKeys = Object.keys(a).sort();
|
|
57
54
|
const bKeys = Object.keys(b).sort();
|
|
58
|
-
let comp = 0;
|
|
59
55
|
|
|
60
|
-
for (let i = 0
|
|
61
|
-
|
|
56
|
+
for (let i = 0, l = Math.min(aKeys.length, bKeys.length); i < l; i++) {
|
|
57
|
+
const comparison = compare(a[aKeys[i]], b[bKeys[i]]);
|
|
62
58
|
|
|
63
|
-
if (
|
|
59
|
+
if (comparison !== 0) { return comparison; }
|
|
64
60
|
}
|
|
65
61
|
|
|
66
62
|
return compareNSB(aKeys.length, bKeys.length);
|
|
@@ -68,41 +64,25 @@ export function compare (a: any, b: any, compareStrings: any = exports.compareNS
|
|
|
68
64
|
|
|
69
65
|
// An in-memory sorting function according to the
|
|
70
66
|
// $sort special query parameter
|
|
71
|
-
export function sorter ($sort:
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
const getVal = (a: any, sortKeys: any[]) => {
|
|
75
|
-
let keys = sortKeys.map(key => key);
|
|
76
|
-
let val = a;
|
|
77
|
-
do {
|
|
78
|
-
let key = keys.shift();
|
|
79
|
-
val = val[key];
|
|
80
|
-
} while (keys.length);
|
|
81
|
-
|
|
82
|
-
return val;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const criteria = Object.keys($sort).map(key => {
|
|
86
|
-
const direction = $sort[key];
|
|
87
|
-
const keys = key.split('.');
|
|
88
|
-
sortLevels = keys.length > 1;
|
|
89
|
-
|
|
90
|
-
return { keys, direction };
|
|
91
|
-
});
|
|
67
|
+
export function sorter ($sort: { [key: string]: -1 | 1 }) {
|
|
68
|
+
const get = (value: any, path: string[]) => path.reduce((value, key) => value[key], value);
|
|
92
69
|
|
|
93
|
-
|
|
94
|
-
|
|
70
|
+
const compares = Object.keys($sort).map(key => {
|
|
71
|
+
const direction = $sort[key];
|
|
72
|
+
const path = key.split('.');
|
|
95
73
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
compare = criterion.direction * exports.compare(getVal(a, criterion.keys), getVal(b, criterion.keys));
|
|
74
|
+
if (path.length === 1) {
|
|
75
|
+
return (a: any, b: any) => direction * compare(a[key], b[key]);
|
|
99
76
|
} else {
|
|
100
|
-
|
|
77
|
+
return (a: any, b: any) => direction * compare(get(a, path), get(b, path));
|
|
101
78
|
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return function (a: any, b: any) {
|
|
82
|
+
for (const compare of compares) {
|
|
83
|
+
const comparasion = compare(a, b);
|
|
102
84
|
|
|
103
|
-
if (
|
|
104
|
-
return compare;
|
|
105
|
-
}
|
|
85
|
+
if (comparasion !== 0) { return comparasion; }
|
|
106
86
|
}
|
|
107
87
|
|
|
108
88
|
return 0;
|
package/lib/filter-query.d.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export declare const FILTERS: {
|
|
2
|
-
$sort: (value: any) => any;
|
|
3
|
-
$limit: (value: any, options: any) => any;
|
|
4
|
-
$skip: (value: any) => number;
|
|
5
|
-
$select: (value: any) => any;
|
|
6
|
-
};
|
|
7
|
-
export declare const OPERATORS: string[];
|
|
8
|
-
export declare function filterQuery(query: any, options?: any): {
|
|
9
|
-
[key: string]: any;
|
|
10
|
-
};
|
package/lib/filter-query.js
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.filterQuery = exports.OPERATORS = exports.FILTERS = void 0;
|
|
4
|
-
const commons_1 = require("@feathersjs/commons");
|
|
5
|
-
const errors_1 = require("@feathersjs/errors");
|
|
6
|
-
function parse(number) {
|
|
7
|
-
if (typeof number !== 'undefined') {
|
|
8
|
-
return Math.abs(parseInt(number, 10));
|
|
9
|
-
}
|
|
10
|
-
return undefined;
|
|
11
|
-
}
|
|
12
|
-
// Returns the pagination limit and will take into account the
|
|
13
|
-
// default and max pagination settings
|
|
14
|
-
function getLimit(limit, paginate) {
|
|
15
|
-
if (paginate && (paginate.default || paginate.max)) {
|
|
16
|
-
const base = paginate.default || 0;
|
|
17
|
-
const lower = typeof limit === 'number' && !isNaN(limit) ? limit : base;
|
|
18
|
-
const upper = typeof paginate.max === 'number' ? paginate.max : Number.MAX_VALUE;
|
|
19
|
-
return Math.min(lower, upper);
|
|
20
|
-
}
|
|
21
|
-
return limit;
|
|
22
|
-
}
|
|
23
|
-
// Makes sure that $sort order is always converted to an actual number
|
|
24
|
-
function convertSort(sort) {
|
|
25
|
-
if (typeof sort !== 'object' || Array.isArray(sort)) {
|
|
26
|
-
return sort;
|
|
27
|
-
}
|
|
28
|
-
return Object.keys(sort).reduce((result, key) => {
|
|
29
|
-
result[key] = typeof sort[key] === 'object'
|
|
30
|
-
? sort[key] : parseInt(sort[key], 10);
|
|
31
|
-
return result;
|
|
32
|
-
}, {});
|
|
33
|
-
}
|
|
34
|
-
function cleanQuery(query, operators, filters) {
|
|
35
|
-
if (Array.isArray(query)) {
|
|
36
|
-
return query.map(value => cleanQuery(value, operators, filters));
|
|
37
|
-
}
|
|
38
|
-
else if (commons_1._.isObject(query) && query.constructor === {}.constructor) {
|
|
39
|
-
const result = {};
|
|
40
|
-
commons_1._.each(query, (value, key) => {
|
|
41
|
-
if (key[0] === '$') {
|
|
42
|
-
if (filters[key] !== undefined) {
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
if (!operators.includes(key)) {
|
|
46
|
-
throw new errors_1.BadRequest(`Invalid query parameter ${key}`, query);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
result[key] = cleanQuery(value, operators, filters);
|
|
50
|
-
});
|
|
51
|
-
Object.getOwnPropertySymbols(query).forEach(symbol => {
|
|
52
|
-
// @ts-ignore
|
|
53
|
-
result[symbol] = query[symbol];
|
|
54
|
-
});
|
|
55
|
-
return result;
|
|
56
|
-
}
|
|
57
|
-
return query;
|
|
58
|
-
}
|
|
59
|
-
function assignFilters(object, query, filters, options) {
|
|
60
|
-
if (Array.isArray(filters)) {
|
|
61
|
-
commons_1._.each(filters, (key) => {
|
|
62
|
-
if (query[key] !== undefined) {
|
|
63
|
-
object[key] = query[key];
|
|
64
|
-
}
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
else {
|
|
68
|
-
commons_1._.each(filters, (converter, key) => {
|
|
69
|
-
const converted = converter(query[key], options);
|
|
70
|
-
if (converted !== undefined) {
|
|
71
|
-
object[key] = converted;
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
return object;
|
|
76
|
-
}
|
|
77
|
-
exports.FILTERS = {
|
|
78
|
-
$sort: (value) => convertSort(value),
|
|
79
|
-
$limit: (value, options) => getLimit(parse(value), options.paginate),
|
|
80
|
-
$skip: (value) => parse(value),
|
|
81
|
-
$select: (value) => value
|
|
82
|
-
};
|
|
83
|
-
exports.OPERATORS = ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$or'];
|
|
84
|
-
// Converts Feathers special query parameters and pagination settings
|
|
85
|
-
// and returns them separately a `filters` and the rest of the query
|
|
86
|
-
// as `query`
|
|
87
|
-
function filterQuery(query, options = {}) {
|
|
88
|
-
const { filters: additionalFilters = {}, operators: additionalOperators = [] } = options;
|
|
89
|
-
const result = {};
|
|
90
|
-
result.filters = assignFilters({}, query, exports.FILTERS, options);
|
|
91
|
-
result.filters = assignFilters(result.filters, query, additionalFilters, options);
|
|
92
|
-
result.query = cleanQuery(query, exports.OPERATORS.concat(additionalOperators), result.filters);
|
|
93
|
-
return result;
|
|
94
|
-
}
|
|
95
|
-
exports.filterQuery = filterQuery;
|
|
96
|
-
//# sourceMappingURL=filter-query.js.map
|
package/lib/filter-query.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"filter-query.js","sourceRoot":"","sources":["../src/filter-query.ts"],"names":[],"mappings":";;;AAAA,iDAAwC;AACxC,+CAAgD;AAEhD,SAAS,KAAK,CAAE,MAAW;IACzB,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE;QACjC,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC;KACvC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,8DAA8D;AAC9D,sCAAsC;AACtC,SAAS,QAAQ,CAAE,KAAU,EAAE,QAAa;IAC1C,IAAI,QAAQ,IAAI,CAAC,QAAQ,CAAC,OAAO,IAAI,QAAQ,CAAC,GAAG,CAAC,EAAE;QAClD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,IAAI,CAAC,CAAC;QACnC,MAAM,KAAK,GAAG,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;QACxE,MAAM,KAAK,GAAG,OAAO,QAAQ,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC;QAEjF,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;KAC/B;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,sEAAsE;AACtE,SAAS,WAAW,CAAE,IAAS;IAC7B,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE;QACnD,OAAO,IAAI,CAAC;KACb;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;QAC9C,MAAM,CAAC,GAAG,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,QAAQ;YACzC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,CAAC;QAExC,OAAO,MAAM,CAAC;IAChB,CAAC,EAAE,EAA+B,CAAC,CAAC;AACtC,CAAC;AAED,SAAS,UAAU,CAAE,KAAU,EAAE,SAAc,EAAE,OAAY;IAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;QACxB,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;KAClE;SAAM,IAAI,WAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,WAAW,KAAK,EAAE,CAAC,WAAW,EAAE;QACpE,MAAM,MAAM,GAA2B,EAAE,CAAC;QAE1C,WAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAC3B,IAAI,GAAG,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE;gBAClB,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;oBAC9B,OAAO;iBACR;gBAED,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE;oBAC5B,MAAM,IAAI,mBAAU,CAAC,2BAA2B,GAAG,EAAE,EAAE,KAAK,CAAC,CAAC;iBAC/D;aACF;YAED,MAAM,CAAC,GAAG,CAAC,GAAG,UAAU,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;QACtD,CAAC,CAAC,CAAC;QAEH,MAAM,CAAC,qBAAqB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE;YACnD,aAAa;YACb,MAAM,CAAC,MAAM,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;KACf;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,aAAa,CAAE,MAAW,EAAE,KAAU,EAAE,OAAY,EAAE,OAAY;IACzE,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;QAC1B,WAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACtB,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE;gBAC5B,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;aAC1B;QACH,CAAC,CAAC,CAAC;KACJ;SAAM;QACL,WAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,EAAE;YACjC,MAAM,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;YAEjD,IAAI,SAAS,KAAK,SAAS,EAAE;gBAC3B,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC;aACzB;QACH,CAAC,CAAC,CAAC;KACJ;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAEY,QAAA,OAAO,GAAG;IACrB,KAAK,EAAE,CAAC,KAAU,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC;IACzC,MAAM,EAAE,CAAC,KAAU,EAAE,OAAY,EAAE,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC;IAC9E,KAAK,EAAE,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC;IACnC,OAAO,EAAE,CAAC,KAAU,EAAE,EAAE,CAAC,KAAK;CAC/B,CAAC;AAEW,QAAA,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AAErF,qEAAqE;AACrE,oEAAoE;AACpE,aAAa;AACb,SAAgB,WAAW,CAAE,KAAU,EAAE,UAAe,EAAE;IACxD,MAAM,EACJ,OAAO,EAAE,iBAAiB,GAAG,EAAE,EAC/B,SAAS,EAAE,mBAAmB,GAAG,EAAE,EACpC,GAAG,OAAO,CAAC;IACZ,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,MAAM,CAAC,OAAO,GAAG,aAAa,CAAC,EAAE,EAAE,KAAK,EAAE,eAAO,EAAE,OAAO,CAAC,CAAC;IAC5D,MAAM,CAAC,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,EAAE,iBAAiB,EAAE,OAAO,CAAC,CAAC;IAElF,MAAM,CAAC,KAAK,GAAG,UAAU,CAAC,KAAK,EAAE,iBAAS,CAAC,MAAM,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;IAExF,OAAO,MAAM,CAAC;AAChB,CAAC;AAbD,kCAaC"}
|