Skip to content

Commit 5e44d80

Browse files
committed
Merge branch 'main' into @chrispader/update-nitro-sqlite-to-v9.6.0
2 parents 674b1f2 + 2ae39de commit 5e44d80

File tree

11 files changed

+288
-151
lines changed

11 files changed

+288
-151
lines changed

lib/Onyx.ts

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,13 @@ function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>):
237237

238238
try {
239239
const validChanges = mergeQueue[key].filter((change) => {
240-
const {isCompatible, existingValueType, newValueType} = utils.checkCompatibilityWithExistingValue(change, existingValue);
240+
const {isCompatible, existingValueType, newValueType, isEmptyArrayCoercion} = utils.checkCompatibilityWithExistingValue(change, existingValue);
241+
if (isEmptyArrayCoercion) {
242+
// Merging an object into an empty array isn't semantically correct, but we allow it
243+
// in case we accidentally encoded an empty object as an empty array in PHP. If you're
244+
// looking at a bugbot from this message, we're probably missing that key in OnyxKeys::KEYS_REQUIRING_EMPTY_OBJECT
245+
Logger.logAlert(`[ENSURE_BUGBOT] Onyx merge called on key "${key}" whose existing value is an empty array. Will coerce to object.`);
246+
}
241247
if (!isCompatible) {
242248
Logger.logAlert(logMessages.incompatibleUpdateAlert(key, 'merge', existingValueType, newValueType));
243249
}
@@ -260,8 +266,9 @@ function merge<TKey extends OnyxKey>(key: TKey, changes: OnyxMergeInput<TKey>):
260266
return Promise.resolve();
261267
}
262268

263-
return OnyxMerge.applyMerge(key, existingValue, validChanges).then(({mergedValue}) => {
269+
return OnyxMerge.applyMerge(key, existingValue, validChanges).then(({mergedValue, updatePromise}) => {
264270
OnyxUtils.sendActionToDevTools(OnyxUtils.METHOD.MERGE, key, changes, mergedValue);
271+
return updatePromise;
265272
});
266273
} catch (error) {
267274
Logger.logAlert(`An error occurred while applying merge for key: ${key}, Error: ${error}`);
@@ -373,6 +380,16 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
373380
keysToBeClearedFromStorage.push(key);
374381
}
375382

383+
const updatePromises: Array<Promise<void>> = [];
384+
385+
// Notify the subscribers for each key/value group so they can receive the new values
386+
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
387+
updatePromises.push(OnyxUtils.scheduleSubscriberUpdate(key, value));
388+
}
389+
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
390+
updatePromises.push(OnyxUtils.scheduleNotifyCollectionSubscribers(key, value.newValues, value.oldValues));
391+
}
392+
376393
// Exclude RAM-only keys to prevent them from being saved to storage
377394
const defaultKeyValuePairs = Object.entries(
378395
Object.keys(defaultKeyStates)
@@ -391,14 +408,7 @@ function clear(keysToPreserve: OnyxKey[] = []): Promise<void> {
391408
.then(() => Storage.multiSet(defaultKeyValuePairs))
392409
.then(() => {
393410
DevTools.clearState(keysToPreserve);
394-
395-
// Notify the subscribers for each key/value group so they can receive the new values
396-
for (const [key, value] of Object.entries(keyValuesToResetIndividually)) {
397-
OnyxUtils.keyChanged(key, value);
398-
}
399-
for (const [key, value] of Object.entries(keyValuesToResetAsCollection)) {
400-
OnyxUtils.keysChanged(key, value.newValues, value.oldValues);
401-
}
411+
return Promise.all(updatePromises);
402412
});
403413
})
404414
.then(() => undefined);

lib/OnyxMerge/index.native.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,21 @@ const applyMerge: ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<T
2626
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.MERGE, key, mergedValue, hasChanged);
2727

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

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

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

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

lib/OnyxMerge/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,20 @@ const applyMerge: ApplyMerge = <TKey extends OnyxKey, TValue extends OnyxInput<T
1818
OnyxUtils.logKeyChanged(OnyxUtils.METHOD.MERGE, key, mergedValue, hasChanged);
1919

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

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

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

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

lib/OnyxMerge/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type {OnyxInput, OnyxKey} from '../types';
22

33
type ApplyMergeResult<TValue> = {
44
mergedValue: TValue;
5+
updatePromise: Promise<void>;
56
};
67

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

0 commit comments

Comments
 (0)