-
Notifications
You must be signed in to change notification settings - Fork 95
File handling POC #102
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
Merged
thienlnam
merged 48 commits into
Expensify:master
from
kidroca:kidroca/file-handling-poc
Dec 14, 2021
Merged
File handling POC #102
Changes from all commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
693684a
Extract ProviderInterface
kidroca 535cf48
Add expo-file-system as peerDependency
kidroca c8c8a61
chore: add expo-file-system as dev dependency for intellisense
kidroca 95df46d
Create storage/fs.native.js
kidroca d77e1c5
Create storage/fs.js for web and desktop
kidroca b53c79a
Add `localforage` as peer dependency
kidroca e45b66a
Create LocalForage provider
kidroca 55afdb2
Create AsyncStorage provider
kidroca 0513625
Move NativeFileHandler to providers
kidroca 628c56d
Remove JSON parse/stringify handling from Onyx
kidroca 42eab2a
Update NativeFileHandler
kidroca 355fa19
Update Storage type definitions
kidroca 661990a
Remove fs.js - this is completely covered by localForage
kidroca 019ea8c
Update package with unimodules
kidroca ef48097
Update stringification
kidroca 86d8ad9
NativeStorage implementation handling File items
kidroca 20dd112
Simplify Native file save handling
kidroca 4448684
Simplify providers, move away from class based implementations
kidroca c4441b5
remove unused methods from FileHandler
kidroca 449d802
rename "storeFileLocally" to "prepareFile"
kidroca ec22e2c
Update prepareFile so it can be called sync
kidroca 577091f
Native Storage stats
kidroca dcce126
Create folder for the local path
kidroca 2968c30
Feat: synchronize IndexDB updates across different tabs
kidroca 0bffc81
Update tests after changes
kidroca 449e4ba
Update docs
kidroca b6ad244
Use a hidden folder `.onyx_files`
kidroca cc01240
Merge branch 'master' into kidroca/file-handling-poc
kidroca dac932e
Delete storage typings index
kidroca 81af8f7
Address part of the requested changes (comments and clarification cha…
kidroca 6f4abd3
Get rid of empty `synchronizeInstances` method in index.native.js
kidroca c6a5d69
LocalForage Simplify multiGet implementation
kidroca f409c68
LocalForage apply multiMerge suggested changes, use underscore
kidroca 35c2281
NativeFIleHandler: Apply review suggestion
kidroca cb7a8c0
Document provider methods
kidroca 273080f
NativeFileHandler extract bytesToMB, use underscore
kidroca 6429c70
Remove empty `prepareFile` and add a check in Onyx
kidroca 029a7a9
Replace index.native with Platform.select
kidroca abf0339
Update to expo-file-system 13 which does not require unimodules
kidroca 41bed4d
Remove accidental JSON.stringify resulted from merge
kidroca fe0646c
Remove NativeFileHandler, prepareFile and the expo-file-system package
kidroca 45ddac4
WebStorage make keepInstancesSync handle removeItem and clear
kidroca 4c941f8
WebStorage: wait for all remove calls to finish and then resolve clear
kidroca c738e7e
tab-sync cache fix - update cache as well as raise keyChanged
kidroca 9b02f63
Move `storage/__mocks__` to the root level mocks
kidroca 3d5a675
Small code style cleanup
kidroca 3c8aa3f
package: remove localforage from dev dependencies
kidroca 5e95175
docs: fix typo
kidroca File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 '../../../lib/storage/WebStorage'; | ||
|
|
||
| export default WebStorage; |
This file contains hidden or 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 hidden or 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 Storage from './providers/AsyncStorage'; | ||
|
|
||
| export default Storage; |
This file contains hidden or 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,50 @@ | ||
| import _ from 'underscore'; | ||
| import Storage from './providers/LocalForage'; | ||
|
|
||
| const SYNC_ONYX = 'SYNC_ONYX'; | ||
|
|
||
| /** | ||
| * Raise an event thorough `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); | ||
| } | ||
|
|
||
| const webStorage = { | ||
| ...Storage, | ||
|
|
||
| /** | ||
| * Storage synchronization mechanism keeping all opened tabs in sync | ||
| * @param {function(key: String, data: *)} onStorageKeyChanged | ||
| */ | ||
| keepInstancesSync(onStorageKeyChanged) { | ||
| // Override set, remove and clear to raise storage events that we intercept in other tabs | ||
| this.setItem = (key, value) => Storage.setItem(key, value) | ||
| .then(() => raiseStorageSyncEvent(key)); | ||
|
|
||
| this.removeItem = key => Storage.removeItem(key) | ||
| .then(() => raiseStorageSyncEvent(key)); | ||
|
|
||
| // If we just call Storage.clear other tabs will have no idea which keys were available previously | ||
| // so that they can call keysChanged for them. That's why we iterate and remove keys one by one | ||
| this.clear = () => Storage.getAllKeys() | ||
| .then(keys => _.map(keys, key => this.removeItem(key))) | ||
| .then(tasks => Promise.all(tasks)); | ||
|
|
||
| // 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; | ||
| Storage.getItem(onyxKey) | ||
| .then(value => onStorageKeyChanged(onyxKey, value)); | ||
| }); | ||
| }, | ||
| }; | ||
|
|
||
| export default webStorage; |
This file contains hidden or 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,8 @@ | ||
| import {Platform} from 'react-native'; | ||
|
|
||
| const Storage = Platform.select({ | ||
| default: () => require('./WebStorage').default, | ||
| native: () => require('./NativeStorage').default, | ||
| })(); | ||
|
|
||
| export default Storage; |
This file contains hidden or 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,97 @@ | ||
| /** | ||
| * The AsyncStorage provider stores everything in a key/value store by | ||
| * converting the value to a JSON string | ||
| */ | ||
|
|
||
| import _ from 'underscore'; | ||
| import AsyncStorage from '@react-native-async-storage/async-storage'; | ||
|
|
||
| /** | ||
| * Values other than null and undefined should be stringified before | ||
| * they are saved in storage | ||
| * @param {*} value | ||
| * @returns {string|null} | ||
| */ | ||
| function prepareValueForStorage(value) { | ||
| if (_.isUndefined(value) || _.isNull(value)) { | ||
| return value; | ||
| } | ||
|
|
||
| return JSON.stringify(value); | ||
| } | ||
|
|
||
| const provider = { | ||
| /** | ||
| * Get the value of a given key or return `null` if it's not available in storage | ||
| * @param {String} key | ||
| * @return {Promise<*>} | ||
| */ | ||
| getItem(key) { | ||
| return AsyncStorage.getItem(key) | ||
| .then((value) => { | ||
| const parsed = value && JSON.parse(value); | ||
| return parsed; | ||
| }); | ||
| }, | ||
|
|
||
| /** | ||
| * Get multiple key-value pairs for the give array of keys in a batch | ||
| * @param {String[]} keys | ||
| * @return {Promise<Array<[key, value]>>} | ||
| */ | ||
| multiGet(keys) { | ||
| return AsyncStorage.multiGet(keys) | ||
| .then(pairs => _.map(pairs, ([key, value]) => [key, value && JSON.parse(value)])); | ||
| }, | ||
|
|
||
| /** | ||
| * 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) { | ||
| return AsyncStorage.setItem(key, prepareValueForStorage(value)); | ||
| }, | ||
|
|
||
| /** | ||
| * Stores multiple key-value pairs in a batch | ||
| * @param {Array<[key, value]>} pairs | ||
| * @return {Promise<void>} | ||
| */ | ||
| multiSet(pairs) { | ||
| const stringPairs = _.map(pairs, ([key, value]) => [key, prepareValueForStorage(value)]); | ||
| return AsyncStorage.multiSet(stringPairs); | ||
| }, | ||
|
|
||
| /** | ||
| * Multiple merging of existing and new values in a batch | ||
| * @param {Array<[key, value]>} pairs | ||
| * @return {Promise<void>} | ||
| */ | ||
| multiMerge(pairs) { | ||
| const stringPairs = _.map(pairs, ([key, value]) => [key, prepareValueForStorage(value)]); | ||
| return AsyncStorage.multiMerge(stringPairs); | ||
| }, | ||
|
|
||
| /** | ||
| * Returns all keys available in storage | ||
| * @returns {Promise<String[]>} | ||
| */ | ||
| getAllKeys: AsyncStorage.getAllKeys, | ||
|
|
||
| /** | ||
| * Remove given key and it's value from storage | ||
| * @param {String} key | ||
| * @returns {Promise<void>} | ||
| */ | ||
| removeItem: AsyncStorage.removeItem, | ||
|
|
||
| /** | ||
| * Clear absolutely everything from storage | ||
| * @returns {Promise<void>} | ||
| */ | ||
| clear: AsyncStorage.clear, | ||
| }; | ||
|
|
||
| export default provider; |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.