Skip to content

Commit

Permalink
return additional wasRemoved flag
Browse files Browse the repository at this point in the history
  • Loading branch information
Christoph Pader committed Dec 19, 2023
1 parent d521b86 commit 113bbcd
Showing 1 changed file with 29 additions and 24 deletions.
53 changes: 29 additions & 24 deletions lib/Onyx.js
Original file line number Diff line number Diff line change
Expand Up @@ -1021,17 +1021,18 @@ function evictStorageAndRetry(error, onyxMethod, ...args) {
*
* @param {String} key
* @param {*} value
* @param {Boolean} hasChanged
* @param {String} method
* @param {Boolean} hasChanged
* @param {Boolean} wasRemoved
* @returns {Promise}
*/
function broadcastUpdate(key, value, hasChanged, method) {
function broadcastUpdate(key, value, method, hasChanged, wasRemoved = false) {
// Logging properties only since values could be sensitive things we don't want to log
Logger.logInfo(`${method}() called for key: ${key}${_.isObject(value) ? ` properties: ${_.keys(value).join(',')}` : ''}`);

// Update subscribers if the cached value has changed, or when the subscriber specifically requires
// all updates regardless of value changes (indicated by initWithStoredValues set to false).
if (hasChanged) {
if (hasChanged && !wasRemoved) {
cache.set(key, value);
} else {
cache.addToAccessedKeys(key);
Expand All @@ -1053,20 +1054,21 @@ function hasPendingMergeForKey(key) {
* Otherwise removes all nested null values in objects and returns the object
* @param {String} key
* @param {Mixed} value
* @returns {Mixed} `null` if the key got removed completely, otherwise the value without null values
* @returns {Mixed} The value without null values and a boolean "wasRemoved", which indicates if the key got removed completely
*/
function removeNullValues(key, value) {
if (_.isNull(value)) {
remove(key);
return null;
return {value, wasRemoved: true};
}

// We can remove all null values in an object by merging it with itself
// utils.fastMerge recursively goes through the object and removes all null values
// Passing two identical objects as source and target to fastMerge will not change it, but only remove the null values
return utils.removeNestedNullValues(value);
return {value: utils.removeNestedNullValues(value), wasRemoved: false};
}

const setOperationPromise = {}
/**
* Write a value to our store with the given key
*
Expand All @@ -1085,28 +1087,33 @@ function set(key, value) {
return Promise.resolve();
}

const valueWithoutNull = removeNullValues(key, value);
// If the value is null, we remove the key from storage
const {value: valueAfterRemoving, wasRemoved} = removeNullValues(key, value);

if (valueWithoutNull === null) {
return Promise.resolve();
}
console.log({queue: mergeQueue[key]})

if (hasPendingMergeForKey(key)) {
console.log("merge ongoing")
Logger.logAlert(`Onyx.set() called after Onyx.merge() for key: ${key}. It is recommended to use set() or merge() not both.`);
}

const hasChanged = cache.hasValueChanged(key, valueWithoutNull);
const hasChanged = cache.hasValueChanged(key, valueAfterRemoving);

// This approach prioritizes fast UI changes without waiting for data to be stored in device storage.
const updatePromise = broadcastUpdate(key, valueWithoutNull, hasChanged, 'set');
const updatePromise = broadcastUpdate(key, valueAfterRemoving, 'set', hasChanged, wasRemoved);

// If the key got removed earlier, we don't have to set the value in storage, so return early instead
if (wasRemoved) {
return updatePromise;
}

// If the value has not changed, calling Storage.setItem() would be redundant and a waste of performance, so return early instead.
if (!hasChanged) {
return updatePromise;
}

return Storage.setItem(key, valueWithoutNull)
.catch((error) => evictStorageAndRetry(error, set, key, valueWithoutNull))
return Storage.setItem(key, valueAfterRemoving)
.catch((error) => evictStorageAndRetry(error, set, key, valueAfterRemoving))
.then(() => updatePromise);
}

Expand All @@ -1116,10 +1123,10 @@ function set(key, value) {
* to an array of key-value pairs in the above format
* @private
* @param {Record} data
* @return {Array} an array of key - value pairs <[key, value]>
* @return {Array} an array of key - value pairs and a boolean which indicates if the key got removed <[key, {value, wasRemoved}]>
*/
function prepareKeyValuePairsForStorage(data) {
return _.map(data, (value, key) => [key, value]);
return _.map(data, (value, key) => [key, removeNullValues(value)]);
}

/**
Expand All @@ -1142,20 +1149,18 @@ function multiSet(data) {

const keyValuePairs = prepareKeyValuePairsForStorage(data);

const updatePromises = _.map(data, (val, key) => {
const updatePromises = _.map(keyValuePairs, ([key, {value, wasRemoved}]) => {
// Update cache and optimistically inform subscribers on the next tick
cache.set(key, val);
return scheduleSubscriberUpdate(key, val);
cache.set(key, value);
return scheduleSubscriberUpdate(key, value);
});

const keyValuePairsWithoutNull = _.filter(
_.map(keyValuePairs, ([key, value]) => {
const valueWithoutNull = removeNullValues(key, value);

if (valueWithoutNull === null) {
_.map(keyValuePairs, ([key, {value, wasRemoved}]) => {
if (wasRemoved) {
return;
}
return [key, valueWithoutNull];
return [key, value];
}),
Boolean,
);
Expand Down

0 comments on commit 113bbcd

Please sign in to comment.