@feathersjs/memory 5.0.0-pre.9 → 5.0.0

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/src/index.ts CHANGED
@@ -1,156 +1,306 @@
1
- import { NotFound } from '@feathersjs/errors';
2
- import { _ } from '@feathersjs/commons';
3
- import { sorter, select, AdapterService, ServiceOptions, InternalServiceMethods, AdapterParams } from '@feathersjs/adapter-commons';
4
- import sift from 'sift';
5
- import { NullableId, Id } from '@feathersjs/feathers';
1
+ import { BadRequest, MethodNotAllowed, NotFound } from '@feathersjs/errors'
2
+ import { _ } from '@feathersjs/commons'
3
+ import {
4
+ sorter,
5
+ select,
6
+ AdapterBase,
7
+ AdapterServiceOptions,
8
+ PaginationOptions,
9
+ AdapterParams
10
+ } from '@feathersjs/adapter-commons'
11
+ import sift from 'sift'
12
+ import { NullableId, Id, Params, Paginated } from '@feathersjs/feathers'
6
13
 
7
14
  export interface MemoryServiceStore<T> {
8
- [key: string]: T;
15
+ [key: string]: T
9
16
  }
10
17
 
11
- export interface MemoryServiceOptions<T = any> extends ServiceOptions {
12
- store: MemoryServiceStore<T>;
13
- startId: number;
14
- matcher?: (query: any) => any;
15
- sorter?: (sort: any) => any;
18
+ export interface MemoryServiceOptions<T = any> extends AdapterServiceOptions {
19
+ store?: MemoryServiceStore<T>
20
+ startId?: number
21
+ matcher?: (query: any) => any
22
+ sorter?: (sort: any) => any
16
23
  }
17
24
 
18
25
  const _select = (data: any, params: any, ...args: any[]) => {
19
- const base = select(params, ...args);
26
+ const base = select(params, ...args)
20
27
 
21
- return base(JSON.parse(JSON.stringify(data)));
22
- };
23
-
24
- export class Service<T = any, D = Partial<any>> extends AdapterService<T, D> implements InternalServiceMethods<T> {
25
- options: MemoryServiceOptions;
26
- store: MemoryServiceStore<T>;
27
- _uId: number;
28
+ return base(JSON.parse(JSON.stringify(data)))
29
+ }
28
30
 
29
- constructor (options: Partial<MemoryServiceOptions<T>> = {}) {
30
- super(_.extend({
31
+ export class MemoryAdapter<
32
+ Result = any,
33
+ Data = Partial<Result>,
34
+ ServiceParams extends Params = Params,
35
+ PatchData = Partial<Data>
36
+ > extends AdapterBase<Result, Data, PatchData, ServiceParams, MemoryServiceOptions<Result>> {
37
+ store: MemoryServiceStore<Result>
38
+ _uId: number
39
+
40
+ constructor(options: MemoryServiceOptions<Result> = {}) {
41
+ super({
31
42
  id: 'id',
32
43
  matcher: sift,
33
- sorter
34
- }, options));
35
- this._uId = options.startId || 0;
36
- this.store = options.store || {};
44
+ sorter,
45
+ store: {},
46
+ startId: 0,
47
+ ...options
48
+ })
49
+ this._uId = this.options.startId
50
+ this.store = { ...this.options.store }
37
51
  }
38
52
 
39
- async getEntries (params = {}) {
40
- const { query } = this.filterQuery(params);
53
+ async getEntries(_params?: ServiceParams) {
54
+ const params = _params || ({} as ServiceParams)
41
55
 
42
- return this._find(Object.assign({}, params, {
43
- paginate: false,
44
- query
45
- }) as any) as Promise<T[]>;
56
+ return this._find({
57
+ ...params,
58
+ paginate: false
59
+ })
46
60
  }
47
61
 
48
- async _find (params: AdapterParams = {}) {
49
- const { query, filters, paginate } = this.filterQuery(params);
50
- let values = _.values(this.store).filter(this.options.matcher(query));
51
- const total = values.length;
62
+ getQuery(params: ServiceParams) {
63
+ const { $skip, $sort, $limit, $select, ...query } = params.query || {}
52
64
 
53
- if (filters.$sort !== undefined) {
54
- values.sort(this.options.sorter(filters.$sort));
65
+ return {
66
+ query,
67
+ filters: { $skip, $sort, $limit, $select }
55
68
  }
69
+ }
56
70
 
57
- if (filters.$skip !== undefined) {
58
- values = values.slice(filters.$skip);
71
+ async _find(_params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>
72
+ async _find(_params?: ServiceParams & { paginate: false }): Promise<Result[]>
73
+ async _find(_params?: ServiceParams): Promise<Paginated<Result> | Result[]>
74
+ async _find(params: ServiceParams = {} as ServiceParams): Promise<Paginated<Result> | Result[]> {
75
+ const { paginate } = this.getOptions(params)
76
+ const { query, filters } = this.getQuery(params)
77
+
78
+ let values = _.values(this.store)
79
+ const total = values.length
80
+ const hasSkip = filters.$skip !== undefined
81
+ const hasSort = filters.$sort !== undefined
82
+ const hasLimit = filters.$limit !== undefined
83
+ const hasQuery = _.keys(query).length > 0
84
+
85
+ if (hasSort) {
86
+ values.sort(this.options.sorter(filters.$sort))
59
87
  }
60
88
 
61
- if (filters.$limit !== undefined) {
62
- values = values.slice(0, filters.$limit);
89
+ if (hasQuery || hasLimit || hasSkip) {
90
+ let skipped = 0
91
+ const matcher = this.options.matcher(query)
92
+ const matched = []
93
+
94
+ for (let index = 0, length = values.length; index < length; index++) {
95
+ const value = values[index]
96
+
97
+ if (hasQuery && !matcher(value, index, values)) {
98
+ continue
99
+ }
100
+
101
+ if (hasSkip && filters.$skip > skipped) {
102
+ skipped++
103
+ continue
104
+ }
105
+
106
+ matched.push(_select(value, params))
107
+
108
+ if (hasLimit && filters.$limit === matched.length) {
109
+ break
110
+ }
111
+ }
112
+
113
+ values = matched
63
114
  }
64
115
 
65
- const result = {
66
- total,
116
+ const result: Paginated<Result> = {
117
+ total: hasQuery ? values.length : total,
67
118
  limit: filters.$limit,
68
119
  skip: filters.$skip || 0,
69
- data: values.map(value => _select(value, params))
70
- };
120
+ data: filters.$limit === 0 ? [] : values
121
+ }
71
122
 
72
- if (!(paginate && (paginate ).default)) {
73
- return result.data;
123
+ if (!paginate) {
124
+ return result.data
74
125
  }
75
126
 
76
- return result;
127
+ return result
77
128
  }
78
129
 
79
- async _get (id: Id, params: AdapterParams = {}) {
130
+ async _get(id: Id, params: ServiceParams = {} as ServiceParams): Promise<Result> {
131
+ const { query } = this.getQuery(params)
132
+
80
133
  if (id in this.store) {
81
- const { query } = this.filterQuery(params);
82
- const value = this.store[id];
134
+ const value = this.store[id]
83
135
 
84
136
  if (this.options.matcher(query)(value)) {
85
- return _select(value, params, this.id);
137
+ return _select(value, params, this.id)
86
138
  }
87
139
  }
88
140
 
89
- throw new NotFound(`No record found for id '${id}'`);
141
+ throw new NotFound(`No record found for id '${id}'`)
90
142
  }
91
143
 
92
- // Create without hooks and mixins that can be used internally
93
- async _create (data: Partial<T> | Partial<T>[], params: AdapterParams = {}): Promise<T | T[]> {
144
+ async _create(data: Partial<Data>, params?: ServiceParams): Promise<Result>
145
+ async _create(data: Partial<Data>[], params?: ServiceParams): Promise<Result[]>
146
+ async _create(data: Partial<Data> | Partial<Data>[], _params?: ServiceParams): Promise<Result | Result[]>
147
+ async _create(
148
+ data: Partial<Data> | Partial<Data>[],
149
+ params: ServiceParams = {} as ServiceParams
150
+ ): Promise<Result | Result[]> {
94
151
  if (Array.isArray(data)) {
95
- return Promise.all(data.map(current => this._create(current, params) as Promise<T>));
152
+ return Promise.all(data.map((current) => this._create(current, params)))
96
153
  }
97
154
 
98
- const id = (data as any)[this.id] || this._uId++;
99
- const current = _.extend({}, data, { [this.id]: id });
100
- const result = (this.store[id] = current);
155
+ const id = (data as any)[this.id] || this._uId++
156
+ const current = _.extend({}, data, { [this.id]: id })
157
+ const result = (this.store[id] = current)
101
158
 
102
- return _select(result, params, this.id);
159
+ return _select(result, params, this.id) as Result
103
160
  }
104
161
 
105
- async _update (id: NullableId, data: T, params: AdapterParams = {}) {
106
- const oldEntry = await this._get(id);
162
+ async _update(id: Id, data: Data, params: ServiceParams = {} as ServiceParams): Promise<Result> {
163
+ if (id === null || Array.isArray(data)) {
164
+ throw new BadRequest("You can not replace multiple instances. Did you mean 'patch'?")
165
+ }
166
+
167
+ const oldEntry = await this._get(id)
107
168
  // We don't want our id to change type if it can be coerced
108
- const oldId = oldEntry[this.id];
169
+ const oldId = (oldEntry as any)[this.id]
109
170
 
110
171
  // eslint-disable-next-line eqeqeq
111
- id = oldId == id ? oldId : id;
172
+ id = oldId == id ? oldId : id
112
173
 
113
- this.store[id] = _.extend({}, data, { [this.id]: id });
174
+ this.store[id] = _.extend({}, data, { [this.id]: id })
114
175
 
115
- return this._get(id, params);
176
+ return this._get(id, params)
116
177
  }
117
178
 
118
- async _patch (id: NullableId, data: Partial<T>, params: AdapterParams = {}) {
119
- const patchEntry = (entry: T) => {
120
- const currentId = (entry as any)[this.id];
179
+ async _patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>
180
+ async _patch(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>
181
+ async _patch(id: NullableId, data: PatchData, _params?: ServiceParams): Promise<Result | Result[]>
182
+ async _patch(
183
+ id: NullableId,
184
+ data: PatchData,
185
+ params: ServiceParams = {} as ServiceParams
186
+ ): Promise<Result | Result[]> {
187
+ if (id === null && !this.allowsMulti('patch', params)) {
188
+ throw new MethodNotAllowed('Can not patch multiple entries')
189
+ }
190
+
191
+ const { query } = this.getQuery(params)
192
+ const patchEntry = (entry: Result) => {
193
+ const currentId = (entry as any)[this.id]
121
194
 
122
- this.store[currentId] = _.extend(this.store[currentId], _.omit(data, this.id));
195
+ this.store[currentId] = _.extend(this.store[currentId], _.omit(data, this.id))
123
196
 
124
- return _select(this.store[currentId], params, this.id);
125
- };
197
+ return _select(this.store[currentId], params, this.id)
198
+ }
126
199
 
127
200
  if (id === null) {
128
- const entries = await this.getEntries(params);
201
+ const entries = await this.getEntries({
202
+ ...params,
203
+ query
204
+ })
129
205
 
130
- return entries.map(patchEntry);
206
+ return entries.map(patchEntry)
131
207
  }
132
208
 
133
- return patchEntry(await this._get(id, params)); // Will throw an error if not found
209
+ return patchEntry(await this._get(id, params)) // Will throw an error if not found
134
210
  }
135
211
 
136
- // Remove without hooks and mixins that can be used internally
137
- async _remove (id: NullableId, params: AdapterParams = {}): Promise<T|T[]> {
212
+ async _remove(id: null, params?: ServiceParams): Promise<Result[]>
213
+ async _remove(id: Id, params?: ServiceParams): Promise<Result>
214
+ async _remove(id: NullableId, _params?: ServiceParams): Promise<Result | Result[]>
215
+ async _remove(id: NullableId, params: ServiceParams = {} as ServiceParams): Promise<Result | Result[]> {
216
+ if (id === null && !this.allowsMulti('remove', params)) {
217
+ throw new MethodNotAllowed('Can not remove multiple entries')
218
+ }
219
+
220
+ const { query } = this.getQuery(params)
221
+
138
222
  if (id === null) {
139
- const entries = await this.getEntries(params);
223
+ const entries = await this.getEntries({
224
+ ...params,
225
+ query
226
+ })
227
+
228
+ return Promise.all(entries.map((current: any) => this._remove(current[this.id] as Id, params)))
229
+ }
230
+
231
+ const entry = await this._get(id, params)
232
+
233
+ delete this.store[id]
234
+
235
+ return entry
236
+ }
237
+ }
238
+
239
+ export class MemoryService<
240
+ Result = any,
241
+ Data = Partial<Result>,
242
+ ServiceParams extends AdapterParams = AdapterParams,
243
+ PatchData = Partial<Data>
244
+ > extends MemoryAdapter<Result, Data, ServiceParams, PatchData> {
245
+ async find(params?: ServiceParams & { paginate?: PaginationOptions }): Promise<Paginated<Result>>
246
+ async find(params?: ServiceParams & { paginate: false }): Promise<Result[]>
247
+ async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]>
248
+ async find(params?: ServiceParams): Promise<Paginated<Result> | Result[]> {
249
+ return this._find({
250
+ ...params,
251
+ query: await this.sanitizeQuery(params)
252
+ })
253
+ }
140
254
 
141
- return Promise.all(entries.map(current =>
142
- this._remove((current as any)[this.id], params) as Promise<T>
143
- ));
255
+ async get(id: Id, params?: ServiceParams): Promise<Result> {
256
+ return this._get(id, {
257
+ ...params,
258
+ query: await this.sanitizeQuery(params)
259
+ })
260
+ }
261
+
262
+ async create(data: Data, params?: ServiceParams): Promise<Result>
263
+ async create(data: Data[], params?: ServiceParams): Promise<Result[]>
264
+ async create(data: Data | Data[], params?: ServiceParams): Promise<Result | Result[]> {
265
+ if (Array.isArray(data) && !this.allowsMulti('create', params)) {
266
+ throw new MethodNotAllowed('Can not create multiple entries')
144
267
  }
145
268
 
146
- const entry = await this._get(id, params);
269
+ return this._create(data, params)
270
+ }
271
+
272
+ async update(id: Id, data: Data, params?: ServiceParams): Promise<Result> {
273
+ return this._update(id, data, {
274
+ ...params,
275
+ query: await this.sanitizeQuery(params)
276
+ })
277
+ }
278
+
279
+ async patch(id: Id, data: PatchData, params?: ServiceParams): Promise<Result>
280
+ async patch(id: null, data: PatchData, params?: ServiceParams): Promise<Result[]>
281
+ async patch(id: NullableId, data: PatchData, params?: ServiceParams): Promise<Result | Result[]> {
282
+ const { $limit, ...query } = await this.sanitizeQuery(params)
147
283
 
148
- delete this.store[id];
284
+ return this._patch(id, data, {
285
+ ...params,
286
+ query
287
+ })
288
+ }
149
289
 
150
- return entry;
290
+ async remove(id: Id, params?: ServiceParams): Promise<Result>
291
+ async remove(id: null, params?: ServiceParams): Promise<Result[]>
292
+ async remove(id: NullableId, params?: ServiceParams): Promise<Result | Result[]> {
293
+ const { $limit, ...query } = await this.sanitizeQuery(params)
294
+
295
+ return this._remove(id, {
296
+ ...params,
297
+ query
298
+ })
151
299
  }
152
300
  }
153
301
 
154
- export function memory (options: Partial<MemoryServiceOptions> = {}) {
155
- return new Service(options);
302
+ export function memory<T = any, D = Partial<T>, P extends Params = Params>(
303
+ options: Partial<MemoryServiceOptions<T>> = {}
304
+ ) {
305
+ return new MemoryService<T, D, P>(options)
156
306
  }