Skip to content

Commit 959b778

Browse files
committed
add copies options to get-getter
1 parent 7b4de7d commit 959b778

File tree

5 files changed

+203
-27
lines changed

5 files changed

+203
-27
lines changed

docs/composition-api.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ And here's a look at each individual property:
119119
- Set `params.paginate` to `true` to turn off realtime updates for the results and defer pagination to the API server. Pagination works the same as for the [makeFindMixin pagination](./mixins.html#pagination-with-fall-through-cacheing).
120120
- Set `params.debounce` to an integer and the API requests will automatically be debounced by that many milliseconds. For example, setting `debounce: 1000` will assure that the API request will be made at most every 1 second.
121121
- Set `params.temps` to `true` to include temporary (local-only) items in the results. Temporary records are instances that have been created but not yet saved to the database.
122+
- Set `params.copies` to `true` to include cloned items in the results. The queried items get replaced with the corresponding copies from `copiesById`
122123
- `fetchParams` This is a separate set of params that, when provided, will become the params sent to the API server. The `params` will then only be used to query data from the local data store.
123124
- Explicitly returning `null` will prevent an API request from being made.
124125
- `queryWhen` must be a `computed` property which returns a `boolean`. It provides a logical separation for preventing API requests *outside* of the `params`.

docs/service-plugin.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,10 @@ Service modules include the following getters:
199199

200200
- `list {Array}` - an array of items. The array form of `keyedById` Read only.
201201
- `find(params) {Function}` - a helper function that allows you to use the [Feathers Adapter Common API](https://docs.feathersjs.com/api/databases/common) and [Query API](https://docs.feathersjs.com/api/databases/querying) to pull data from the store. This allows you to treat the store just like a local Feathers database adapter (but without hooks).
202-
- `params {Object}` - an object with a `query` object and optional `paginate` and `temps` boolean properties. The `query` is in the FeathersJS query format. You can set `params.paginate` to `false` to disable pagination for a single request.
202+
- `params {Object}` - an object with a `query` object and optional properties. You can set the following properties:
203+
- `params.query {Boolean}` - The `query` is in the FeathersJS query format.
204+
- `params.temps {Boolean}` - **Default:** `false` - if `true` also consider temporary records from `tempsById`
205+
- `params.copies {Boolean}` - **Default:** `false` - if `true`: first search for the regular records and then replace the records with the related copies from `copiesById`
203206
- `count(params) {Function}` - a helper function that counts items in the store matching the provided query in the params and returns this number <Badge text="3.12.0+" />
204207
- `params {Object}` - an object with a `query` object and an optional `temps` boolean property.
205208
- `get(id[, params]) {Function}` - a function that allows you to query the store for a single item, by id. It works the same way as `get` requests in Feathers database adapters.

src/service-module/service-module.getters.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ const OPERATORS = ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$or']
1616
const additionalOperators = ['$elemMatch']
1717
const defaultOps = FILTERS.concat(OPERATORS).concat(additionalOperators)
1818

19+
const getCopiesById = ({
20+
keepCopiesInStore,
21+
servicePath,
22+
serverAlias,
23+
copiesById
24+
}) => {
25+
if (keepCopiesInStore) {
26+
return copiesById
27+
} else {
28+
const Model = _get(models, `[${serverAlias}].byServicePath[${servicePath}]`)
29+
30+
return Model.copiesById
31+
}
32+
}
33+
1934
export default function makeServiceGetters() {
2035
return {
2136
list(state) {
@@ -30,6 +45,9 @@ export default function makeServiceGetters() {
3045
// Set params.temps to true to include the tempsById records
3146
params.temps = params.hasOwnProperty('temps') ? params.temps : false
3247

48+
// Set params.copies to true to include the copiesById records
49+
params.copies = params.hasOwnProperty('copies') ? params.copies : false
50+
3351
const { paramsForServer, whitelist, keyedById } = state
3452
const q = _omit(params.query || {}, paramsForServer)
3553

@@ -44,6 +62,18 @@ export default function makeServiceGetters() {
4462

4563
values = values.filter(sift(query))
4664

65+
if (params.copies) {
66+
const { idField } = state
67+
const copiesById = getCopiesById(state)
68+
values.forEach((val, i, arr) => {
69+
const copy = copiesById[val[idField]]
70+
if (copy) {
71+
// replace keyedById value with existing clone value
72+
arr[i] = copy
73+
}
74+
})
75+
}
76+
4777
const total = values.length
4878

4979
if (filters.$sort) {
@@ -102,18 +132,8 @@ export default function makeServiceGetters() {
102132
return tempRecord || null
103133
},
104134
getCopyById: state => id => {
105-
const { servicePath, keepCopiesInStore, serverAlias } = state
106-
107-
if (keepCopiesInStore) {
108-
return state.copiesById[id]
109-
} else {
110-
const Model = _get(
111-
models,
112-
`[${serverAlias}].byServicePath[${servicePath}]`
113-
)
114-
115-
return Model.copiesById[id]
116-
}
135+
const copiesById = getCopiesById(state)
136+
return copiesById[id]
117137
}
118138
}
119139
}

src/utils.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ interface Params {
2828
provider?: string
2929
route?: { [key: string]: string }
3030
headers?: { [key: string]: any }
31+
temps?: boolean
32+
copies?: boolean
3133

3234
[key: string]: any // (JL) not sure if we want this
3335
}
@@ -231,7 +233,6 @@ export function getId(item, idField) {
231233
if (item._id != null || item.hasOwnProperty('_id')) {
232234
return item._id
233235
}
234-
235236
}
236237

237238
// Creates a Model class name from the last part of the servicePath

test/service-module/module.getters.test.ts

Lines changed: 164 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import {
1212
clearModels
1313
} from '../../src/service-module/global-models'
1414

15+
import { values as _values } from 'lodash'
16+
1517
const options = {
1618
idField: '_id',
1719
tempIdField: '__id',
@@ -81,24 +83,20 @@ describe('Service Module - Getters', function () {
8183
1: { test: true }
8284
}
8385
}
84-
// @ts-ignore
86+
8587
const result = getCopyById(state)(1)
8688

87-
// @ts-ignore
8889
assert(result.test, 'got the copy')
8990
})
9091

9192
it('getCopyById with keepCopiesInStore: false', function () {
9293
const state = {
9394
keepCopiesInStore: false,
9495
servicePath: 'todos',
95-
serverAlias: 'my-getters-test',
96-
copiesById: {
97-
1: { test: true }
98-
}
96+
serverAlias: 'my-getters-test'
9997
}
10098
Object.assign(globalModels, {
101-
'my-getters-test': {
99+
[state.serverAlias]: {
102100
byServicePath: {
103101
todos: {
104102
copiesById: {
@@ -108,31 +106,28 @@ describe('Service Module - Getters', function () {
108106
}
109107
}
110108
})
111-
// @ts-ignore
109+
112110
const result = getCopyById(state)(1)
113111

114-
// @ts-ignore
115112
assert(result.test, 'got the copy')
116113

117114
clearModels()
118115
})
119116

120117
it('get works on keyedById', function () {
121118
const { state, items } = this
122-
// @ts-ignore
119+
123120
const result = get(state)(1)
124121

125-
// @ts-ignore
126122
assert.deepEqual(result, items[0])
127123
})
128124

129125
it('get works on tempsById', function () {
130126
const { state } = this
131127
const tempId = Object.keys(state.tempsById)[0]
132-
// @ts-ignore
128+
133129
const result = get(state)(tempId)
134130

135-
// @ts-ignore
136131
assert(result.__id === tempId)
137132
})
138133

@@ -163,6 +158,162 @@ describe('Service Module - Getters', function () {
163158
assert(results.total === 4, 'total was correct')
164159
})
165160

161+
it('find - no copies by default', function () {
162+
const state = {
163+
keepCopiesInStore: false,
164+
servicePath: 'todos',
165+
serverAlias: 'my-getters-test',
166+
keyedById: {
167+
1: { _id: 1, test: true, __isClone: false },
168+
2: { _id: 2, test: true, __isClone: false },
169+
3: { _id: 3, test: true, __isClone: false }
170+
},
171+
copiesById: {
172+
1: { _id: 1, test: true, __isClone: true }
173+
}
174+
}
175+
Object.assign(globalModels, {
176+
[state.serverAlias]: {
177+
byServicePath: {
178+
todos: {
179+
copiesById: {
180+
1: { _id: 1, test: true, __isClone: true }
181+
}
182+
}
183+
}
184+
}
185+
})
186+
187+
const params = { query: {} }
188+
const results = find(state)(params)
189+
190+
assert.deepEqual(
191+
results.data,
192+
_values(state.keyedById).filter(i => !i.__isClone),
193+
'the list was correct'
194+
)
195+
assert(results.limit === 0, 'limit was correct')
196+
assert(results.skip === 0, 'skip was correct')
197+
assert(results.total === 3, 'total was correct')
198+
199+
clearModels()
200+
})
201+
202+
it('find - with copies with keepCopiesInStore:true', function () {
203+
const state = {
204+
keepCopiesInStore: true,
205+
idField: '_id',
206+
keyedById: {
207+
1: { _id: 1, test: true, __isClone: false },
208+
2: { _id: 2, test: true, __isClone: false },
209+
3: { _id: 3, test: true, __isClone: false }
210+
},
211+
copiesById: {
212+
1: { _id: 1, test: true, __isClone: true }
213+
}
214+
}
215+
216+
const params = { query: {}, copies: true }
217+
const results = find(state)(params)
218+
219+
const expected = [
220+
{ _id: 1, test: true, __isClone: true },
221+
{ _id: 2, test: true, __isClone: false },
222+
{ _id: 3, test: true, __isClone: false }
223+
]
224+
225+
assert.deepEqual(results.data, expected, 'the list was correct')
226+
assert(results.limit === 0, 'limit was correct')
227+
assert(results.skip === 0, 'skip was correct')
228+
assert(results.total === 3, 'total was correct')
229+
})
230+
231+
it('find - with copies with keepCopiesInStore:false', function () {
232+
const state = {
233+
keepCopiesInStore: false,
234+
servicePath: 'todos',
235+
serverAlias: 'my-getters-test',
236+
idField: '_id',
237+
keyedById: {
238+
1: { _id: 1, test: true, __isClone: false },
239+
2: { _id: 2, test: true, __isClone: false },
240+
3: { _id: 3, test: true, __isClone: false }
241+
}
242+
}
243+
Object.assign(globalModels, {
244+
[state.serverAlias]: {
245+
byServicePath: {
246+
todos: {
247+
copiesById: {
248+
1: { _id: 1, test: true, __isClone: true }
249+
}
250+
}
251+
}
252+
}
253+
})
254+
255+
const params = { query: {}, copies: true }
256+
const results = find(state)(params)
257+
258+
const expected = [
259+
{ _id: 1, test: true, __isClone: true },
260+
{ _id: 2, test: true, __isClone: false },
261+
{ _id: 3, test: true, __isClone: false }
262+
]
263+
264+
assert.deepEqual(results.data, expected, 'the list was correct')
265+
assert(results.limit === 0, 'limit was correct')
266+
assert(results.skip === 0, 'skip was correct')
267+
assert(results.total === 3, 'total was correct')
268+
269+
clearModels()
270+
})
271+
272+
it('find - with copies and temps', function () {
273+
const state = {
274+
keepCopiesInStore: false,
275+
servicePath: 'todos',
276+
serverAlias: 'my-getters-test',
277+
idField: '_id',
278+
keyedById: {
279+
1: { _id: 1, test: true, __isClone: false },
280+
2: { _id: 2, test: true, __isClone: false },
281+
3: { _id: 3, test: true, __isClone: false }
282+
},
283+
tempsById: {
284+
abc: { __id: 'abc', test: true, __isClone: false, __isTemp: true }
285+
}
286+
}
287+
Object.assign(globalModels, {
288+
[state.serverAlias]: {
289+
byServicePath: {
290+
todos: {
291+
copiesById: {
292+
1: { _id: 1, test: true, __isClone: true }
293+
}
294+
}
295+
}
296+
}
297+
})
298+
299+
const params = { query: {}, copies: true, temps: true }
300+
const results = find(state)(params)
301+
302+
const expected = [
303+
{ _id: 1, test: true, __isClone: true },
304+
{ _id: 2, test: true, __isClone: false },
305+
{ _id: 3, test: true, __isClone: false },
306+
{ __id: 'abc', test: true, __isClone: false, __isTemp: true }
307+
]
308+
309+
assert.deepEqual(results.data, expected, 'the list was correct')
310+
assert(results.limit === 0, 'limit was correct')
311+
assert(results.skip === 0, 'skip was correct')
312+
assert(results.total === 4, 'total was correct')
313+
314+
clearModels()
315+
})
316+
166317
it('find with query', function () {
167318
const { state } = this
168319
const params = { query: { test: false } }

0 commit comments

Comments
 (0)