Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions lib/Onyx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,9 @@ function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>):
return Promise.resolve();
}

return OnyxMerge.applyMerge(key, existingValue, validChanges).then(({mergedValue}) => {
return OnyxMerge.applyMerge(key, existingValue, validChanges).then(({mergedValue, updatePromise}) => {
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.MERGE, key, changes, mergedValue);
return updatePromise;
});
} catch (error) {
Logger.logAlert(`An error occurred while applying merge for key: ${key}, Error: ${error}`);
Expand Down Expand Up @@ -379,6 +380,16 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
keysToBeClearedFromStorage.push(key);
}

const updatePromises: Array<Promise<void>> = [];

// Notify the subscribers for each key/value group so they can receive the new values
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
updatePromises.push(OnyxUtils.scheduleSubscriberUpdate(key, value));
}
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
updatePromises.push(OnyxUtils.scheduleNotifyCollectionSubscribers(key, value.newValues, value.oldValues));
}

// Exclude RAM-only keys to prevent them from being saved to storage
const defaultKeyValuePairs = Object.entries(
Object.keys(defaultKeyStates)
Expand All @@ -397,14 +408,7 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
.then(() => Storage.multiSet(defaultKeyValuePairs))
.then(() => {
DevTools.clearState(keysToPreserve);

// Notify the subscribers for each key/value group so they can receive the new values
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
OnyxUtils.keyChanged(key, value);
}
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
OnyxUtils.keysChanged(key, value.newValues, value.oldValues);
}
return Promise.all(updatePromises);
});
})
.then(() => undefined);
Expand Down
5 changes: 3 additions & 2 deletions lib/OnyxMerge/index.native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,21 @@ const applyMerge: ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<T
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.MERGE, key, mergedValue, hasChanged);

// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);
const updatePromise = OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);

const shouldSkipStorageOperations = !hasChanged || OnyxUtils.isRamOnlyKey(key);

// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
if (shouldSkipStorageOperations) {
return Promise.resolve({mergedValue});
return Promise.resolve({mergedValue, updatePromise});
}

// For native platforms we use `mergeItem` that will take advantage of JSON_PATCH and JSON_REPLACE SQL operations to
// merge the object in a performant way.
return Storage.mergeItem(key, batchedChanges as OnyxValue<TKey>, replaceNullPatches).then(() => ({
mergedValue,
updatePromise,
}));
};

Expand Down
5 changes: 3 additions & 2 deletions lib/OnyxMerge/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,20 @@ const applyMerge: ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<T
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.MERGE, key, mergedValue, hasChanged);

// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);
const updatePromise = OnyxUtils.broadcastUpdate(key, mergedValue as OnyxValue<TKey>, hasChanged);

const shouldSkipStorageOperations = !hasChanged || OnyxUtils.isRamOnlyKey(key);

// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
// If the key is marked as RAM-only, it should not be saved nor updated in the storage.
if (shouldSkipStorageOperations) {
return Promise.resolve({mergedValue});
return Promise.resolve({mergedValue, updatePromise});
}

// For web platforms we use `setItem` since the object was already merged with its changes before.
return Storage.setItem(key, mergedValue as OnyxValue<TKey>).then(() => ({
mergedValue,
updatePromise,
}));
};

Expand Down
1 change: 1 addition & 0 deletions lib/OnyxMerge/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {OnyxInput, OnyxKey} from '../types';

type ApplyMergeResult<TValue> = {
mergedValue: TValue;
updatePromise: Promise<void>;
};

type ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<OnyxKey> | undefined, TChange extends OnyxInput<OnyxKey> | null>(
Expand Down
Loading
Loading