Skip to content

Commit ed2c456

Browse files
committed
Merge branch 'master' of https://github.com/feathersjs-ecosystem/feathers-vuex into find-copies
2 parents ead1121 + a64db9f commit ed2c456

29 files changed

+1469
-316
lines changed

docs/mixins.md

Lines changed: 158 additions & 28 deletions
Large diffs are not rendered by default.

docs/model-classes.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ const todo = new Todo({ description: 'Do something!' })
339339

340340
The examples above show instantiating a new Model instance without an `id` field. In this case, the record is not added to the Vuex store. If you instantiate a record **with an `id`** field, it **will** get added to the Vuex store. *Note: This field is customizable using the `idField` option for this service.*
341341

342-
Now that we have Model instances, let's take a look at the functionality they provide. Each instance will include the following methods:
342+
Now that we have Model instances, let's take a look at the functionality they provide.
343+
344+
Each instance will include the following methods:
343345

344346
- `.save()`
345347
- `.create()`
@@ -349,6 +351,15 @@ Now that we have Model instances, let's take a look at the functionality they pr
349351
- `.commit()`
350352
- `.reset()`
351353

354+
and the following readonly attributes:
355+
356+
- `isCreatePending` - `create` is currently pending on this model
357+
- `isUpdatePending` - `update` is currently pending on this model
358+
- `isPatchPending` - `patch` is currently pending on this model
359+
- `isRemovePending` - `remove` is currently pending on this model
360+
- `isSavePending` - Any of `create`, `update` or `patch` is currently pending on this model
361+
- `isPending` - Any method is currently pending on this model
362+
352363
*Remember, if a record already has an attribute with any of these method names, it will be overwritten with the method.*
353364

354365
These methods give access to many of the store `actions` and `mutations`. Using Model instances, you no longer have to use `mapActions` for `create`, `patch`, `update`, or `remove`. You also no longer have to use `mapMutations` for `createCopy`, `commitCopy`, or `resetCopy`.

