From 937171c4de12918da22fa00060f15a924008f5d3 Mon Sep 17 00:00:00 2001 From: Mark Vayngrib Date: Wed, 18 Jan 2017 16:51:00 -0500 Subject: [PATCH] add AsyncStorage.setBackend to support custom backends --- Libraries/Storage/AsyncStorage.js | 274 +++++++++++++------------ Libraries/Storage/AsyncStorageTypes.js | 13 ++ 2 files changed, 156 insertions(+), 131 deletions(-) create mode 100644 Libraries/Storage/AsyncStorageTypes.js diff --git a/Libraries/Storage/AsyncStorage.js b/Libraries/Storage/AsyncStorage.js index b8b6820276f6..4fc6ac6f0806 100644 --- a/Libraries/Storage/AsyncStorage.js +++ b/Libraries/Storage/AsyncStorage.js @@ -13,6 +13,8 @@ */ 'use strict'; +import type { AsyncStorageBackend } from './AsyncStorageTypes'; + var NativeModules = require('NativeModules'); var RCTAsyncSQLiteStorage = NativeModules.AsyncSQLiteDBStorage; var RCTAsyncRocksDBStorage = NativeModules.AsyncRocksDBStorage; @@ -144,59 +146,6 @@ var AsyncStorage = { }); }, - /** - * Merges an existing `key` value with an input value, assuming both values - * are stringified JSON. Returns a `Promise` object. - * - * **NOTE:** This is not supported by all native implementations. - * - * @param key Key of the item to modify. - * @param value New value to merge for the `key`. - * @param callback Function that will be called with any error. - * @returns A `Promise` object. - * - * @example Example - * let UID123_object = { - * name: 'Chris', - * age: 30, - * traits: {hair: 'brown', eyes: 'brown'}, - * }; - * // You only need to define what will be added or updated - * let UID123_delta = { - * age: 31, - * traits: {eyes: 'blue', shoe_size: 10} - * }; - * - * AsyncStorage.setItem('UID123', JSON.stringify(UID123_object), () => { - * AsyncStorage.mergeItem('UID123', JSON.stringify(UID123_delta), () => { - * AsyncStorage.getItem('UID123', (err, result) => { - * console.log(result); - * }); - * }); - * }); - * - * // Console log result: - * // => {'name':'Chris','age':31,'traits': - * // {'shoe_size':10,'hair':'brown','eyes':'blue'}} - */ - mergeItem: function( - key: string, - value: string, - callback?: ?(error: ?Error) => void - ): Promise { - return new Promise((resolve, reject) => { - RCTAsyncStorage.multiMerge([[key,value]], function(errors) { - var errs = convertErrors(errors); - callback && callback(errs && errs[0]); - if (errs) { - reject(errs[0]); - } else { - resolve(null); - } - }); - }); - }, - /** * Erases *all* `AsyncStorage` for all clients, libraries, etc. You probably * don't want to call this; use `removeItem` or `multiRemove` to clear only @@ -406,86 +355,149 @@ var AsyncStorage = { }); }, - /** - * Batch operation to merge in existing and new values for a given set of - * keys. This assumes that the values are stringified JSON. Returns a - * `Promise` object. - * - * **NOTE**: This is not supported by all native implementations. - * - * @param keyValuePairs Array of key-value array for the items to merge. - * @param callback Function that will be called with an array of any - * key-specific errors found. - * @returns A `Promise` object. - * - * @example Example - * // first user, initial values - * let UID234_object = { - * name: 'Chris', - * age: 30, - * traits: {hair: 'brown', eyes: 'brown'}, - * }; - * - * // first user, delta values - * let UID234_delta = { - * age: 31, - * traits: {eyes: 'blue', shoe_size: 10}, - * }; - * - * // second user, initial values - * let UID345_object = { - * name: 'Marge', - * age: 25, - * traits: {hair: 'blonde', eyes: 'blue'}, - * }; - * - * // second user, delta values - * let UID345_delta = { - * age: 26, - * traits: {eyes: 'green', shoe_size: 6}, - * }; - * - * let multi_set_pairs = [['UID234', JSON.stringify(UID234_object)], ['UID345', JSON.stringify(UID345_object)]] - * let multi_merge_pairs = [['UID234', JSON.stringify(UID234_delta)], ['UID345', JSON.stringify(UID345_delta)]] - * - * AsyncStorage.multiSet(multi_set_pairs, (err) => { - * AsyncStorage.multiMerge(multi_merge_pairs, (err) => { - * AsyncStorage.multiGet(['UID234','UID345'], (err, stores) => { - * stores.map( (result, i, store) => { - * let key = store[i][0]; - * let val = store[i][1]; - * console.log(key, val); - * }); - * }); - * }); - * }); - * - * // Console log results: - * // => UID234 {"name":"Chris","age":31,"traits":{"shoe_size":10,"hair":"brown","eyes":"blue"}} - * // => UID345 {"name":"Marge","age":26,"traits":{"shoe_size":6,"hair":"blonde","eyes":"green"}} - */ - multiMerge: function( - keyValuePairs: Array>, - callback?: ?(errors: ?Array) => void - ): Promise { - return new Promise((resolve, reject) => { - RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) { - var error = convertErrors(errors); - callback && callback(error); - if (error) { - reject(error); - } else { - resolve(null); - } - }); - }); - }, + setBackend: function ( + backend: AsyncStorageBackend + ) { + RCTAsyncStorage = backend; + // Not all native implementations support merge. + if (backend.multiMerge) { + AsyncStorage.mergeItem = mergeItem; + AsyncStorage.multiMerge = multiMerge; + } else { + delete AsyncStorage.mergeItem; + delete AsyncStorage.multiMerge; + } + } }; -// Not all native implementations support merge. -if (!RCTAsyncStorage.multiMerge) { - delete AsyncStorage.mergeItem; - delete AsyncStorage.multiMerge; +AsyncStorage.setBackend(RCTAsyncStorage); + +/** + * Batch operation to merge in existing and new values for a given set of + * keys. This assumes that the values are stringified JSON. Returns a + * `Promise` object. + * + * **NOTE**: This is not supported by all native implementations. + * + * @param keyValuePairs Array of key-value array for the items to merge. + * @param callback Function that will be called with an array of any + * key-specific errors found. + * @returns A `Promise` object. + * + * @example Example + * // first user, initial values + * let UID234_object = { + * name: 'Chris', + * age: 30, + * traits: {hair: 'brown', eyes: 'brown'}, + * }; + * + * // first user, delta values + * let UID234_delta = { + * age: 31, + * traits: {eyes: 'blue', shoe_size: 10}, + * }; + * + * // second user, initial values + * let UID345_object = { + * name: 'Marge', + * age: 25, + * traits: {hair: 'blonde', eyes: 'blue'}, + * }; + * + * // second user, delta values + * let UID345_delta = { + * age: 26, + * traits: {eyes: 'green', shoe_size: 6}, + * }; + * + * let multi_set_pairs = [['UID234', JSON.stringify(UID234_object)], ['UID345', JSON.stringify(UID345_object)]] + * let multi_merge_pairs = [['UID234', JSON.stringify(UID234_delta)], ['UID345', JSON.stringify(UID345_delta)]] + * + * AsyncStorage.multiSet(multi_set_pairs, (err) => { + * AsyncStorage.multiMerge(multi_merge_pairs, (err) => { + * AsyncStorage.multiGet(['UID234','UID345'], (err, stores) => { + * stores.map( (result, i, store) => { + * let key = store[i][0]; + * let val = store[i][1]; + * console.log(key, val); + * }); + * }); + * }); + * }); + * + * // Console log results: + * // => UID234 {"name":"Chris","age":31,"traits":{"shoe_size":10,"hair":"brown","eyes":"blue"}} + * // => UID345 {"name":"Marge","age":26,"traits":{"shoe_size":6,"hair":"blonde","eyes":"green"}} + */ +function multiMerge ( + keyValuePairs: Array>, + callback?: ?(errors: ?Array) => void +): Promise { + return new Promise((resolve, reject) => { + RCTAsyncStorage.multiMerge(keyValuePairs, function(errors) { + var error = convertErrors(errors); + callback && callback(error); + if (error) { + reject(error); + } else { + resolve(null); + } + }); + }); +} + +/** + * Merges an existing `key` value with an input value, assuming both values + * are stringified JSON. Returns a `Promise` object. + * + * **NOTE:** This is not supported by all native implementations. + * + * @param key Key of the item to modify. + * @param value New value to merge for the `key`. + * @param callback Function that will be called with any error. + * @returns A `Promise` object. + * + * @example Example + * let UID123_object = { + * name: 'Chris', + * age: 30, + * traits: {hair: 'brown', eyes: 'brown'}, + * }; + * // You only need to define what will be added or updated + * let UID123_delta = { + * age: 31, + * traits: {eyes: 'blue', shoe_size: 10} + * }; + * + * AsyncStorage.setItem('UID123', JSON.stringify(UID123_object), () => { + * AsyncStorage.mergeItem('UID123', JSON.stringify(UID123_delta), () => { + * AsyncStorage.getItem('UID123', (err, result) => { + * console.log(result); + * }); + * }); + * }); + * + * // Console log result: + * // => {'name':'Chris','age':31,'traits': + * // {'shoe_size':10,'hair':'brown','eyes':'blue'}} + */ +function mergeItem( + key: string, + value: string, + callback?: ?(error: ?Error) => void +): Promise { + return new Promise((resolve, reject) => { + RCTAsyncStorage.multiMerge([[key,value]], function(errors) { + var errs = convertErrors(errors); + callback && callback(errs && errs[0]); + if (errs) { + reject(errs[0]); + } else { + resolve(null); + } + }); + }); } function convertErrors(errs) { diff --git a/Libraries/Storage/AsyncStorageTypes.js b/Libraries/Storage/AsyncStorageTypes.js new file mode 100644 index 000000000000..7d1cb931c19b --- /dev/null +++ b/Libraries/Storage/AsyncStorageTypes.js @@ -0,0 +1,13 @@ +/** + * @flow + */ +'use strict'; + +export type AsyncStorageBackend = { + clear: Function, + getAllKeys: Function, + multiGet: Function, + multiSet: Function, + multiRemove: Function, + multiMerge?: Function +};