Skip to content

Commit eaf44f0

Browse files
authored
Merge pull request #19 from rezo-labs/feature/optimize_with_cache
Optimize api query with cache
2 parents c19bab5 + a6eb9a2 commit eaf44f0

File tree

1 file changed

+66
-25
lines changed

1 file changed

+66
-25
lines changed

src/utils.ts

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,14 +45,21 @@ export const useDeepValues = (
4545
) => {
4646
const api = useApi();
4747
const finalValues = ref<Record<string, any>>({});
48+
let fieldCache: Record<string, any> = {};
49+
let itemCache: Record<string, any> = {};
4850
// Directus store o2m value as reference so when o2m updated, val & oldVal in watch are the same.
4951
// This will serialize values so when o2m fields are updated, their changes can be seen.
50-
const cloneValues = computed(() => JSON.stringify(values.value));
52+
const cloneValues = computed(() => JSON.stringify(
53+
values.value,
54+
(k, v) => v === undefined ? null : v, // convert all undefined values to null to prevent JSON.stringify from removing their keys
55+
));
5156

5257
watch(
5358
cloneValues,
5459
async (val, oldVal) => {
55-
if (!shouldUpdate(template, computedField, JSON.parse(val), JSON.parse(oldVal))) {
60+
const valObj = JSON.parse(val);
61+
const oldValObj = oldVal !== undefined ? JSON.parse(oldVal) : {};
62+
if (!shouldUpdate(template, computedField, valObj, oldValObj)) {
5663
return;
5764
}
5865

@@ -68,17 +75,25 @@ export const useDeepValues = (
6875
const isM2O = relation.collection === collection;
6976
const fieldName = isM2O ? relation.meta?.many_field : relation.meta?.one_field;
7077

71-
let fieldChanges = values.value[fieldName!] as IRelationUpdate;
72-
if (!fieldChanges) {
73-
continue;
74-
}
78+
let fieldChanges = values.value[fieldName!] as IRelationUpdate ?? {
79+
create: [],
80+
update: [],
81+
delete: [],
82+
};
7583

7684
let arrayOfIds: (string | number)[] = [];
7785
let arrayOfData: unknown[] = [];
7886

7987
if (isM2O) {
8088
if (typeof fieldChanges === 'number' || typeof fieldChanges === 'string') {
8189
fieldChanges = { update: [{ id: fieldChanges }] };
90+
91+
if (typeof oldValObj[key] === 'object') {
92+
// When saving, fieldChanges will return to the initial value.
93+
// We must clear cache to obtain the new value after saving.
94+
fieldCache = {};
95+
itemCache = {};
96+
}
8297
} else if (typeof fieldChanges === 'object') {
8398
if ('id' in fieldChanges) {
8499
fieldChanges = { update: [fieldChanges as { id: number | string }] };
@@ -87,15 +102,26 @@ export const useDeepValues = (
87102
}
88103
}
89104
} else {
105+
if (fieldChanges instanceof Array && !(oldValObj[key] instanceof Array)) {
106+
// When saving, fieldChanges will return to the initial value.
107+
// We must clear cache to obtain the new value after saving.
108+
fieldCache = {};
109+
itemCache = {};
110+
}
111+
90112
if (pk !== '+') {
91-
const {
92-
data: { data },
93-
} = await api.get(`items/${collection}/${pk}`, {
94-
params: {
95-
fields: [key],
96-
},
97-
});
98-
arrayOfIds = arrayOfIds.concat(data[key]);
113+
let data;
114+
if (key in fieldCache) {
115+
data = fieldCache[key];
116+
} else {
117+
data = (await api.get(`items/${collection}/${pk}`, {
118+
params: {
119+
fields: [key],
120+
},
121+
})).data.data[key];
122+
fieldCache[key] = data;
123+
}
124+
arrayOfIds = arrayOfIds.concat(data);
99125
}
100126

101127
if (fieldChanges.delete) {
@@ -109,18 +135,32 @@ export const useDeepValues = (
109135

110136
if (arrayOfIds.length) {
111137
const relatedCollection = isM2O ? relation.related_collection : relation.collection;
138+
const path = relatedCollection === 'directus_users' ? '/users' : `items/${relatedCollection}`;
112139

113-
const {
114-
data: { data },
115-
} = await api.get(`items/${relatedCollection}`, {
116-
params: { filter: { id: { _in: arrayOfIds } } },
117-
});
118-
119-
// merging item updates
120-
arrayOfData = data.map((item: any) => ({
121-
...item,
122-
...fieldChanges.update?.find(({ id }) => item.id === id),
123-
}));
140+
if (relatedCollection) {
141+
let data;
142+
if (relatedCollection in itemCache && arrayOfIds.every(id => id in itemCache[relatedCollection])) {
143+
data = arrayOfIds.map(id => itemCache[relatedCollection][id]);
144+
} else {
145+
data = (await api.get(path, {
146+
params: { filter: { id: { _in: arrayOfIds } } },
147+
})).data.data;
148+
}
149+
150+
// merging item updates
151+
arrayOfData = data.map((item: any) => {
152+
if (relatedCollection in itemCache) {
153+
itemCache[relatedCollection][item.id] = item;
154+
} else {
155+
itemCache[relatedCollection] = { [item.id]: item };
156+
}
157+
158+
return {
159+
...item,
160+
...fieldChanges.update?.find(({ id }) => item.id === id),
161+
};
162+
});
163+
}
124164
}
125165

126166
// must concat after request, created items doenst have ids
@@ -135,6 +175,7 @@ export const useDeepValues = (
135175
},
136176
{
137177
deep: false,
178+
immediate: true,
138179
}
139180
);
140181

0 commit comments

Comments
 (0)