Skip to content

Commit fe05748

Browse files
committed
Fix patching to update only existing props
1 parent bdb9a36 commit fe05748

File tree

4 files changed

+61
-48
lines changed

4 files changed

+61
-48
lines changed

lib/Actions.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { ActionContext, Commit, ActionTree, Action } from "vuex";
22
import { AxiosInstance, Method } from "axios";
33
import at from "lodash-es/at";
4+
import cloneDeep from "lodash-es/cloneDeep";
45
import flatMap from "lodash-es/flatMap";
56
import forEach from "lodash-es/forEach";
67
import get from "lodash-es/get";
@@ -16,11 +17,13 @@ import { applyModifier, formatUrl } from "./utils";
1617
class ActionBase<S, R> {
1718
private _axios: AxiosInstance;
1819
private _models: ModelTypeTree;
19-
private _dataPath: string | undefined;
20+
private _dataPath = "data";
2021
constructor(axios: AxiosInstance, models: ModelTypeTree, dataPath?: string) {
2122
this._axios = axios;
2223
this._models = models;
23-
this._dataPath = dataPath;
24+
if (dataPath) {
25+
this._dataPath = `${this._dataPath}.${dataPath}`;
26+
}
2427

2528
// add watched changes to queue
2629
// this.queueActionWatcher = (
@@ -62,10 +65,11 @@ class ActionBase<S, R> {
6265
return this._axios
6366
.get(formatUrl(payload), payload.axiosConfig)
6467
.then(async result => {
65-
const resultData = this._dataPath
66-
? get(result.data, this._dataPath)
67-
: result.data;
68-
commit(`ADD_${this._getModel(payload).name.toUpperCase()}`, resultData);
68+
const resultData = get(result, this._dataPath);
69+
commit(
70+
`ADD_${this._getModel(payload).name.toUpperCase()}`,
71+
cloneDeep(resultData)
72+
);
6973
return resultData;
7074
});
7175
}
@@ -88,10 +92,11 @@ class ActionBase<S, R> {
8892
};
8993
const config = { ...mainConfig, ...payload.axiosConfig };
9094
return this._axios(config).then(result => {
91-
const resultData = this._dataPath
92-
? get(result.data, this._dataPath)
93-
: result.data;
94-
commit(`ADD_${this._getModel(payload).name.toUpperCase()}`, resultData);
95+
const resultData = get(result, this._dataPath);
96+
commit(
97+
`ADD_${this._getModel(payload).name.toUpperCase()}`,
98+
cloneDeep(resultData)
99+
);
95100
return resultData;
96101
});
97102
}

lib/ApiStore.ts

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,18 @@ export default class ApiStore<S> implements StoreOptions<S> {
4444
this.state[modelIdx] = model.type;
4545

4646
// adding ADD_* mutations
47-
this.mutations[`ADD_${model.name.toUpperCase()}`] = (
47+
this.mutations[`ADD_${model.name.toUpperCase()}`] = async (
4848
myState: ApiState,
4949
item: IndexedObject | Array<IndexedObject>
50-
) =>
51-
applyModifier("afterGet", modelKey, this.models, item).then(
52-
(i: IndexedObject) => {
53-
this.storeOriginItem(
54-
get(myState, `${modelIdx}.originItems`),
55-
i,
56-
model.beforeQueue
57-
);
58-
this.patchEntity(myState, model, i);
59-
// this.linkReferences(i, myState, model.references);
60-
myState[modelIdx].lastLoad = new Date();
61-
}
50+
) => {
51+
const res = await this.patchEntity(myState, model, item);
52+
this.storeOriginItem(
53+
get(myState, `${modelIdx}.originItems`),
54+
res,
55+
model.beforeQueue
6256
);
57+
myState[modelIdx].lastLoad = new Date();
58+
};
6359

6460
// adding DELETE_* mutations
6561
this.mutations[`DELETE_${model.name.toUpperCase()}`] = (
@@ -200,20 +196,34 @@ export default class ApiStore<S> implements StoreOptions<S> {
200196
const store = state[model.plural];
201197

202198
if (has(store.items, entity.id)) {
203-
forEach(entity, (value, idx: string) => {
204-
if (!isFunction(value)) {
205-
if (!isEqual(value, get(store.items[entity.id], idx))) {
206-
Vue.set(store.items[entity.id], idx, value);
199+
forEach(entity, (value, name: string) => {
200+
if (!isFunction(value) && !has(model.references, name)) {
201+
const storeEntity = store.items[entity.id];
202+
if (
203+
has(storeEntity, name) &&
204+
!isEqual(value, get(storeEntity, name))
205+
) {
206+
Vue.set(storeEntity, name, value);
207207
}
208208
}
209209
});
210210

211211
return store.items[entity.id];
212212
} else {
213-
store.items = { ...store.items, [entity.id]: entity };
214-
this.storeOriginItem(store.originItems, entity, model.beforeQueue);
213+
const toStoreEntity = await applyModifier(
214+
"afterGet",
215+
model.name.toLowerCase(),
216+
this.models,
217+
entity
218+
);
219+
store.items = { ...store.items, [entity.id]: toStoreEntity };
220+
this.storeOriginItem(
221+
store.originItems,
222+
toStoreEntity,
223+
model.beforeQueue
224+
);
215225

216-
return entity;
226+
return toStoreEntity;
217227
}
218228
}
219229
}
@@ -224,15 +234,8 @@ export default class ApiStore<S> implements StoreOptions<S> {
224234
modelName: string,
225235
prop: string
226236
) {
227-
const refEntity = await applyModifier(
228-
"afterGet",
229-
modelName,
230-
this.models,
231-
entity[prop]
232-
);
233-
234237
if (has(this.models, modelName)) {
235-
return this.patchEntity(state, this.models[modelName], refEntity);
238+
return this.patchEntity(state, this.models[modelName], entity[prop]);
236239
} else {
237240
// eslint-disable-next-line no-console
238241
console.warn(

tests/unit/apistore.spec.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import axios from "axios";
55
import flushPromises from "flush-promises";
66
import size from "lodash-es/size";
77
import forEach from "lodash-es/forEach";
8-
import cloneDeep from "lodash-es/cloneDeep";
98
import ApiStorePlugin from "../../lib/ApiStorePlugin";
109
import ApiState from "../../lib/ApiState";
1110

@@ -134,23 +133,27 @@ describe("ApiStore by default", function() {
134133
});
135134

136135
it("test force fetch", async () => {
137-
const singleResource = cloneDeep(data[0]);
138136
await fillStore();
139137
// Uncomment the following line and set expect(mock.history.get.length).toBe(1);
140138
// when the next axios-mock-adapter version (current v1.16.0) is released
141139
// mock.resetHistory();
142-
singleResource.newData = "new_stuff";
143-
mock.onGet(`/resource/${singleResource.id}`).reply(200, singleResource);
144-
store.dispatch("api/get", {
145-
id: singleResource.id,
140+
store.getters["api/resources"].items[data[0].id].name = "changed name";
141+
store.getters["api/resources"].items[data[0].id].newData = "new_stuff";
142+
mock.onGet(`/resource/${data[0].id}`).reply(200, data[0]);
143+
const res = await store.dispatch("api/get", {
144+
id: data[0].id,
146145
type: "resource",
147146
forceFetch: true
148147
});
149148
await flushPromises();
150149
expect(mock.history.get.length).toBe(2);
151-
expect(
152-
store.getters["api/resources"].items[singleResource.id]
153-
).toStrictEqual(singleResource);
150+
expect(store.getters["api/resources"].items[data[0].id].name).not.toBe(
151+
"changed name"
152+
);
153+
expect(store.getters["api/resources"].items[data[0].id].newData).toBe(
154+
"new_stuff"
155+
);
156+
expect(res).toStrictEqual(data[0]);
154157
});
155158

156159
it("test if references are proper ref", async () => {

tests/unit/apistoreCustomModel.spec.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,9 @@ describe("ApiStore custom model", function() {
459459
mock.onGet(`/user/${user.id}`).reply(200, user);
460460
store.dispatch("api/get", {
461461
id: user.id,
462-
type: "user"
462+
type: "user",
463+
forceFetch: true,
464+
clear: false
463465
});
464466
await flushPromises();
465467
expect(store.getters["api/users"].items[user.id].localProp).toBe(true);

0 commit comments

Comments
 (0)