Skip to content

Commit 72d037e

Browse files
committed
rollback js code
1 parent 3117a91 commit 72d037e

File tree

8 files changed

+845
-4
lines changed

8 files changed

+845
-4
lines changed
Lines changed: 356 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,356 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
import {
9+
checkValidArgs,
10+
checkValidInput,
11+
convertError,
12+
convertErrors,
13+
} from "./helpers";
14+
import RCTAsyncStorage from "./RCTAsyncStorage";
15+
import type {
16+
AsyncStorageStatic,
17+
ErrorLike,
18+
KeyValuePair,
19+
MultiRequest,
20+
} from "./types";
21+
22+
if (!RCTAsyncStorage) {
23+
throw new Error(`[@RNC/AsyncStorage]: NativeModule: AsyncStorage is null.
24+
25+
To fix this issue try these steps:
26+
27+
• Uninstall, rebuild and restart the app.
28+
29+
• Run the packager with \`--reset-cache\` flag.
30+
31+
• If you are using CocoaPods on iOS, run \`pod install\` in the \`ios\` directory, then rebuild and re-run the app.
32+
33+
• Make sure your project's \`package.json\` depends on \`@react-native-async-storage/async-storage\`, even if you only depend on it indirectly through other dependencies. CLI only autolinks native modules found in your \`package.json\`.
34+
35+
• If this happens while testing with Jest, check out how to integrate AsyncStorage here: https://react-native-async-storage.github.io/async-storage/docs/advanced/jest
36+
37+
If none of these fix the issue, please open an issue on the GitHub repository: https://github.com/react-native-async-storage/async-storage/issues
38+
`);
39+
}
40+
41+
/**
42+
* `AsyncStorage` is a simple, unencrypted, asynchronous, persistent, key-value
43+
* storage system that is global to the app. It should be used instead of
44+
* LocalStorage.
45+
*
46+
* See https://react-native-async-storage.github.io/async-storage/docs/api
47+
*/
48+
const AsyncStorage = ((): AsyncStorageStatic => {
49+
let _getRequests: MultiRequest[] = [];
50+
let _getKeys: string[] = [];
51+
let _immediate: ReturnType<typeof setImmediate> | null = null;
52+
53+
return {
54+
/**
55+
* Fetches an item for a `key` and invokes a callback upon completion.
56+
*
57+
* See https://react-native-async-storage.github.io/async-storage/docs/api#getitem
58+
*/
59+
getItem: (key, callback) => {
60+
return new Promise((resolve, reject) => {
61+
checkValidInput(key);
62+
RCTAsyncStorage.multiGet(
63+
[key],
64+
(errors?: ErrorLike[], result?: string[][]) => {
65+
// Unpack result to get value from [[key,value]]
66+
const value = result?.[0]?.[1] ? result[0][1] : null;
67+
const errs = convertErrors(errors);
68+
callback?.(errs?.[0], value);
69+
if (errs) {
70+
reject(errs[0]);
71+
} else {
72+
resolve(value);
73+
}
74+
}
75+
);
76+
});
77+
},
78+
79+
/**
80+
* Sets the value for a `key` and invokes a callback upon completion.
81+
*
82+
* See https://react-native-async-storage.github.io/async-storage/docs/api#setitem
83+
*/
84+
setItem: (key, value, callback) => {
85+
return new Promise((resolve, reject) => {
86+
checkValidInput(key, value);
87+
RCTAsyncStorage.multiSet([[key, value]], (errors?: ErrorLike[]) => {
88+
const errs = convertErrors(errors);
89+
callback?.(errs?.[0]);
90+
if (errs) {
91+
reject(errs[0]);
92+
} else {
93+
resolve();
94+
}
95+
});
96+
});
97+
},
98+
99+
/**
100+
* Removes an item for a `key` and invokes a callback upon completion.
101+
*
102+
* See https://react-native-async-storage.github.io/async-storage/docs/api#removeitem
103+
*/
104+
removeItem: (key, callback) => {
105+
return new Promise((resolve, reject) => {
106+
checkValidInput(key);
107+
RCTAsyncStorage.multiRemove([key], (errors?: ErrorLike[]) => {
108+
const errs = convertErrors(errors);
109+
callback?.(errs?.[0]);
110+
if (errs) {
111+
reject(errs[0]);
112+
} else {
113+
resolve();
114+
}
115+
});
116+
});
117+
},
118+
119+
/**
120+
* Merges an existing `key` value with an input value, assuming both values
121+
* are stringified JSON.
122+
*
123+
* See https://react-native-async-storage.github.io/async-storage/docs/api#mergeitem
124+
*/
125+
mergeItem: (key, value, callback) => {
126+
return new Promise((resolve, reject) => {
127+
checkValidInput(key, value);
128+
RCTAsyncStorage.multiMerge([[key, value]], (errors?: ErrorLike[]) => {
129+
const errs = convertErrors(errors);
130+
callback?.(errs?.[0]);
131+
if (errs) {
132+
reject(errs[0]);
133+
} else {
134+
resolve();
135+
}
136+
});
137+
});
138+
},
139+
140+
/**
141+
* Erases *all* `AsyncStorage` for all clients, libraries, etc. You probably
142+
* don't want to call this; use `removeItem` or `multiRemove` to clear only
143+
* your app's keys.
144+
*
145+
* See https://react-native-async-storage.github.io/async-storage/docs/api#clear
146+
*/
147+
clear: (callback) => {
148+
return new Promise((resolve, reject) => {
149+
RCTAsyncStorage.clear((error?: ErrorLike) => {
150+
const err = convertError(error);
151+
callback?.(err);
152+
if (err) {
153+
reject(err);
154+
} else {
155+
resolve();
156+
}
157+
});
158+
});
159+
},
160+
161+
/**
162+
* Gets *all* keys known to your app; for all callers, libraries, etc.
163+
*
164+
* See https://react-native-async-storage.github.io/async-storage/docs/api#getallkeys
165+
*/
166+
getAllKeys: (callback) => {
167+
return new Promise((resolve, reject) => {
168+
RCTAsyncStorage.getAllKeys((error?: ErrorLike, keys?: string[]) => {
169+
const err = convertError(error);
170+
callback?.(err, keys);
171+
if (keys) {
172+
resolve(keys);
173+
} else {
174+
reject(err);
175+
}
176+
});
177+
});
178+
},
179+
180+
/**
181+
* The following batched functions are useful for executing a lot of
182+
* operations at once, allowing for native optimizations and provide the
183+
* convenience of a single callback after all operations are complete.
184+
*
185+
* These functions return arrays of errors, potentially one for every key.
186+
* For key-specific errors, the Error object will have a key property to
187+
* indicate which key caused the error.
188+
*/
189+
190+
/**
191+
* Flushes any pending requests using a single batch call to get the data.
192+
*
193+
* See https://react-native-async-storage.github.io/async-storage/docs/api#flushgetrequests
194+
* */
195+
flushGetRequests: () => {
196+
const getRequests = _getRequests;
197+
const getKeys = _getKeys;
198+
199+
_getRequests = [];
200+
_getKeys = [];
201+
202+
RCTAsyncStorage.multiGet(
203+
getKeys,
204+
(errors?: ErrorLike[], result?: string[][]) => {
205+
// Even though the runtime complexity of this is theoretically worse vs if we used a map,
206+
// it's much, much faster in practice for the data sets we deal with (we avoid
207+
// allocating result pair arrays). This was heavily benchmarked.
208+
//
209+
// Is there a way to avoid using the map but fix the bug in this breaking test?
210+
// https://github.com/facebook/react-native/commit/8dd8ad76579d7feef34c014d387bf02065692264
211+
const map: Record<string, string> = {};
212+
result?.forEach(([key, value]) => {
213+
map[key] = value;
214+
return value;
215+
});
216+
const reqLength = getRequests.length;
217+
218+
/**
219+
* As mentioned few lines above, this method could be called with the array of potential error,
220+
* in case of anything goes wrong. The problem is, if any of the batched calls fails
221+
* the rest of them would fail too, but the error would be consumed by just one. The rest
222+
* would simply return `undefined` as their result, rendering false negatives.
223+
*
224+
* In order to avoid this situation, in case of any call failing,
225+
* the rest of them will be rejected as well (with the same error).
226+
*/
227+
const errorList = convertErrors(errors);
228+
const error = errorList?.length ? errorList[0] : null;
229+
230+
for (let i = 0; i < reqLength; i++) {
231+
const request = getRequests[i];
232+
if (error) {
233+
request.callback?.(errorList);
234+
request.reject?.(error);
235+
continue;
236+
}
237+
const requestResult = request.keys.map<KeyValuePair>((key) => [
238+
key,
239+
map[key],
240+
]);
241+
request.callback?.(null, requestResult);
242+
request.resolve?.(requestResult);
243+
}
244+
}
245+
);
246+
},
247+
248+
/**
249+
* This allows you to batch the fetching of items given an array of `key`
250+
* inputs. Your callback will be invoked with an array of corresponding
251+
* key-value pairs found.
252+
*
253+
* See https://react-native-async-storage.github.io/async-storage/docs/api#multiget
254+
*/
255+
multiGet: (keys, callback) => {
256+
if (!_immediate) {
257+
_immediate = setImmediate(() => {
258+
_immediate = null;
259+
AsyncStorage.flushGetRequests();
260+
});
261+
}
262+
263+
const getRequest: MultiRequest = {
264+
keys: keys,
265+
callback: callback,
266+
// do we need this?
267+
keyIndex: _getKeys.length,
268+
};
269+
270+
const promiseResult = new Promise<readonly KeyValuePair[]>(
271+
(resolve, reject) => {
272+
getRequest.resolve = resolve;
273+
getRequest.reject = reject;
274+
}
275+
);
276+
277+
_getRequests.push(getRequest);
278+
// avoid fetching duplicates
279+
keys.forEach((key) => {
280+
if (_getKeys.indexOf(key) === -1) {
281+
_getKeys.push(key);
282+
}
283+
});
284+
285+
return promiseResult;
286+
},
287+
288+
/**
289+
* Use this as a batch operation for storing multiple key-value pairs. When
290+
* the operation completes you'll get a single callback with any errors.
291+
*
292+
* See https://react-native-async-storage.github.io/async-storage/docs/api#multiset
293+
*/
294+
multiSet: (keyValuePairs, callback) => {
295+
checkValidArgs(keyValuePairs, callback);
296+
return new Promise((resolve, reject) => {
297+
keyValuePairs.forEach(([key, value]) => {
298+
checkValidInput(key, value);
299+
});
300+
301+
RCTAsyncStorage.multiSet(keyValuePairs, (errors?: ErrorLike[]) => {
302+
const error = convertErrors(errors);
303+
callback?.(error);
304+
if (error) {
305+
reject(error);
306+
} else {
307+
resolve();
308+
}
309+
});
310+
});
311+
},
312+
313+
/**
314+
* Call this to batch the deletion of all keys in the `keys` array.
315+
*
316+
* See https://react-native-async-storage.github.io/async-storage/docs/api#multiremove
317+
*/
318+
multiRemove: (keys, callback) => {
319+
return new Promise((resolve, reject) => {
320+
keys.forEach((key) => checkValidInput(key));
321+
322+
RCTAsyncStorage.multiRemove(keys, (errors?: ErrorLike[]) => {
323+
const error = convertErrors(errors);
324+
callback?.(error);
325+
if (error) {
326+
reject(error);
327+
} else {
328+
resolve();
329+
}
330+
});
331+
});
332+
},
333+
334+
/**
335+
* Batch operation to merge in existing and new values for a given set of
336+
* keys. This assumes that the values are stringified JSON.
337+
*
338+
* See https://react-native-async-storage.github.io/async-storage/docs/api#multimerge
339+
*/
340+
multiMerge: (keyValuePairs, callback) => {
341+
return new Promise((resolve, reject) => {
342+
RCTAsyncStorage.multiMerge(keyValuePairs, (errors?: ErrorLike[]) => {
343+
const error = convertErrors(errors);
344+
callback?.(error);
345+
if (error) {
346+
reject(error);
347+
} else {
348+
resolve();
349+
}
350+
});
351+
});
352+
},
353+
};
354+
})();
355+
356+
export default AsyncStorage;

0 commit comments

Comments
 (0)