Skip to content

Commit 1bfb805

Browse files
committed
2 parents 00ccac8 + 8e30056 commit 1bfb805

13 files changed

+580
-178
lines changed

src/make-find-mixin.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ export default function makeBaseModel(options: FeathersVuexOptions) {
4949
const { serverAlias } = options
5050

5151
// If this serverAlias already has a BaseModel, return it
52-
const ExistingBaseModel = _get(globalModels, `[${serverAlias}].BaseModel`)
52+
const ExistingBaseModel = _get(globalModels, [serverAlias, 'BaseModel'])
5353
if (ExistingBaseModel) {
5454
return ExistingBaseModel as ModelStatic
5555
}

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
}

src/service-module/service-module.actions.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -301,6 +301,8 @@ export default function makeServiceActions(service: Service<any>) {
301301
const toRemove = []
302302
const { idField, autoRemove } = state
303303

304+
const disableRemove = response.disableRemove || !autoRemove
305+
304306
list.forEach(item => {
305307
const id = getId(item, idField)
306308
const existingItem = state.keyedById[id]
@@ -310,13 +312,10 @@ export default function makeServiceActions(service: Service<any>) {
310312
}
311313
})
312314

313-
if (!isPaginated && autoRemove) {
315+
if (!isPaginated && !disableRemove) {
314316
// Find IDs from the state which are not in the list
315317
state.ids.forEach(id => {
316-
if (
317-
id !== state.currentId &&
318-
!list.some(item => getId(item, idField) === id)
319-
) {
318+
if (!list.some(item => getId(item, idField) === id)) {
320319
toRemove.push(state.keyedById[id])
321320
}
322321
})
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
import { getId } from '../utils'
2+
import _debounce from 'lodash/debounce'
3+
import { globalModels } from './global-models'
4+
5+
export interface ServiceEventsDebouncedQueue {
6+
addOrUpdateById: {}
7+
removeItemById: {}
8+
enqueueAddOrUpdate(item: any): void
9+
enqueueRemoval(item: any): void
10+
flushAddOrUpdateQueue(): void
11+
flushRemoveItemQueue(): void
12+
}
13+
14+
export default function enableServiceEvents({
15+
service,
16+
Model,
17+
store,
18+
options
19+
}): ServiceEventsDebouncedQueue {
20+
const debouncedQueue: ServiceEventsDebouncedQueue = {
21+
addOrUpdateById: {},
22+
removeItemById: {},
23+
enqueueAddOrUpdate(item): void {
24+
const id = getId(item, options.idField)
25+
this.addOrUpdateById[id] = item
26+
if (this.removeItemById.hasOwnProperty(id)) {
27+
delete this.removeItemById[id]
28+
}
29+
this.flushAddOrUpdateQueue()
30+
},
31+
enqueueRemoval(item): void {
32+
const id = getId(item, options.idField)
33+
this.removeItemById[id] = item
34+
if (this.addOrUpdateById.hasOwnProperty(id)) {
35+
delete this.addOrUpdateById[id]
36+
}
37+
this.flushRemoveItemQueue()
38+
},
39+
flushAddOrUpdateQueue: _debounce(
40+
async function () {
41+
const values = Object.values(this.addOrUpdateById)
42+
if (values.length === 0) return
43+
await store.dispatch(`${options.namespace}/addOrUpdateList`, {
44+
data: values,
45+
disableRemove: true
46+
})
47+
this.addOrUpdateById = {}
48+
},
49+
options.debounceEventsTime || 20,
50+
{ maxWait: options.debounceEventsMaxWait }
51+
),
52+
flushRemoveItemQueue: _debounce(
53+
function () {
54+
const values = Object.values(this.removeItemById)
55+
if (values.length === 0) return
56+
store.commit(`${options.namespace}/removeItems`, values)
57+
this.removeItemById = {}
58+
},
59+
options.debounceEventsTime || 20,
60+
{ maxWait: options.debounceEventsMaxWait }
61+
)
62+
}
63+
64+
const handleEvent = (eventName, item, mutationName): void => {
65+
const handler = options.handleEvents[eventName]
66+
const confirmOrArray = handler(item, {
67+
model: Model,
68+
models: globalModels
69+
})
70+
const [affectsStore, modified = item] = Array.isArray(confirmOrArray)
71+
? confirmOrArray
72+
: [confirmOrArray]
73+
if (affectsStore) {
74+
if (!options.debounceEventsTime) {
75+
eventName === 'removed'
76+
? store.commit(`${options.namespace}/removeItem`, modified)
77+
: store.dispatch(`${options.namespace}/${mutationName}`, modified)
78+
} else {
79+
eventName === 'removed'
80+
? debouncedQueue.enqueueRemoval(item)
81+
: debouncedQueue.enqueueAddOrUpdate(item)
82+
}
83+
}
84+
}
85+
86+
// Listen to socket events when available.
87+
service.on('created', item => {
88+
handleEvent('created', item, 'addOrUpdate')
89+
Model.emit && Model.emit('created', item)
90+
})
91+
service.on('updated', item => {
92+
handleEvent('updated', item, 'addOrUpdate')
93+
Model.emit && Model.emit('updated', item)
94+
})
95+
service.on('patched', item => {
96+
handleEvent('patched', item, 'addOrUpdate')
97+
Model.emit && Model.emit('patched', item)
98+
})
99+
service.on('removed', item => {
100+
handleEvent('removed', item, 'removeItem')
101+
Model.emit && Model.emit('removed', item)
102+
})
103+
104+
return debouncedQueue
105+
}

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

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,7 @@ import { ServiceState } from '..'
1414
import { Id } from '@feathersjs/feathers'
1515

1616
const FILTERS = ['$sort', '$limit', '$skip', '$select']
17-
const OPERATORS = ['$in', '$nin', '$lt', '$lte', '$gt', '$gte', '$ne', '$or']
1817
const additionalOperators = ['$elemMatch']
19-
const defaultOps = FILTERS.concat(OPERATORS).concat(additionalOperators)
2018

2119
export default function makeServiceGetters() {
2220
return {
@@ -109,10 +107,7 @@ export default function makeServiceGetters() {
109107
if (keepCopiesInStore) {
110108
return state.copiesById[id]
111109
} else {
112-
const Model = _get(
113-
models,
114-
`[${serverAlias}].byServicePath[${servicePath}]`
115-
)
110+
const Model = _get(models, [serverAlias, 'byServicePath', servicePath])
116111

117112
return Model.copiesById[id]
118113
}

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

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ export type PendingIdServiceMethodName = Exclude<
3535
export default function makeServiceMutations() {
3636
function addItems(state, items) {
3737
const { serverAlias, idField, tempIdField, modelName } = state
38-
const Model = _get(models, `[${serverAlias}][${modelName}]`)
39-
const BaseModel = _get(models, `[${serverAlias}].BaseModel`)
38+
const Model = _get(models, [serverAlias, modelName])
39+
const BaseModel = _get(models, [serverAlias, 'BaseModel'])
4040

4141
for (let item of items) {
4242
const id = getId(item, idField)
@@ -70,8 +70,8 @@ export default function makeServiceMutations() {
7070

7171
function updateItems(state, items) {
7272
const { idField, replaceItems, addOnUpsert, serverAlias, modelName } = state
73-
const Model = _get(models, `[${serverAlias}][${modelName}]`)
74-
const BaseModel = _get(models, `[${state.serverAlias}].BaseModel`)
73+
const Model = _get(models, [serverAlias, modelName])
74+
const BaseModel = _get(models, [state.serverAlias, 'BaseModel'])
7575

7676
for (let item of items) {
7777
const id = getId(item, idField)
@@ -122,7 +122,7 @@ export default function makeServiceMutations() {
122122
}
123123

124124
function mergeInstance(state, item) {
125-
const { serverAlias, idField, tempIdField, modelName } = state
125+
const { idField } = state
126126
const id = getId(item, idField)
127127
const existingItem = state.keyedById[id]
128128
if (existingItem) {
@@ -173,7 +173,7 @@ export default function makeServiceMutations() {
173173
}
174174

175175
// Add _id to temp's clone as well if it exists
176-
const Model = _get(models, `[${state.serverAlias}][${state.modelName}]`)
176+
const Model = _get(models, [state.serverAlias, state.modelName])
177177
const tempClone = Model && Model.copiesById && Model.copiesById[tempId]
178178
if (tempClone) {
179179
tempClone[state.idField] = id
@@ -263,10 +263,7 @@ export default function makeServiceMutations() {
263263
createCopy(state, id) {
264264
const { servicePath, keepCopiesInStore, serverAlias } = state
265265
const current = state.keyedById[id] || state.tempsById[id]
266-
const Model = _get(
267-
models,
268-
`[${serverAlias}].byServicePath[${servicePath}]`
269-
)
266+
const Model = _get(models, [serverAlias, 'byServicePath', servicePath])
270267

271268
if (Model) {
272269
var model = new Model(current, { clone: true })
@@ -292,13 +289,14 @@ export default function makeServiceMutations() {
292289
// Resets the copy to match the original record, locally
293290
resetCopy(state, id) {
294291
const { servicePath, keepCopiesInStore } = state
295-
const Model = _get(
296-
models,
297-
`[${state.serverAlias}].byServicePath[${servicePath}]`
298-
)
292+
const Model = _get(models, [
293+
state.serverAlias,
294+
'byServicePath',
295+
servicePath
296+
])
299297
const copy = keepCopiesInStore
300298
? state.copiesById[id]
301-
: Model && _get(Model, `copiesById[${id}]`)
299+
: Model && _get(Model, ['copiesById', id])
302300

303301
if (copy) {
304302
const original =
@@ -312,13 +310,14 @@ export default function makeServiceMutations() {
312310
// Deep assigns copy to original record, locally
313311
commitCopy(state, id) {
314312
const { servicePath, keepCopiesInStore } = state
315-
const Model = _get(
316-
models,
317-
`[${state.serverAlias}].byServicePath[${servicePath}]`
318-
)
313+
const Model = _get(models, [
314+
state.serverAlias,
315+
'byServicePath',
316+
servicePath
317+
])
319318
const copy = keepCopiesInStore
320319
? state.copiesById[id]
321-
: Model && _get(Model, `copiesById[${id}]`)
320+
: Model && _get(Model, ['copiesById', id])
322321

323322
if (copy) {
324323
const original =

src/service-module/service-module.state.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ export interface ServiceStateExclusiveDefaults {
3737
}
3838
paramsForServer: string[]
3939
modelName?: string
40-
40+
debounceEventsTime: number
4141
isIdCreatePending: Id[]
4242
isIdUpdatePending: Id[]
4343
isIdPatchPending: Id[]
@@ -83,6 +83,8 @@ export interface ServiceState<M extends Model = Model> {
8383
default?: PaginationState
8484
}
8585
modelName?: string
86+
debounceEventsTime: number
87+
debounceEventsMaxWait: number
8688
isIdCreatePending: Id[]
8789
isIdUpdatePending: Id[]
8890
isIdPatchPending: Id[]
@@ -121,6 +123,7 @@ export default function makeDefaultState(options: MakeServicePluginOptions) {
121123
defaultSkip: null
122124
},
123125
paramsForServer: ['$populateParams'],
126+
debounceEventsTime: null,
124127

125128
isFindPending: false,
126129
isGetPending: false,
@@ -139,7 +142,7 @@ export default function makeDefaultState(options: MakeServicePluginOptions) {
139142
isIdCreatePending: [],
140143
isIdUpdatePending: [],
141144
isIdPatchPending: [],
142-
isIdRemovePending: [],
145+
isIdRemovePending: []
143146
}
144147

145148
if (options.Model) {

0 commit comments

Comments
 (0)