Skip to content

Commit ea2b093

Browse files
Merge pull request #536 from fratzinger/find-copies
support copies in find-getter and other things
2 parents 528e04e + aec8134 commit ea2b093

16 files changed

+1029
-208
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
@@ -211,7 +211,10 @@ Service modules include the following getters:
211211

212212
- `list {Array}` - an array of items. The array form of `keyedById` Read only.
213213
- `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).
214-
- `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.
214+
- `params {Object}` - an object with a `query` object and optional properties. You can set the following properties:
215+
- `params.query {Boolean}` - The `query` is in the FeathersJS query format.
216+
- `params.temps {Boolean}` - **Default:** `false` - if `true` also consider temporary records from `tempsById`
217+
- `params.copies {Boolean}` - **Default:** `false` - if `true`: first search for the regular records and then replace the records with the related copies from `copiesById`
215218
- `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+" />
216219
- `params {Object}` - an object with a `query` object and an optional `temps` boolean property.
217220
- `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/make-base-model.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
8080
public static serverAlias: string = options.serverAlias
8181

8282
public static readonly models = globalModels as GlobalModels // Can access other Models here
83-
public static copiesById: {
83+
84+
public static readonly copiesById: {
8485
[key: string]: Model | undefined
8586
[key: number]: Model | undefined
8687
} = {}
@@ -397,7 +398,9 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
397398
* Calls service patch with the current instance data
398399
* @param params
399400
*/
400-
public patch<D extends {} = AnyData>(params?: PatchParams<D>): Promise<this> {
401+
public patch<D extends {} = AnyData>(
402+
params?: PatchParams<D>
403+
): Promise<this> {
401404
const { idField, _dispatch } = this.constructor as typeof BaseModel
402405
const id = getId(this, idField)
403406

@@ -442,7 +445,9 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
442445
}
443446
return _dispatch.call(this.constructor, 'remove', [id, params])
444447
} else {
448+
// is temp
445449
_commit.call(this.constructor, 'removeTemps', [this[tempIdField]])
450+
_commit.call(this.constructor, 'clearCopy', [this[tempIdField]])
446451
return Promise.resolve(this)
447452
}
448453
}

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

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ import { Id } from '@feathersjs/feathers'
1616
const FILTERS = ['$sort', '$limit', '$skip', '$select']
1717
const additionalOperators = ['$elemMatch']
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

@@ -39,11 +57,23 @@ export default function makeServiceGetters() {
3957
let values = _.values(keyedById)
4058

4159
if (params.temps) {
42-
values = values.concat(_.values(state.tempsById))
60+
values.push(..._.values(state.tempsById))
4361
}
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,15 +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(models, [serverAlias, 'byServicePath', servicePath])
111-
112-
return Model.copiesById[id]
113-
}
135+
const copiesById = getCopiesById(state)
136+
return copiesById[id]
114137
},
115138

116139
isCreatePendingById: ({ isIdCreatePending }: ServiceState) => (id: Id) =>
@@ -126,8 +149,7 @@ export default function makeServiceGetters() {
126149
getters.isUpdatePendingById(id) ||
127150
getters.isPatchPendingById(id),
128151
isPendingById: (state: ServiceState, getters) => (id: Id) =>
129-
getters.isSavePendingById(id) ||
130-
getters.isRemovePendingById(id)
152+
getters.isSavePendingById(id) || getters.isRemovePendingById(id)
131153
}
132154
}
133155

src/service-module/service-module.mutations.ts

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,17 @@ export default function makeServiceMutations() {
188188
const isIdOk = idToBeRemoved !== null && idToBeRemoved !== undefined
189189
const index = state.ids.findIndex(i => i === idToBeRemoved)
190190

191+
const Model = _get(models, `[${state.serverAlias}][${state.modelName}]`)
192+
const copiesById = state.keepCopiesInStore
193+
? state.copiesById
194+
: Model.copiesById
195+
191196
if (isIdOk && index !== null && index !== undefined) {
192197
Vue.delete(state.ids, index)
193198
Vue.delete(state.keyedById, idToBeRemoved)
199+
if (copiesById.hasOwnProperty(idToBeRemoved)) {
200+
Vue.delete(copiesById, idToBeRemoved)
201+
}
194202
}
195203
},
196204

