react-native-onyx 2.0.26 → 2.0.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Onyx.js +17 -21
- package/dist/storage/__mocks__/index.d.ts +1 -1
- package/dist/storage/index.js +2 -2
- package/dist/storage/providers/IDBKeyValProvider.js +2 -2
- package/dist/storage/providers/MemoryOnlyProvider.js +2 -2
- package/dist/storage/providers/SQLiteProvider.js +5 -2
- package/dist/storage/providers/types.d.ts +4 -3
- package/package.json +1 -1
package/dist/Onyx.js
CHANGED
|
@@ -271,38 +271,34 @@ function merge(key, changes) {
|
|
|
271
271
|
}
|
|
272
272
|
try {
|
|
273
273
|
// We first only merge the changes, so we can provide these to the native implementation (SQLite uses only delta changes in "JSON_PATCH" to merge)
|
|
274
|
-
// We don't want to remove null values from the "
|
|
275
|
-
|
|
276
|
-
//
|
|
274
|
+
// We don't want to remove null values from the "batchedDeltaChanges", because SQLite uses them to remove keys from storage natively.
|
|
275
|
+
const batchedDeltaChanges = OnyxUtils_1.default.applyMerge(undefined, mergeQueue[key], false);
|
|
276
|
+
// Case (1): When there is no existing value in storage, we want to set the value instead of merge it.
|
|
277
|
+
// Case (2): The presence of a top-level `null` in the merge queue instructs us to drop the whole existing value.
|
|
277
278
|
// In this case, we can't simply merge the batched changes with the existing value, because then the null in the merge queue would have no effect
|
|
278
|
-
const
|
|
279
|
+
const shouldSetValue = !existingValue || mergeQueue[key].includes(null);
|
|
279
280
|
// Clean up the write queue, so we don't apply these changes again
|
|
280
281
|
delete mergeQueue[key];
|
|
281
282
|
delete mergeQueuePromise[key];
|
|
282
283
|
// If the batched changes equal null, we want to remove the key from storage, to reduce storage size
|
|
283
|
-
const { wasRemoved } = OnyxUtils_1.default.removeNullValues(key,
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
//
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
//
|
|
290
|
-
|
|
291
|
-
// Therefore we need to remove null values from the `batchedChanges` which are sent to the SQLite, if no existing value is present.
|
|
292
|
-
if (!existingValue) {
|
|
293
|
-
batchedChanges = OnyxUtils_1.default.applyMerge(undefined, [batchedChanges], true);
|
|
294
|
-
}
|
|
295
|
-
const hasChanged = OnyxCache_1.default.hasValueChanged(key, modifiedData);
|
|
284
|
+
const { wasRemoved } = OnyxUtils_1.default.removeNullValues(key, batchedDeltaChanges);
|
|
285
|
+
// For providers that can't handle delta changes, we need to merge the batched changes with the existing value beforehand.
|
|
286
|
+
// The "preMergedValue" will be directly "set" in storage instead of being merged
|
|
287
|
+
// Therefore we merge the batched changes with the existing value to get the final merged value that will be stored.
|
|
288
|
+
// We can remove null values from the "preMergedValue", because "null" implicates that the user wants to remove a value from storage.
|
|
289
|
+
const preMergedValue = OnyxUtils_1.default.applyMerge(shouldSetValue ? undefined : existingValue, [batchedDeltaChanges], true);
|
|
290
|
+
// In cache, we don't want to remove the key if it's null to improve performance and speed up the next merge.
|
|
291
|
+
const hasChanged = OnyxCache_1.default.hasValueChanged(key, preMergedValue);
|
|
296
292
|
// Logging properties only since values could be sensitive things we don't want to log
|
|
297
|
-
Logger.logInfo(`merge called for key: ${key}${underscore_1.default.isObject(
|
|
293
|
+
Logger.logInfo(`merge called for key: ${key}${underscore_1.default.isObject(batchedDeltaChanges) ? ` properties: ${underscore_1.default.keys(batchedDeltaChanges).join(',')}` : ''} hasChanged: ${hasChanged}`);
|
|
298
294
|
// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
|
|
299
|
-
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key,
|
|
295
|
+
const updatePromise = OnyxUtils_1.default.broadcastUpdate(key, preMergedValue, hasChanged, wasRemoved);
|
|
300
296
|
// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
|
|
301
297
|
if (!hasChanged || wasRemoved) {
|
|
302
298
|
return updatePromise;
|
|
303
299
|
}
|
|
304
|
-
return storage_1.default.mergeItem(key,
|
|
305
|
-
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MERGE, key, changes,
|
|
300
|
+
return storage_1.default.mergeItem(key, batchedDeltaChanges, preMergedValue, shouldSetValue).then(() => {
|
|
301
|
+
OnyxUtils_1.default.sendActionToDevTools(OnyxUtils_1.default.METHOD.MERGE, key, changes, preMergedValue);
|
|
306
302
|
return updatePromise;
|
|
307
303
|
});
|
|
308
304
|
}
|
|
@@ -5,7 +5,7 @@ declare const StorageMock: {
|
|
|
5
5
|
multiGet: jest.Mock<Promise<import("../providers/types").KeyValuePairList>, [keys: import("../providers/types").KeyList]>;
|
|
6
6
|
setItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [key: any, value: unknown]>;
|
|
7
7
|
multiSet: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [pairs: import("../providers/types").KeyValuePairList]>;
|
|
8
|
-
mergeItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [key: any,
|
|
8
|
+
mergeItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult>, [key: any, deltaChanges: unknown, preMergedValue: unknown, shouldSetValue?: boolean | undefined]>;
|
|
9
9
|
multiMerge: jest.Mock<Promise<void | import("react-native-quick-sqlite").BatchQueryResult | IDBValidKey[]>, [pairs: import("../providers/types").KeyValuePairList]>;
|
|
10
10
|
removeItem: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [key: string]>;
|
|
11
11
|
removeItems: jest.Mock<Promise<void | import("react-native-quick-sqlite").QueryResult>, [keys: import("../providers/types").KeyList]>;
|
package/dist/storage/index.js
CHANGED
|
@@ -118,8 +118,8 @@ const Storage = {
|
|
|
118
118
|
/**
|
|
119
119
|
* Merging an existing value with a new one
|
|
120
120
|
*/
|
|
121
|
-
mergeItem: (key,
|
|
122
|
-
const promise = provider.mergeItem(key,
|
|
121
|
+
mergeItem: (key, deltaChanges, preMergedValue, shouldSetValue = false) => tryOrDegradePerformance(() => {
|
|
122
|
+
const promise = provider.mergeItem(key, deltaChanges, preMergedValue, shouldSetValue);
|
|
123
123
|
if (shouldKeepInstancesSync) {
|
|
124
124
|
return promise.then(() => InstanceSync_1.default.mergeItem(key));
|
|
125
125
|
}
|
|
@@ -37,9 +37,9 @@ const provider = {
|
|
|
37
37
|
return Promise.all(upsertMany);
|
|
38
38
|
});
|
|
39
39
|
}),
|
|
40
|
-
mergeItem(key,
|
|
40
|
+
mergeItem(key, _deltaChanges, preMergedValue) {
|
|
41
41
|
// Since Onyx also merged the existing value with the changes, we can just set the value directly
|
|
42
|
-
return provider.setItem(key,
|
|
42
|
+
return provider.setItem(key, preMergedValue);
|
|
43
43
|
},
|
|
44
44
|
multiSet: (pairs) => (0, idb_keyval_1.setMany)(pairs, idbKeyValStore),
|
|
45
45
|
clear: () => (0, idb_keyval_1.clear)(idbKeyValStore),
|
|
@@ -64,9 +64,9 @@ const provider = {
|
|
|
64
64
|
/**
|
|
65
65
|
* Merging an existing value with a new one
|
|
66
66
|
*/
|
|
67
|
-
mergeItem(key,
|
|
67
|
+
mergeItem(key, _deltaChanges, preMergedValue) {
|
|
68
68
|
// Since Onyx already merged the existing value with the changes, we can just set the value directly
|
|
69
|
-
return this.setItem(key,
|
|
69
|
+
return this.setItem(key, preMergedValue);
|
|
70
70
|
},
|
|
71
71
|
/**
|
|
72
72
|
* Multiple merging of existing and new values in a batch
|
|
@@ -68,8 +68,11 @@ const provider = {
|
|
|
68
68
|
});
|
|
69
69
|
return db.executeBatchAsync([[query, queryArguments]]);
|
|
70
70
|
},
|
|
71
|
-
mergeItem(key,
|
|
72
|
-
|
|
71
|
+
mergeItem(key, deltaChanges, preMergedValue, shouldSetValue) {
|
|
72
|
+
if (shouldSetValue) {
|
|
73
|
+
return this.setItem(key, preMergedValue);
|
|
74
|
+
}
|
|
75
|
+
return this.multiMerge([[key, deltaChanges]]);
|
|
73
76
|
},
|
|
74
77
|
getAllKeys: () => db.executeAsync('SELECT record_key FROM keyvaluepairs;').then(({ rows }) => {
|
|
75
78
|
// eslint-disable-next-line no-underscore-dangle
|
|
@@ -35,10 +35,11 @@ type StorageProvider = {
|
|
|
35
35
|
multiMerge: (pairs: KeyValuePairList) => Promise<BatchQueryResult | IDBValidKey[] | void>;
|
|
36
36
|
/**
|
|
37
37
|
* Merges an existing value with a new one by leveraging JSON_PATCH
|
|
38
|
-
* @param
|
|
39
|
-
* @param
|
|
38
|
+
* @param deltaChanges - the delta for a specific key
|
|
39
|
+
* @param preMergedValue - the pre-merged data from `Onyx.applyMerge`
|
|
40
|
+
* @param shouldSetValue - whether the data should be set instead of merged
|
|
40
41
|
*/
|
|
41
|
-
mergeItem: <TKey extends OnyxKey>(key: TKey,
|
|
42
|
+
mergeItem: <TKey extends OnyxKey>(key: TKey, deltaChanges: OnyxValue<TKey>, preMergedValue: OnyxValue<TKey>, shouldSetValue?: boolean) => Promise<BatchQueryResult | void>;
|
|
42
43
|
/**
|
|
43
44
|
* Returns all keys available in storage
|
|
44
45
|
*/
|