docs/service-plugin.md

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,12 @@ Each service comes loaded with the following default state:
156156
errorOnCreate: undefined,
157157
errorOnUpdate: undefined,
158158
errorOnPatch: undefined,
159-
errorOnRemove: undefined
159+
errorOnRemove: undefined,
160+
161+
isIdCreatePending: [],
162+
isIdUpdatePending: [],
163+
isIdPatchPending: [],
164+
isIdRemovePending: [],
160165
}
161166
```
162167

@@ -193,6 +198,13 @@ The following state attribute will be populated with any request error, serializ
193198
- `errorOnPatch {Error}`
194199
- `errorOnRemo {Error}`
195200

201+
The following state attributes allow you to bind to the pending state of requests *per item ID*
202+
203+
- `isIdCreatePending {Array}` - Contains `id` if there's a pending `create` request for `id`.
204+
- `isIdUpdatePending {Array}` -Contains `id` if there's a pending `update` request for `id`.
205+
- `isIdPatchPending {Array}` - Contains `id` if there's a pending `patch` request for `id`.
206+
- `isIdRemovePending {Array}` - Contains `id` if there's a pending `remove` request for `id`.
207+
196208
## Service Getters
197209

198210
Service modules include the following getters:
@@ -209,6 +221,15 @@ Service modules include the following getters:
209221
- `id {Number|String}` - the id of the data to be retrieved by id from the store.
210222
- `params {Object}` - an object containing a Feathers `query` object.
211223

224+
The following getters ease access to per-instance pending status
225+
226+
- `isCreatePendingById(id) {Function}` - Check if `create` is pending for `id`
227+
- `isUpdatePendingById(id) {Function}` - Check if `update` is pending for `id`
228+
- `isPatchPendingById(id) {Function}` - Check if `patch` is pending for `id`
229+
- `isRemovePendingById(id) {Function}` - Check if `remove` is pending for `id`
230+
- `isSavePendingById(id) {Function}` - Check if `create`, `update`, or `patch` is pending for `id`
231+
- `isPendingById(id) {Function}` - Check if `create`, `update`, `patch` or `remove` is pending for `id`
232+
212233
## Service Mutations
213234

214235
The following mutations are included in each service module.
@@ -265,7 +286,9 @@ Clears all data from `ids`, `keyedById`, and `currentId`
265286
The following mutations are called automatically by the service actions, and will rarely, if ever, need to be used manually.
266287

267288
- `setPending(state, method)` - sets the `is${method}Pending` attribute to true
289+
- `setIdPending(state, { method, id })` - adds `id` to `isId${method}Pending` array
268290
- `unsetPending(state, method)` - sets the `is${method}Pending` attribute to false
291+
- `unsetIdPending(state, { method, id })` - removes `id` from `isId${method}Pending` array
269292

270293
### Mutations for Managing Errors
271294

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "feathers-vuex",
33
"description": "FeathersJS, Vue, and Nuxt for the artisan developer",
4-
"version": "3.12.3",
4+
"version": "3.13.0",
55
"homepage": "https:feathers-vuex.feathersjs-ecosystem.com",
66
"main": "dist/",
77
"module": "dist/",

src/FeathersVuexFind.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,14 @@ export default {
7373
}),
7474
computed: {
7575
items() {
76-
const { query, service, $store, temps } = this
76+
let { query, service, $store, temps } = this
7777
let { params } = this
78+
79+
query = query || {}
7880

7981
params = params || { query, temps }
8082

81-
return query ? $store.getters[`${service}/find`](params).data : []
83+
return $store.getters[`${service}/find`](params).data
8284
},
8385
pagination() {
8486
return this.$store.state[this.service].pagination[this.qid]

src/make-find-mixin.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ export default function makeFindMixin(options) {
1818
const {
1919
service,
2020
params,
21-
fetchQuery,
21+
fetchParams,
2222
queryWhen = () => true,
2323
local = false,
2424
qid = 'default',
@@ -224,9 +224,8 @@ export default function makeFindMixin(options) {
224224
getPaginationForQuery(params = {}) {
225225
const pagination = this[PAGINATION]
226226
const { qid, queryId, pageId } = getQueryInfo(params)
227-
const queryInfo = _get(pagination, `[${qid}][${queryId}]`) || {}
228-
const pageInfo =
229-
_get(pagination, `[${qid}][${queryId}][${pageId}]`) || {}
227+
const queryInfo = _get(pagination, [qid, queryId], {})
228+
const pageInfo = _get(pagination, [qid, queryId, pageId], {})
230229

231230
return { queryInfo, pageInfo }
232231
}
@@ -319,7 +318,7 @@ export default function makeFindMixin(options) {
319318

320319
setupAttribute(SERVICE_NAME, service, 'computed', true)
321320
setupAttribute(PARAMS, params)
322-
setupAttribute(FETCH_PARAMS, fetchQuery)
321+
setupAttribute(FETCH_PARAMS, fetchParams)
323322
setupAttribute(QUERY_WHEN, queryWhen, 'computed')
324323
setupAttribute(LOCAL, local)
325324

src/service-module/make-base-model.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import _get from 'lodash/get'
2121
import { EventEmitter } from 'events'
2222
import { ModelSetupContext } from './types'
2323
import { Store } from 'vuex'
24+
import { GetterName } from './service-module.getters'
2425

2526
const defaultOptions = {
2627
clone: false,
@@ -48,7 +49,7 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
4849
const { serverAlias } = options
4950

5051
// If this serverAlias already has a BaseModel, return it
51-
const ExistingBaseModel = _get(globalModels, `[${serverAlias}].BaseModel`)
52+
const ExistingBaseModel = _get(globalModels, [serverAlias, 'BaseModel'])
5253
if (ExistingBaseModel) {
5354
return ExistingBaseModel as ModelStatic
5455
}
@@ -176,6 +177,37 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
176177
return this
177178
}
178179

180+
/**
181+
* Calls `getter`, passing this model's ID as the parameter
182+
* @param getter name of getter to call
183+
*/
184+
private getGetterWithId(getter: GetterName): unknown {
185+
const { _getters, idField, tempIdField } = this
186+
.constructor as typeof BaseModel
187+
const id =
188+
getId(this, idField) != null ? getId(this, idField) : this[tempIdField]
189+
return _getters.call(this.constructor, getter, id)
190+
}
191+
192+
get isCreatePending(): boolean {
193+
return this.getGetterWithId('isCreatePendingById') as boolean
194+
}
195+
get isUpdatePending(): boolean {
196+
return this.getGetterWithId('isUpdatePendingById') as boolean
197+
}
198+
get isPatchPending(): boolean {
199+
return this.getGetterWithId('isPatchPendingById') as boolean
200+
}
201+
get isRemovePending(): boolean {
202+
return this.getGetterWithId('isRemovePendingById') as boolean
203+
}
204+
get isSavePending(): boolean {
205+
return this.getGetterWithId('isSavePendingById') as boolean
206+
}
207+
get isPending(): boolean {
208+
return this.getGetterWithId('isPendingById') as boolean
209+
}
210+
179211
public static getId(record: Record<string, any>): string {
180212
const { idField } = this.constructor as typeof BaseModel
181213
return getId(record, idField)
@@ -215,7 +247,7 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
215247
* @param method the vuex getter name without the namespace
216248
* @param payload if provided, the getter will be called as a function
217249
*/
218-
public static _getters(name: string, idOrParams?: any, params?: any) {
250+
public static _getters(name: GetterName, idOrParams?: any, params?: any) {
219251
const { namespace, store } = this
220252

221253
if (checkNamespace(namespace, this, options.debug)) {

src/service-module/make-service-plugin.ts

Lines changed: 6 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ eslint
66
import { FeathersVuexOptions, MakeServicePluginOptions } from './types'
77
import makeServiceModule from './make-service-module'
88
import { globalModels, prepareAddModel } from './global-models'
9+
import enableServiceEvents from './service-module.events'
910
import { makeNamespace, getServicePath, assignIfNotPresent } from '../utils'
1011
import _get from 'lodash/get'
1112

@@ -18,6 +19,7 @@ interface ServiceOptionsDefaults {
1819
actions: {}
1920
instanceDefaults: () => {}
2021
setupInstance: (instance: {}) => {}
22+
debounceEventsMaxWait: number
2123
}
2224

2325
const defaults: ServiceOptionsDefaults = {
@@ -28,7 +30,8 @@ const defaults: ServiceOptionsDefaults = {
2830
mutations: {}, // for custom mutations
2931
actions: {}, // for custom actions
3032
instanceDefaults: () => ({}), // Default instanceDefaults returns an empty object
31-
setupInstance: instance => instance // Default setupInstance returns the instance
33+
setupInstance: instance => instance, // Default setupInstance returns the instance
34+
debounceEventsMaxWait: 1000
3235
}
3336
const events = ['created', 'patched', 'updated', 'removed']
3437

@@ -93,7 +96,7 @@ export default function prepareMakeServicePlugin(
9396
store.registerModule(options.namespace, module, { preserveState: false })
9497

9598
// (2a^) Monkey patch the BaseModel in globalModels
96-
const BaseModel = _get(globalModels, `[${options.serverAlias}].BaseModel`)
99+
const BaseModel = _get(globalModels, [options.serverAlias, 'BaseModel'])
97100
if (BaseModel && !BaseModel.store) {
98101
Object.assign(BaseModel, {
99102
store
@@ -120,39 +123,7 @@ export default function prepareMakeServicePlugin(
120123

121124
// (3^) Setup real-time events
122125
if (options.enableEvents) {
123-
const handleEvent = (eventName, item, mutationName) => {
124-
const handler = options.handleEvents[eventName]
125-
const confirmOrArray = handler(item, {
126-
model: Model,
127-
models: globalModels
128-
})
129-
const [affectsStore, modified = item] = Array.isArray(confirmOrArray)
130-
? confirmOrArray
131-
: [confirmOrArray]
132-
if (affectsStore) {
133-
eventName === 'removed'
134-
? store.commit(`${options.namespace}/removeItem`, modified)
135-
: store.dispatch(`${options.namespace}/${mutationName}`, modified)
136-
}
137-
}
138-
139-
// Listen to socket events when available.
140-
service.on('created', item => {
141-
handleEvent('created', item, 'addOrUpdate')
142-
Model.emit && Model.emit('created', item)
143-
})
144-
service.on('updated', item => {
145-
handleEvent('updated', item, 'addOrUpdate')
146-
Model.emit && Model.emit('updated', item)
147-
})
148-
service.on('patched', item => {
149-
handleEvent('patched', item, 'addOrUpdate')
150-
Model.emit && Model.emit('patched', item)
151-
})
152-
service.on('removed', item => {
153-
handleEvent('removed', item, 'removeItem')
154-
Model.emit && Model.emit('removed', item)
155-
})
126+
enableServiceEvents({ service, Model, store, options })
156127
}
157128
}
158129
}

0 commit comments

Comments
 (0)