-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactor: unify storage/providers (for further InMemory storage integ…
…ration) [1/2]
- Loading branch information
1 parent
13936ae
commit 29cd54c
Showing
16 changed files
with
295 additions
and
125 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
/** | ||
* This is used to keep multiple browser tabs in sync, therefore only needed on web | ||
* On native platforms, we omit this syncing logic by setting this to null. | ||
*/ | ||
const InstanceSync = null; | ||
|
||
export default InstanceSync; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/* eslint-disable no-invalid-this */ | ||
/** | ||
* The InstancesSync object provides data-changed events like the ones that exist | ||
* when using LocalStorage APIs in the browser. These events are great because multiple tabs can listen for when | ||
* data changes and then stay up-to-date with everything happening in Onyx. | ||
*/ | ||
import _ from 'underscore'; | ||
|
||
const SYNC_ONYX = 'SYNC_ONYX'; | ||
|
||
/** | ||
* Raise an event through `localStorage` to let other tabs know a value changed | ||
* @param {String} onyxKey | ||
*/ | ||
function raiseStorageSyncEvent(onyxKey) { | ||
global.localStorage.setItem(SYNC_ONYX, onyxKey); | ||
global.localStorage.removeItem(SYNC_ONYX, onyxKey); | ||
} | ||
|
||
function raiseStorageSyncManyKeysEvent(onyxKeys) { | ||
_.each(onyxKeys, (onyxKey) => { | ||
raiseStorageSyncEvent(onyxKey); | ||
}); | ||
} | ||
|
||
const InstanceSync = { | ||
/** | ||
* @param {Function} onStorageKeyChanged Storage synchronization mechanism keeping all opened tabs in sync | ||
*/ | ||
init: (onStorageKeyChanged) => { | ||
// This listener will only be triggered by events coming from other tabs | ||
global.addEventListener('storage', (event) => { | ||
// Ignore events that don't originate from the SYNC_ONYX logic | ||
if (event.key !== SYNC_ONYX || !event.newValue) { | ||
return; | ||
} | ||
|
||
const onyxKey = event.newValue; | ||
this.getItem(onyxKey).then((value) => onStorageKeyChanged(onyxKey, value)); | ||
}); | ||
}, | ||
setItem: raiseStorageSyncEvent, | ||
removeItem: raiseStorageSyncEvent, | ||
removeItems: raiseStorageSyncManyKeysEvent, | ||
mergeItem: raiseStorageSyncEvent, | ||
clear: (clearImplementation) => { | ||
let allKeys; | ||
|
||
// The keys must be retrieved before storage is cleared or else the list of keys would be empty | ||
return this.getAllKeys() | ||
.then((keys) => { | ||
allKeys = keys; | ||
}) | ||
.then(() => clearImplementation()) | ||
.then(() => { | ||
// Now that storage is cleared, the storage sync event can happen which is a more atomic action | ||
// for other browser tabs | ||
raiseStorageSyncManyKeysEvent(allKeys) | ||
}); | ||
}, | ||
}; | ||
|
||
export default InstanceSync; |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,158 @@ | ||
import WebStorage from './WebStorage'; | ||
import PlatformStorage from './platforms'; | ||
import InstanceSync from './InstanceSync'; | ||
|
||
export default WebStorage; | ||
const provider = PlatformStorage; | ||
let shouldKeepInstancesSync = false; | ||
|
||
|
||
const Storage = { | ||
/** | ||
* Returns the storage provider currently in use | ||
* @returns {Object} the current storage provider | ||
*/ | ||
getStorageProvider() { | ||
return provider; | ||
}, | ||
|
||
/** | ||
* Initializes all providers in the list of storage providers | ||
* and enables fallback providers if necessary | ||
*/ | ||
init() { | ||
provider.init(); | ||
}, | ||
|
||
/** | ||
* Get the value of a given key or return `null` if it's not available in memory | ||
* @param {String} key | ||
* @return {Promise<*>} | ||
*/ | ||
getItem: (key) => provider.getItem(key), | ||
|
||
/** | ||
* Get multiple key-value pairs for the give array of keys in a batch. | ||
* @param {String[]} keys | ||
* @return {Promise<Array<[key, value]>>} | ||
*/ | ||
multiGet: (keys) => provider.multiGet(keys), | ||
|
||
/** | ||
* Sets the value for a given key. The only requirement is that the value should be serializable to JSON string | ||
* @param {String} key | ||
* @param {*} value | ||
* @return {Promise<void>} | ||
*/ | ||
setItem: (key, value) => { | ||
const promise = provider.setItem(key, value); | ||
|
||
if (shouldKeepInstancesSync) { | ||
return promise.then(() => InstanceSync.setItem(key)); | ||
} | ||
|
||
return promise; | ||
}, | ||
|
||
/** | ||
* Stores multiple key-value pairs in a batch | ||
* @param {Array<[key, value]>} pairs | ||
* @return {Promise<void>} | ||
*/ | ||
multiSet: (pairs) => provider.multiSet(pairs), | ||
|
||
/** | ||
* Merging an existing value with a new one | ||
* @param {String} key | ||
* @param {*} changes - the delta for a specific key | ||
* @param {any} modifiedData - the pre-merged data from `Onyx.applyMerge` | ||
* @return {Promise<void>} | ||
*/ | ||
mergeItem: (key, changes, modifiedData) => { | ||
const promise = provider.mergeItem(key, changes, modifiedData); | ||
|
||
if (shouldKeepInstancesSync) { | ||
return promise.then(() => InstanceSync.mergeItem(key)); | ||
} | ||
|
||
return promise; | ||
}, | ||
|
||
/** | ||
* Multiple merging of existing and new values in a batch | ||
* @param {Array<[key, value]>} pairs | ||
* This function also removes all nested null values from an object. | ||
* @return {Promise<void>} | ||
*/ | ||
multiMerge: (pairs) => provider.multiMerge(pairs), | ||
|
||
/** | ||
* Remove given key and it's value from memory | ||
* @param {String} key | ||
* @returns {Promise<void>} | ||
*/ | ||
removeItem: (key) => { | ||
const promise = provider.removeItem(key); | ||
|
||
if (shouldKeepInstancesSync) { | ||
return promise.then(() => InstanceSync.removeItem(key)); | ||
} | ||
|
||
return promise; | ||
}, | ||
|
||
/** | ||
* Remove given keys and their values from memory | ||
* | ||
* @param {Array} keys | ||
* @returns {Promise} | ||
*/ | ||
removeItems: (keys) => { | ||
const promise = provider.removeItems(keys); | ||
|
||
if (shouldKeepInstancesSync) { | ||
return promise.then(() => InstanceSync.removeItems(keys)); | ||
} | ||
|
||
return promise; | ||
}, | ||
|
||
/** | ||
* Clear everything from memory | ||
* @returns {Promise<void>} | ||
*/ | ||
clear: () => { | ||
if (shouldKeepInstancesSync) { | ||
return InstanceSync.clear(() => provider.clear()); | ||
} | ||
|
||
return provider.clear(); | ||
}, | ||
|
||
// This is a noop for now in order to keep clients from crashing see https://github.com/Expensify/Expensify/issues/312438 | ||
setMemoryOnlyKeys: () => provider.setMemoryOnlyKeys(), | ||
|
||
/** | ||
* Returns all keys available in memory | ||
* @returns {Promise<String[]>} | ||
*/ | ||
getAllKeys: () => provider.getAllKeys(), | ||
|
||
/** | ||
* Gets the total bytes of the store. | ||
* `bytesRemaining` will always be `Number.POSITIVE_INFINITY` since we don't have a hard limit on memory. | ||
* @returns {Promise<number>} | ||
*/ | ||
getDatabaseSize: () => provider.getDatabaseSize(), | ||
|
||
/** | ||
* @param {Function} onStorageKeyChanged Storage synchronization mechanism keeping all opened tabs in sync (web only) | ||
*/ | ||
keepInstancesSync(onStorageKeyChanged) { | ||
// If InstanceSync is null, it means we're on a native platform and we don't need to keep instances in sync | ||
if (InstanceSync == null) return; | ||
|
||
shouldKeepInstancesSync = true; | ||
InstanceSync.init(onStorageKeyChanged); | ||
}, | ||
}; | ||
|
||
export default Storage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import SQLiteStorage from '../providers/SQLiteProvider'; | ||
|
||
export default SQLiteStorage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import IDBKeyValProvider from '../providers/IDBKeyValProvider'; | ||
|
||
export default IDBKeyValProvider; |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import WebStorage from './WebStorage'; | ||
|
||
export default WebStorage; |
Oops, something went wrong.