@@ -226,8 +234,21 @@ export default function makeServiceMutations() {
226234
map[id] = true
227235
return map
228236
}, {})
237+
238+
const Model = _get(models, [
239+
state.serverAlias,
240+
'byServicePath',
241+
state.servicePath
242+
])
243+
const copiesById = state.keepCopiesInStore
244+
? state.copiesById
245+
: Model.copiesById
246+
229247
idsToRemove.forEach(id => {
230248
Vue.delete(state.keyedById, id)
249+
if (copiesById.hasOwnProperty(id)) {
250+
Vue.delete(copiesById, id)
251+
}
231252
})
232253

233254
// Get indexes to remove from the ids array.
@@ -257,6 +278,19 @@ export default function makeServiceMutations() {
257278
clearAll(state) {
258279
state.ids = []
259280
state.keyedById = {}
281+
282+
if (state.keepCopiesInStore) {
283+
state.copiesById = {}
284+
} else {
285+
const Model = _get(models, [
286+
state.serverAlias,
287+
'byServicePath',
288+
state.servicePath
289+
])
290+
Object.keys(Model.copiesById).forEach(k =>
291+
Vue.delete(Model.copiesById, k)
292+
)
293+
}
260294
},
261295

262296
// Creates a copy of the record with the passed-in id, stores it in copiesById
@@ -265,13 +299,18 @@ export default function makeServiceMutations() {
265299
const current = state.keyedById[id] || state.tempsById[id]
266300
const Model = _get(models, [serverAlias, 'byServicePath', servicePath])
267301

302+
let item
303+
268304
if (Model) {
269-
var model = new Model(current, { clone: true })
305+
item = new Model(current, { clone: true })
270306
} else {
271-
var copyData = mergeWithAccessors({}, current)
307+
const existingClone = state.copiesById[id]
308+
309+
item = existingClone
310+
? mergeWithAccessors(existingClone, current)
311+
: mergeWithAccessors({}, current)
272312
}
273313

274-
let item = model || copyData
275314
if (keepCopiesInStore) {
276315
state.copiesById[id] = item
277316
} else {
@@ -330,9 +369,18 @@ export default function makeServiceMutations() {
330369

331370
// Removes the copy from copiesById
332371
clearCopy(state, id) {
333-
const newCopiesById = Object.assign({}, state.copiesById)
334-
delete newCopiesById[id]
335-
state.copiesById = newCopiesById
372+
const { keepCopiesInStore } = state
373+
const Model = _get(models, [
374+
state.serverAlias,
375+
'byServicePath',
376+
state.servicePath
377+
])
378+
379+
const copiesById = keepCopiesInStore ? state.copiesById : Model.copiesById
380+
381+
if (copiesById[id]) {
382+
Vue.delete(copiesById, id)
383+
}
336384
},
337385

338386
/**

src/service-module/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ export interface MakeServicePluginOptions {
5757
replaceItems?: boolean
5858
skipRequestIfExists?: boolean
5959
nameStyle?: string
60+
keepCopiesInStore?: boolean
6061
debounceEventsTime?: number
6162
debounceEventsMaxWait?: number
6263

src/utils.ts

Lines changed: 2 additions & 0 deletions
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
}

test/make-find-mixin.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function makeContext() {
3030
Vue.use(Vuex)
3131
Vue.use(FeathersVuex)
3232

33-
describe('Find Mixin', function() {
33+
describe('Find Mixin', function () {
3434
const { makeServicePlugin, FindModel } = makeContext()
3535
const serviceName = 'todos'
3636
const store = new Vuex.Store({
@@ -42,7 +42,7 @@ describe('Find Mixin', function() {
4242
]
4343
})
4444

45-
it('correctly forms mixin data', function() {
45+
it('correctly forms mixin data', function () {
4646
const todosMixin = makeFindMixin({ service: 'todos' })
4747
interface TodosComponent {
4848
todos: []
@@ -99,7 +99,7 @@ describe('Find Mixin', function() {
9999
)
100100
})
101101

102-
it('correctly forms mixin data for dynamic service', function() {
102+
it('correctly forms mixin data for dynamic service', function () {
103103
const tasksMixin = makeFindMixin({
104104
service() {
105105
return this.serviceName

0 commit comments

Comments
 (0)