Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Try to synchronize operations within one update #490

Merged
merged 46 commits into from
Jul 16, 2024
Merged
Changes from 2 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
b4c739b
Try to synchronize operations within one update
paultsimura Mar 3, 2024
e9966f0
DRY
paultsimura Mar 4, 2024
9cb563e
Broadcast updates
paultsimura Mar 4, 2024
c7247ea
Formatting
paultsimura Mar 4, 2024
1d32cc2
Update test
paultsimura Mar 4, 2024
748c51f
Update test
paultsimura Mar 5, 2024
d0d261b
Update comments
paultsimura Mar 5, 2024
44617ed
Merge branch 'main' into fix/update-order
paultsimura Mar 6, 2024
f537212
WIP
paultsimura Mar 7, 2024
c160503
WIP
paultsimura Mar 7, 2024
e32f0e3
WIP
paultsimura Mar 7, 2024
b56d236
WIP
paultsimura Mar 7, 2024
f2513d8
WIP
paultsimura Mar 11, 2024
a98aeb1
Remove failing tests for the deep null removal
paultsimura Mar 12, 2024
150a16e
Cleanup
paultsimura Mar 12, 2024
94ec428
Merge branch 'main' into fix/update-order
paultsimura Mar 12, 2024
b954d72
Use multiSet
paultsimura Mar 12, 2024
2796388
Handle `null` merge efficiently
paultsimura Mar 15, 2024
10ab402
Use mergeCollection even for 1-item updates
paultsimura Mar 18, 2024
90473be
Update test: include mergeCollection call
paultsimura Mar 18, 2024
3447e6f
Bring back the 1-item merge
paultsimura Mar 18, 2024
a153237
Merge branch 'main' into fix/update-order
paultsimura Mar 25, 2024
290b4b7
Merge branch 'main' into fix/update-order
paultsimura Apr 5, 2024
00ddb11
Implement the bulk merge in TS
paultsimura Apr 12, 2024
bb3acaa
Merge branch 'main' into fix/update-order
paultsimura Apr 12, 2024
6fea4d3
Fix tests
paultsimura Apr 12, 2024
918d2e9
Merge branch 'main' into fix/update-order
paultsimura Apr 17, 2024
47fc3cb
TS migration
paultsimura Apr 17, 2024
c986e51
Patch: TS migration
paultsimura Apr 17, 2024
3381ff8
Fix TS issues
paultsimura Apr 17, 2024
31fd63e
Fix TS issues
paultsimura Apr 18, 2024
e9abdd5
Merge branch 'main' into fix/update-order
paultsimura Apr 24, 2024
ad25727
Merge branch 'main' into fix/update-order
paultsimura May 13, 2024
4169591
Fix TS issues
paultsimura May 14, 2024
d1b6b95
fix comments
paultsimura May 23, 2024
ca3cd29
Merge branch 'main' into fix/update-order
paultsimura Jun 9, 2024
8ea4699
Resolve conflicts
paultsimura Jun 9, 2024
28c6d5c
Resolve conflicts
paultsimura Jun 18, 2024
230ef57
TEMP: add dist
paultsimura Jun 19, 2024
c2e6351
Merge branch 'main' into fix/update-order
paultsimura Jun 19, 2024
153bc79
TEMP: add dist
paultsimura Jun 19, 2024
2f74bfd
TEMP: remove dist
paultsimura Jun 24, 2024
45b0523
Merge branch 'main' into fix/update-order
paultsimura Jun 28, 2024
d11cbd4
Resolve conflicts
paultsimura Jun 29, 2024
873443c
TEMP: add dist
paultsimura Jun 29, 2024
4fabc64
TEMP: revert dist
paultsimura Jul 16, 2024
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
88 changes: 61 additions & 27 deletions lib/Onyx.js
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
}

