@feathersjs/memory 5.0.0-pre.6 → 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/CHANGELOG.md +188 -19
- package/LICENSE +1 -1
- package/README.md +42 -36
- package/lib/index.d.ts +56 -22
- package/lib/index.js +162 -100
- package/lib/index.js.map +1 -1
- package/package.json +21 -18
- package/src/index.ts +236 -86
package/src/index.ts
CHANGED
|
@@ -1,156 +1,306 @@
|
|
|
1
|
-
import { NotFound } from '@feathersjs/errors'
|
|
2
|
-
import { _ } from '@feathersjs/commons'
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
|
|
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
|
|
12
|
-
store
|
|
13
|
-
startId
|
|
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
|
-
|
|
30
|
-
|
|
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
|
-
|
|
35
|
-
|
|
36
|
-
|
|
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
|
|
40
|
-
const
|
|
53
|
+
async getEntries(_params?: ServiceParams) {
|
|
54
|
+
const params = _params || ({} as ServiceParams)
|
|
41
55
|
|
|
42
|
-
return this._find(
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
})
|
|
56
|
+
return this._find({
|
|
57
|
+
...params,
|
|
58
|
+
paginate: false
|
|
59
|
+
})
|
|
46
60
|
}
|
|
47
61
|
|
|
48
|
-
|
|
49
|
-
const {
|
|
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
|
-
|
|
54
|
-
|
|
65
|
+
return {
|
|
66
|
+
query,
|
|
67
|
+
filters: { $skip, $sort, $limit, $select }
|
|
55
68
|
}
|
|
69
|
+
}
|
|
56
70
|
|
|
57
|
-
|
|
58
|
-
|
|
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 (
|
|
62
|
-
|
|
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:
|
|
70
|
-
}
|
|
120
|
+
data: filters.$limit === 0 ? [] : values
|
|
121
|
+
}
|
|
71
122
|
|
|
72
|
-
if (!
|
|
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
|
|
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
|
|
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
|
-
|
|
93
|
-
async _create
|
|
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)
|
|
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
|
|
106
|
-
|
|
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
|
|
119
|
-
|
|
120
|
-
|
|
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(
|
|
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))
|
|
209
|
+
return patchEntry(await this._get(id, params)) // Will throw an error if not found
|
|
134
210
|
}
|
|
135
211
|
|
|
136
|
-
|
|
137
|
-
async _remove
|
|
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(
|
|
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
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
-
|
|
284
|
+
return this._patch(id, data, {
|
|
285
|
+
...params,
|
|
286
|
+
query
|
|
287
|
+
})
|
|
288
|
+
}
|
|
149
289
|
|
|
150
|
-
|
|
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
|
|
155
|
-
|
|
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
|
}
|