/**
* Notifys subscribers and writes current value to cache
* Notifies subscribers and writes current value to cache
*
* @param {String} key
* @param {*} value
Expand Down Expand Up @@ -1437,24 +1437,10 @@ function clear(keysToPreserve = []) {
});
}

/**
* Merges a collection based on their keys
*
* @example
*
* Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, {
* [`${ONYXKEYS.COLLECTION.REPORT}1`]: report1,
* [`${ONYXKEYS.COLLECTION.REPORT}2`]: report2,
* });
*
* @param {String} collectionKey e.g. `ONYXKEYS.COLLECTION.REPORT`
* @param {Object} collection Object collection keyed by individual collection member keys and values
* @returns {Promise}
*/
function mergeCollection(collectionKey, collection) {
function isValidMergeCollection(collectionKey, collection) {
if (!_.isObject(collection) || _.isArray(collection) || _.isEmpty(collection)) {
Logger.logInfo('mergeCollection() called with invalid or empty value. Skipping this update.');
return Promise.resolve();
return false;
}

// Confirm all the collection keys belong to the same parent
Expand All @@ -1471,9 +1457,25 @@ function mergeCollection(collectionKey, collection) {
hasCollectionKeyCheckFailed = true;
Logger.logAlert(`Provided collection doesn't have all its data belonging to the same parent. CollectionKey: ${collectionKey}, DataKey: ${dataKey}`);
});
return !hasCollectionKeyCheckFailed;
}

// Gracefully handle bad mergeCollection updates so it doesn't block the merge queue
if (hasCollectionKeyCheckFailed) {
/**
* Merges a collection based on their keys
*
* @example
*
* Onyx.mergeCollection(ONYXKEYS.COLLECTION.REPORT, {
* [`${ONYXKEYS.COLLECTION.REPORT}1`]: report1,
* [`${ONYXKEYS.COLLECTION.REPORT}2`]: report2,
* });
*
* @param {String} collectionKey e.g. `ONYXKEYS.COLLECTION.REPORT`
* @param {Object} collection Object collection keyed by individual collection member keys and values
* @returns {Promise}
*/
function mergeCollection(collectionKey, collection) {
if (!isValidMergeCollection(collectionKey, collection)) {
return Promise.resolve();
}

Expand Down Expand Up @@ -1546,22 +1548,36 @@ function update(data) {
}
});

const promises = [];
let clearPromise = Promise.resolve();
const updateQueue = {};
const enqueueSetOperation = (key, value) => {
updateQueue[key] = [{onyxMethod: METHOD.SET, value}];
}
const enqueueMergeOperation = (key, value) => {
const operation = {onyxMethod: METHOD.MERGE, value};
if (!updateQueue[key]) {
updateQueue[key] = [operation];
} else {
updateQueue[key].push(operation);
}
}

let clearPromise = Promise.resolve();
_.each(data, ({onyxMethod, key, value}) => {
switch (onyxMethod) {
case METHOD.SET:
promises.push(() => set(key, value));
enqueueSetOperation(key, value);
break;
case METHOD.MERGE:
promises.push(() => merge(key, value));
case METHOD.MERGE: {
enqueueMergeOperation(key, value);
break;
}
case METHOD.MERGE_COLLECTION:
promises.push(() => mergeCollection(key, value));
if (isValidMergeCollection(key, value)) {
_.each(value, (_value, _key) => enqueueMergeOperation(_key, _value));
}
break;
case METHOD.MULTI_SET:
promises.push(() => multiSet(value));
_.each(value, (_value, _key) => enqueueSetOperation(_key, _value));
break;
case METHOD.CLEAR:
clearPromise = clear();
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -1571,7 +1587,25 @@ function update(data) {
}
});

return clearPromise.then(() => Promise.all(_.map(promises, (p) => p())));
return clearPromise.then(() => Storage.multiGet(_.keys(updateQueue)).then((pairs) => {
const existingSnapshot = _.reduce(pairs, (acc, [key, value]) => {
acc[key] = value;
return acc;
}, {});

const updatedSnapshot = {};
_.each(updateQueue, (operations, key) => {
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
let existingValue = existingSnapshot[key];
if (operations[0].onyxMethod === METHOD.SET) {
existingValue = operations[0].value;
}

const mergeOperations = _.filter(operations, ({onyxMethod}) => onyxMethod === METHOD.MERGE);
paultsimura marked this conversation as resolved.
Show resolved Hide resolved
updatedSnapshot[key] = applyMerge(existingValue, _.map(mergeOperations, ({value}) => value), true);
});

return Storage.multiSet(_.pairs(updatedSnapshot));
}));
}

/**
Expand Down
Loading