@fto-consult/expo-ui 6.37.3 → 6.37.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/App.js +0 -1
- package/node_modules/.package-lock.json +26218 -26188
- package/node_modules/@fto-consult/common/babel.config.alias.js +18 -1
- package/node_modules/@fto-consult/common/package.json +1 -1
- package/node_modules/@react-native-async-storage/async-storage/LICENSE +21 -0
- package/node_modules/@react-native-async-storage/async-storage/README.md +27 -0
- package/node_modules/@react-native-async-storage/async-storage/RNCAsyncStorage.podspec +19 -0
- package/node_modules/@react-native-async-storage/async-storage/android/build.gradle +142 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/AndroidManifest.xml +6 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncLocalStorageUtil.java +178 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageErrorUtil.java +45 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageExpoMigration.java +154 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStorageModule.java +424 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java +58 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/ReactDatabaseSupplier.java +163 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/SerialExecutor.java +40 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/ArgumentHelpers.kt +86 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/ErrorHelpers.kt +39 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageModule.kt +90 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/main/java/com/reactnativecommunity/asyncstorage/next/StorageSupplier.kt +161 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/test/java/com/reactnativecommunity/asyncstorage/next/ArgumentHelpersTest.kt +93 -0
- package/node_modules/@react-native-async-storage/async-storage/android/src/test/java/com/reactnativecommunity/asyncstorage/next/StorageTest.kt +141 -0
- package/node_modules/@react-native-async-storage/async-storage/android/testresults.gradle +38 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.h +51 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.m +898 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorage.xcodeproj/project.pbxproj +283 -0
- package/node_modules/@react-native-async-storage/async-storage/ios/RNCAsyncStorageDelegate.h +73 -0
- package/node_modules/@react-native-async-storage/async-storage/jest/async-storage-mock.d.ts +9 -0
- package/node_modules/@react-native-async-storage/async-storage/jest/async-storage-mock.js +109 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.js +164 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.native.js +366 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/AsyncStorage.native.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/RCTAsyncStorage.js +30 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/RCTAsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/helpers.js +69 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/helpers.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/hooks.js +44 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/hooks.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/index.js +22 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/index.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/shouldFallbackToLegacyNativeModule.js +39 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/shouldFallbackToLegacyNativeModule.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/types.js +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/commonjs/types.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.js +153 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.native.js +348 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/AsyncStorage.native.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/RCTAsyncStorage.js +20 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/RCTAsyncStorage.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/helpers.js +56 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/helpers.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/hooks.js +34 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/hooks.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/index.js +4 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/index.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/shouldFallbackToLegacyNativeModule.js +31 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/shouldFallbackToLegacyNativeModule.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/types.js +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/module/types.js.map +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/AsyncStorage.d.ts +10 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/AsyncStorage.native.d.ts +16 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/RCTAsyncStorage.d.ts +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/helpers.d.ts +5 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/hooks.d.ts +2 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/index.d.ts +4 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/shouldFallbackToLegacyNativeModule.d.ts +1 -0
- package/node_modules/@react-native-async-storage/async-storage/lib/typescript/types.d.ts +113 -0
- package/node_modules/@react-native-async-storage/async-storage/macos/RNCAsyncStorage.xcodeproj/project.pbxproj +385 -0
- package/node_modules/@react-native-async-storage/async-storage/macos/RNCAsyncStorage.xcodeproj/xcshareddata/xcschemes/RNCAsyncStorage-macOS.xcscheme +67 -0
- package/node_modules/@react-native-async-storage/async-storage/macos/RNCAsyncStorage.xcodeproj/xcshareddata/xcschemes/RNCAsyncStorage.xcscheme +67 -0
- package/node_modules/@react-native-async-storage/async-storage/package.json +197 -0
- package/node_modules/@react-native-async-storage/async-storage/src/AsyncStorage.native.ts +356 -0
- package/node_modules/@react-native-async-storage/async-storage/src/AsyncStorage.ts +173 -0
- package/node_modules/@react-native-async-storage/async-storage/src/RCTAsyncStorage.ts +28 -0
- package/node_modules/@react-native-async-storage/async-storage/src/helpers.ts +74 -0
- package/node_modules/@react-native-async-storage/async-storage/src/hooks.ts +11 -0
- package/node_modules/@react-native-async-storage/async-storage/src/index.ts +7 -0
- package/node_modules/@react-native-async-storage/async-storage/src/shouldFallbackToLegacyNativeModule.ts +34 -0
- package/node_modules/@react-native-async-storage/async-storage/src/types.ts +155 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/PropertySheet.props +16 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/ReactNativeAsyncStorage.vcxproj +172 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/ReactNativeAsyncStorage.vcxproj.filters +34 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage/packages.config +4 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage.sln +172 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/PropertySheet.props +16 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/ReactNativeAsyncStorage61.vcxproj +157 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/ReactNativeAsyncStorage61.vcxproj.filters +34 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61/packages.config +4 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage61.sln +195 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/ReactNativeAsyncStorage62.sln +192 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/DBStorage.cpp +599 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/DBStorage.h +162 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/RNCAsyncStorage.h +118 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactNativeAsyncStorage.def +3 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactPackageProvider.cpp +20 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactPackageProvider.h +23 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/ReactPackageProvider.idl +7 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/pch.cpp +3 -0
- package/node_modules/@react-native-async-storage/async-storage/windows/code/pch.h +15 -0
- package/node_modules/merge-options/index.d.ts +2 -0
- package/node_modules/merge-options/index.js +171 -0
- package/node_modules/merge-options/index.mjs +8 -0
- package/node_modules/merge-options/license +21 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/index.d.ts +29 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/index.js +10 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/license +9 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/package.json +38 -0
- package/node_modules/merge-options/node_modules/is-plain-obj/readme.md +54 -0
- package/node_modules/merge-options/package.json +59 -0
- package/node_modules/merge-options/readme.md +130 -0
- package/package.json +131 -130
- package/src/components/Chart/appexChart/appexChart.html +23 -23
@@ -0,0 +1,424 @@
|
|
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
|
+
package com.reactnativecommunity.asyncstorage;
|
9
|
+
|
10
|
+
import android.database.Cursor;
|
11
|
+
import android.database.sqlite.SQLiteStatement;
|
12
|
+
import android.os.AsyncTask;
|
13
|
+
|
14
|
+
import com.facebook.common.logging.FLog;
|
15
|
+
import com.facebook.react.bridge.Arguments;
|
16
|
+
import com.facebook.react.bridge.Callback;
|
17
|
+
import com.facebook.react.bridge.GuardedAsyncTask;
|
18
|
+
import com.facebook.react.bridge.LifecycleEventListener;
|
19
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
20
|
+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
21
|
+
import com.facebook.react.bridge.ReactMethod;
|
22
|
+
import com.facebook.react.bridge.ReadableArray;
|
23
|
+
import com.facebook.react.bridge.WritableArray;
|
24
|
+
import com.facebook.react.bridge.WritableMap;
|
25
|
+
import com.facebook.react.common.ReactConstants;
|
26
|
+
import com.facebook.react.common.annotations.VisibleForTesting;
|
27
|
+
import com.facebook.react.module.annotations.ReactModule;
|
28
|
+
import com.facebook.react.modules.common.ModuleDataCleaner;
|
29
|
+
|
30
|
+
import java.util.ArrayDeque;
|
31
|
+
import java.util.HashSet;
|
32
|
+
import java.util.concurrent.Executor;
|
33
|
+
import java.util.concurrent.Executors;
|
34
|
+
|
35
|
+
@ReactModule(name = AsyncStorageModule.NAME)
|
36
|
+
public final class AsyncStorageModule
|
37
|
+
extends ReactContextBaseJavaModule implements ModuleDataCleaner.Cleanable, LifecycleEventListener {
|
38
|
+
|
39
|
+
// changed name to not conflict with AsyncStorage from RN repo
|
40
|
+
public static final String NAME = "RNC_AsyncSQLiteDBStorage";
|
41
|
+
|
42
|
+
// SQL variable number limit, defined by SQLITE_LIMIT_VARIABLE_NUMBER:
|
43
|
+
// https://raw.githubusercontent.com/android/platform_external_sqlite/master/dist/sqlite3.c
|
44
|
+
private static final int MAX_SQL_KEYS = 999;
|
45
|
+
|
46
|
+
private ReactDatabaseSupplier mReactDatabaseSupplier;
|
47
|
+
private boolean mShuttingDown = false;
|
48
|
+
|
49
|
+
private final SerialExecutor executor;
|
50
|
+
|
51
|
+
public AsyncStorageModule(ReactApplicationContext reactContext) {
|
52
|
+
this(
|
53
|
+
reactContext,
|
54
|
+
BuildConfig.AsyncStorage_useDedicatedExecutor
|
55
|
+
? Executors.newSingleThreadExecutor()
|
56
|
+
: AsyncTask.THREAD_POOL_EXECUTOR
|
57
|
+
);
|
58
|
+
}
|
59
|
+
|
60
|
+
@VisibleForTesting
|
61
|
+
AsyncStorageModule(ReactApplicationContext reactContext, Executor executor) {
|
62
|
+
super(reactContext);
|
63
|
+
// The migration MUST run before the AsyncStorage database is created for the first time.
|
64
|
+
AsyncStorageExpoMigration.migrate(reactContext);
|
65
|
+
|
66
|
+
this.executor = new SerialExecutor(executor);
|
67
|
+
reactContext.addLifecycleEventListener(this);
|
68
|
+
// Creating the database MUST happen after the migration.
|
69
|
+
mReactDatabaseSupplier = ReactDatabaseSupplier.getInstance(reactContext);
|
70
|
+
}
|
71
|
+
|
72
|
+
@Override
|
73
|
+
public String getName() {
|
74
|
+
return NAME;
|
75
|
+
}
|
76
|
+
|
77
|
+
@Override
|
78
|
+
public void initialize() {
|
79
|
+
super.initialize();
|
80
|
+
mShuttingDown = false;
|
81
|
+
}
|
82
|
+
|
83
|
+
@Override
|
84
|
+
public void onCatalystInstanceDestroy() {
|
85
|
+
mShuttingDown = true;
|
86
|
+
}
|
87
|
+
|
88
|
+
@Override
|
89
|
+
public void clearSensitiveData() {
|
90
|
+
// Clear local storage. If fails, crash, since the app is potentially in a bad state and could
|
91
|
+
// cause a privacy violation. We're still not recovering from this well, but at least the error
|
92
|
+
// will be reported to the server.
|
93
|
+
mReactDatabaseSupplier.clearAndCloseDatabase();
|
94
|
+
}
|
95
|
+
|
96
|
+
@Override
|
97
|
+
public void onHostResume() {}
|
98
|
+
|
99
|
+
@Override
|
100
|
+
public void onHostPause() {}
|
101
|
+
|
102
|
+
@Override
|
103
|
+
public void onHostDestroy() {
|
104
|
+
// ensure we close database when activity is destroyed
|
105
|
+
mReactDatabaseSupplier.closeDatabase();
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Given an array of keys, this returns a map of (key, value) pairs for the keys found, and
|
110
|
+
* (key, null) for the keys that haven't been found.
|
111
|
+
*/
|
112
|
+
@ReactMethod
|
113
|
+
public void multiGet(final ReadableArray keys, final Callback callback) {
|
114
|
+
if (keys == null) {
|
115
|
+
callback.invoke(AsyncStorageErrorUtil.getInvalidKeyError(null), null);
|
116
|
+
return;
|
117
|
+
}
|
118
|
+
|
119
|
+
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
120
|
+
@Override
|
121
|
+
protected void doInBackgroundGuarded(Void... params) {
|
122
|
+
if (!ensureDatabase()) {
|
123
|
+
callback.invoke(AsyncStorageErrorUtil.getDBError(null), null);
|
124
|
+
return;
|
125
|
+
}
|
126
|
+
|
127
|
+
String[] columns = {ReactDatabaseSupplier.KEY_COLUMN, ReactDatabaseSupplier.VALUE_COLUMN};
|
128
|
+
HashSet<String> keysRemaining = new HashSet<>();
|
129
|
+
WritableArray data = Arguments.createArray();
|
130
|
+
for (int keyStart = 0; keyStart < keys.size(); keyStart += MAX_SQL_KEYS) {
|
131
|
+
int keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS);
|
132
|
+
Cursor cursor = mReactDatabaseSupplier.get().query(
|
133
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
134
|
+
columns,
|
135
|
+
AsyncLocalStorageUtil.buildKeySelection(keyCount),
|
136
|
+
AsyncLocalStorageUtil.buildKeySelectionArgs(keys, keyStart, keyCount),
|
137
|
+
null,
|
138
|
+
null,
|
139
|
+
null);
|
140
|
+
keysRemaining.clear();
|
141
|
+
try {
|
142
|
+
if (cursor.getCount() != keys.size()) {
|
143
|
+
// some keys have not been found - insert them with null into the final array
|
144
|
+
for (int keyIndex = keyStart; keyIndex < keyStart + keyCount; keyIndex++) {
|
145
|
+
keysRemaining.add(keys.getString(keyIndex));
|
146
|
+
}
|
147
|
+
}
|
148
|
+
|
149
|
+
if (cursor.moveToFirst()) {
|
150
|
+
do {
|
151
|
+
WritableArray row = Arguments.createArray();
|
152
|
+
row.pushString(cursor.getString(0));
|
153
|
+
row.pushString(cursor.getString(1));
|
154
|
+
data.pushArray(row);
|
155
|
+
keysRemaining.remove(cursor.getString(0));
|
156
|
+
} while (cursor.moveToNext());
|
157
|
+
}
|
158
|
+
} catch (Exception e) {
|
159
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
160
|
+
callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage()), null);
|
161
|
+
return;
|
162
|
+
} finally {
|
163
|
+
cursor.close();
|
164
|
+
}
|
165
|
+
|
166
|
+
for (String key : keysRemaining) {
|
167
|
+
WritableArray row = Arguments.createArray();
|
168
|
+
row.pushString(key);
|
169
|
+
row.pushNull();
|
170
|
+
data.pushArray(row);
|
171
|
+
}
|
172
|
+
keysRemaining.clear();
|
173
|
+
}
|
174
|
+
|
175
|
+
callback.invoke(null, data);
|
176
|
+
}
|
177
|
+
}.executeOnExecutor(executor);
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Inserts multiple (key, value) pairs. If one or more of the pairs cannot be inserted, this will
|
182
|
+
* return AsyncLocalStorageFailure, but all other pairs will have been inserted.
|
183
|
+
* The insertion will replace conflicting (key, value) pairs.
|
184
|
+
*/
|
185
|
+
@ReactMethod
|
186
|
+
public void multiSet(final ReadableArray keyValueArray, final Callback callback) {
|
187
|
+
if (keyValueArray.size() == 0) {
|
188
|
+
callback.invoke();
|
189
|
+
return;
|
190
|
+
}
|
191
|
+
|
192
|
+
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
193
|
+
@Override
|
194
|
+
protected void doInBackgroundGuarded(Void... params) {
|
195
|
+
if (!ensureDatabase()) {
|
196
|
+
callback.invoke(AsyncStorageErrorUtil.getDBError(null));
|
197
|
+
return;
|
198
|
+
}
|
199
|
+
|
200
|
+
String sql = "INSERT OR REPLACE INTO " + ReactDatabaseSupplier.TABLE_CATALYST + " VALUES (?, ?);";
|
201
|
+
SQLiteStatement statement = mReactDatabaseSupplier.get().compileStatement(sql);
|
202
|
+
WritableMap error = null;
|
203
|
+
try {
|
204
|
+
mReactDatabaseSupplier.get().beginTransaction();
|
205
|
+
for (int idx=0; idx < keyValueArray.size(); idx++) {
|
206
|
+
if (keyValueArray.getArray(idx).size() != 2) {
|
207
|
+
error = AsyncStorageErrorUtil.getInvalidValueError(null);
|
208
|
+
return;
|
209
|
+
}
|
210
|
+
if (keyValueArray.getArray(idx).getString(0) == null) {
|
211
|
+
error = AsyncStorageErrorUtil.getInvalidKeyError(null);
|
212
|
+
return;
|
213
|
+
}
|
214
|
+
if (keyValueArray.getArray(idx).getString(1) == null) {
|
215
|
+
error = AsyncStorageErrorUtil.getInvalidValueError(null);
|
216
|
+
return;
|
217
|
+
}
|
218
|
+
|
219
|
+
statement.clearBindings();
|
220
|
+
statement.bindString(1, keyValueArray.getArray(idx).getString(0));
|
221
|
+
statement.bindString(2, keyValueArray.getArray(idx).getString(1));
|
222
|
+
statement.execute();
|
223
|
+
}
|
224
|
+
mReactDatabaseSupplier.get().setTransactionSuccessful();
|
225
|
+
} catch (Exception e) {
|
226
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
227
|
+
error = AsyncStorageErrorUtil.getError(null, e.getMessage());
|
228
|
+
} finally {
|
229
|
+
try {
|
230
|
+
mReactDatabaseSupplier.get().endTransaction();
|
231
|
+
} catch (Exception e) {
|
232
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
233
|
+
if (error == null) {
|
234
|
+
error = AsyncStorageErrorUtil.getError(null, e.getMessage());
|
235
|
+
}
|
236
|
+
}
|
237
|
+
}
|
238
|
+
if (error != null) {
|
239
|
+
callback.invoke(error);
|
240
|
+
} else {
|
241
|
+
callback.invoke();
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}.executeOnExecutor(executor);
|
245
|
+
}
|
246
|
+
|
247
|
+
/**
|
248
|
+
* Removes all rows of the keys given.
|
249
|
+
*/
|
250
|
+
@ReactMethod
|
251
|
+
public void multiRemove(final ReadableArray keys, final Callback callback) {
|
252
|
+
if (keys.size() == 0) {
|
253
|
+
callback.invoke();
|
254
|
+
return;
|
255
|
+
}
|
256
|
+
|
257
|
+
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
258
|
+
@Override
|
259
|
+
protected void doInBackgroundGuarded(Void... params) {
|
260
|
+
if (!ensureDatabase()) {
|
261
|
+
callback.invoke(AsyncStorageErrorUtil.getDBError(null));
|
262
|
+
return;
|
263
|
+
}
|
264
|
+
|
265
|
+
WritableMap error = null;
|
266
|
+
try {
|
267
|
+
mReactDatabaseSupplier.get().beginTransaction();
|
268
|
+
for (int keyStart = 0; keyStart < keys.size(); keyStart += MAX_SQL_KEYS) {
|
269
|
+
int keyCount = Math.min(keys.size() - keyStart, MAX_SQL_KEYS);
|
270
|
+
mReactDatabaseSupplier.get().delete(
|
271
|
+
ReactDatabaseSupplier.TABLE_CATALYST,
|
272
|
+
AsyncLocalStorageUtil.buildKeySelection(keyCount),
|
273
|
+
AsyncLocalStorageUtil.buildKeySelectionArgs(keys, keyStart, keyCount));
|
274
|
+
}
|
275
|
+
mReactDatabaseSupplier.get().setTransactionSuccessful();
|
276
|
+
} catch (Exception e) {
|
277
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
278
|
+
error = AsyncStorageErrorUtil.getError(null, e.getMessage());
|
279
|
+
} finally {
|
280
|
+
try {
|
281
|
+
mReactDatabaseSupplier.get().endTransaction();
|
282
|
+
} catch (Exception e) {
|
283
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
284
|
+
if (error == null) {
|
285
|
+
error = AsyncStorageErrorUtil.getError(null, e.getMessage());
|
286
|
+
}
|
287
|
+
}
|
288
|
+
}
|
289
|
+
if (error != null) {
|
290
|
+
callback.invoke(error);
|
291
|
+
} else {
|
292
|
+
callback.invoke();
|
293
|
+
}
|
294
|
+
}
|
295
|
+
}.executeOnExecutor(executor);
|
296
|
+
}
|
297
|
+
|
298
|
+
/**
|
299
|
+
* Given an array of (key, value) pairs, this will merge the given values with the stored values
|
300
|
+
* of the given keys, if they exist.
|
301
|
+
*/
|
302
|
+
@ReactMethod
|
303
|
+
public void multiMerge(final ReadableArray keyValueArray, final Callback callback) {
|
304
|
+
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
305
|
+
@Override
|
306
|
+
protected void doInBackgroundGuarded(Void... params) {
|
307
|
+
if (!ensureDatabase()) {
|
308
|
+
callback.invoke(AsyncStorageErrorUtil.getDBError(null));
|
309
|
+
return;
|
310
|
+
}
|
311
|
+
WritableMap error = null;
|
312
|
+
try {
|
313
|
+
mReactDatabaseSupplier.get().beginTransaction();
|
314
|
+
for (int idx = 0; idx < keyValueArray.size(); idx++) {
|
315
|
+
if (keyValueArray.getArray(idx).size() != 2) {
|
316
|
+
error = AsyncStorageErrorUtil.getInvalidValueError(null);
|
317
|
+
return;
|
318
|
+
}
|
319
|
+
|
320
|
+
if (keyValueArray.getArray(idx).getString(0) == null) {
|
321
|
+
error = AsyncStorageErrorUtil.getInvalidKeyError(null);
|
322
|
+
return;
|
323
|
+
}
|
324
|
+
|
325
|
+
if (keyValueArray.getArray(idx).getString(1) == null) {
|
326
|
+
error = AsyncStorageErrorUtil.getInvalidValueError(null);
|
327
|
+
return;
|
328
|
+
}
|
329
|
+
|
330
|
+
if (!AsyncLocalStorageUtil.mergeImpl(
|
331
|
+
mReactDatabaseSupplier.get(),
|
332
|
+
keyValueArray.getArray(idx).getString(0),
|
333
|
+
keyValueArray.getArray(idx).getString(1))) {
|
334
|
+
error = AsyncStorageErrorUtil.getDBError(null);
|
335
|
+
return;
|
336
|
+
}
|
337
|
+
}
|
338
|
+
mReactDatabaseSupplier.get().setTransactionSuccessful();
|
339
|
+
} catch (Exception e) {
|
340
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
341
|
+
error = AsyncStorageErrorUtil.getError(null, e.getMessage());
|
342
|
+
} finally {
|
343
|
+
try {
|
344
|
+
mReactDatabaseSupplier.get().endTransaction();
|
345
|
+
} catch (Exception e) {
|
346
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
347
|
+
if (error == null) {
|
348
|
+
error = AsyncStorageErrorUtil.getError(null, e.getMessage());
|
349
|
+
}
|
350
|
+
}
|
351
|
+
}
|
352
|
+
if (error != null) {
|
353
|
+
callback.invoke(error);
|
354
|
+
} else {
|
355
|
+
callback.invoke();
|
356
|
+
}
|
357
|
+
}
|
358
|
+
}.executeOnExecutor(executor);
|
359
|
+
}
|
360
|
+
|
361
|
+
/**
|
362
|
+
* Clears the database.
|
363
|
+
*/
|
364
|
+
@ReactMethod
|
365
|
+
public void clear(final Callback callback) {
|
366
|
+
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
367
|
+
@Override
|
368
|
+
protected void doInBackgroundGuarded(Void... params) {
|
369
|
+
if (!mReactDatabaseSupplier.ensureDatabase()) {
|
370
|
+
callback.invoke(AsyncStorageErrorUtil.getDBError(null));
|
371
|
+
return;
|
372
|
+
}
|
373
|
+
try {
|
374
|
+
mReactDatabaseSupplier.clear();
|
375
|
+
callback.invoke();
|
376
|
+
} catch (Exception e) {
|
377
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
378
|
+
callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage()));
|
379
|
+
}
|
380
|
+
}
|
381
|
+
}.executeOnExecutor(executor);
|
382
|
+
}
|
383
|
+
|
384
|
+
/**
|
385
|
+
* Returns an array with all keys from the database.
|
386
|
+
*/
|
387
|
+
@ReactMethod
|
388
|
+
public void getAllKeys(final Callback callback) {
|
389
|
+
new GuardedAsyncTask<Void, Void>(getReactApplicationContext()) {
|
390
|
+
@Override
|
391
|
+
protected void doInBackgroundGuarded(Void... params) {
|
392
|
+
if (!ensureDatabase()) {
|
393
|
+
callback.invoke(AsyncStorageErrorUtil.getDBError(null), null);
|
394
|
+
return;
|
395
|
+
}
|
396
|
+
WritableArray data = Arguments.createArray();
|
397
|
+
String[] columns = {ReactDatabaseSupplier.KEY_COLUMN};
|
398
|
+
Cursor cursor = mReactDatabaseSupplier.get()
|
399
|
+
.query(ReactDatabaseSupplier.TABLE_CATALYST, columns, null, null, null, null, null);
|
400
|
+
try {
|
401
|
+
if (cursor.moveToFirst()) {
|
402
|
+
do {
|
403
|
+
data.pushString(cursor.getString(0));
|
404
|
+
} while (cursor.moveToNext());
|
405
|
+
}
|
406
|
+
} catch (Exception e) {
|
407
|
+
FLog.w(ReactConstants.TAG, e.getMessage(), e);
|
408
|
+
callback.invoke(AsyncStorageErrorUtil.getError(null, e.getMessage()), null);
|
409
|
+
return;
|
410
|
+
} finally {
|
411
|
+
cursor.close();
|
412
|
+
}
|
413
|
+
callback.invoke(null, data);
|
414
|
+
}
|
415
|
+
}.executeOnExecutor(executor);
|
416
|
+
}
|
417
|
+
|
418
|
+
/**
|
419
|
+
* Verify the database is open for reads and writes.
|
420
|
+
*/
|
421
|
+
private boolean ensureDatabase() {
|
422
|
+
return !mShuttingDown && mReactDatabaseSupplier.ensureDatabase();
|
423
|
+
}
|
424
|
+
}
|
@@ -0,0 +1,58 @@
|
|
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
|
+
package com.reactnativecommunity.asyncstorage;
|
9
|
+
|
10
|
+
import android.util.Log;
|
11
|
+
import com.facebook.react.ReactPackage;
|
12
|
+
import com.facebook.react.bridge.JavaScriptModule;
|
13
|
+
import com.facebook.react.bridge.NativeModule;
|
14
|
+
import com.facebook.react.bridge.ReactApplicationContext;
|
15
|
+
import com.facebook.react.bridge.ReactContext;
|
16
|
+
import com.facebook.react.uimanager.ViewManager;
|
17
|
+
import java.util.ArrayList;
|
18
|
+
import java.util.Collections;
|
19
|
+
import java.util.List;
|
20
|
+
|
21
|
+
public class AsyncStoragePackage implements ReactPackage {
|
22
|
+
@Override
|
23
|
+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
24
|
+
|
25
|
+
List<NativeModule> moduleList = new ArrayList<>(1);
|
26
|
+
|
27
|
+
if (BuildConfig.AsyncStorage_useNextStorage) {
|
28
|
+
try {
|
29
|
+
Class storageClass = Class.forName("com.reactnativecommunity.asyncstorage.next.StorageModule");
|
30
|
+
NativeModule inst = (NativeModule) storageClass.getDeclaredConstructor(new Class[]{ReactContext.class}).newInstance(reactContext);
|
31
|
+
moduleList.add(inst);
|
32
|
+
AsyncLocalStorageUtil.verifyAndForceSqliteCheckpoint(reactContext);
|
33
|
+
} catch (Exception e) {
|
34
|
+
String message = "Something went wrong when initializing module:"
|
35
|
+
+ "\n"
|
36
|
+
+ e.getCause().getClass()
|
37
|
+
+ "\n"
|
38
|
+
+ "Cause:" + e.getCause().getLocalizedMessage();
|
39
|
+
Log.e("AsyncStorage_Next", message);
|
40
|
+
}
|
41
|
+
} else {
|
42
|
+
moduleList.add(new AsyncStorageModule(reactContext));
|
43
|
+
}
|
44
|
+
|
45
|
+
return moduleList;
|
46
|
+
}
|
47
|
+
|
48
|
+
// Deprecated in RN 0.47
|
49
|
+
public List<Class<? extends JavaScriptModule>> createJSModules() {
|
50
|
+
return Collections.emptyList();
|
51
|
+
}
|
52
|
+
|
53
|
+
@Override
|
54
|
+
@SuppressWarnings("rawtypes")
|
55
|
+
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
|
56
|
+
return Collections.emptyList();
|
57
|
+
}
|
58
|
+
}
|
@@ -0,0 +1,163 @@
|
|
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
|
+
package com.reactnativecommunity.asyncstorage;
|
9
|
+
|
10
|
+
import android.content.Context;
|
11
|
+
import android.database.sqlite.SQLiteDatabase;
|
12
|
+
import android.database.sqlite.SQLiteException;
|
13
|
+
import android.database.sqlite.SQLiteOpenHelper;
|
14
|
+
import com.facebook.common.logging.FLog;
|
15
|
+
import com.facebook.react.common.ReactConstants;
|
16
|
+
import javax.annotation.Nullable;
|
17
|
+
|
18
|
+
/**
|
19
|
+
* Database supplier of the database used by react native. This creates, opens and deletes the
|
20
|
+
* database as necessary.
|
21
|
+
*/
|
22
|
+
public class ReactDatabaseSupplier extends SQLiteOpenHelper {
|
23
|
+
|
24
|
+
// VisibleForTesting
|
25
|
+
public static final String DATABASE_NAME = "RKStorage";
|
26
|
+
|
27
|
+
private static final int DATABASE_VERSION = 1;
|
28
|
+
private static final int SLEEP_TIME_MS = 30;
|
29
|
+
|
30
|
+
static final String TABLE_CATALYST = "catalystLocalStorage";
|
31
|
+
static final String KEY_COLUMN = "key";
|
32
|
+
static final String VALUE_COLUMN = "value";
|
33
|
+
|
34
|
+
static final String VERSION_TABLE_CREATE =
|
35
|
+
"CREATE TABLE " + TABLE_CATALYST + " (" +
|
36
|
+
KEY_COLUMN + " TEXT PRIMARY KEY, " +
|
37
|
+
VALUE_COLUMN + " TEXT NOT NULL" +
|
38
|
+
")";
|
39
|
+
|
40
|
+
private static @Nullable ReactDatabaseSupplier sReactDatabaseSupplierInstance;
|
41
|
+
|
42
|
+
private Context mContext;
|
43
|
+
private @Nullable SQLiteDatabase mDb;
|
44
|
+
private long mMaximumDatabaseSize = BuildConfig.AsyncStorage_db_size * 1024L * 1024L;
|
45
|
+
|
46
|
+
private ReactDatabaseSupplier(Context context) {
|
47
|
+
super(context, DATABASE_NAME, null, DATABASE_VERSION);
|
48
|
+
mContext = context;
|
49
|
+
}
|
50
|
+
|
51
|
+
public static ReactDatabaseSupplier getInstance(Context context) {
|
52
|
+
if (sReactDatabaseSupplierInstance == null) {
|
53
|
+
sReactDatabaseSupplierInstance = new ReactDatabaseSupplier(context.getApplicationContext());
|
54
|
+
}
|
55
|
+
return sReactDatabaseSupplierInstance;
|
56
|
+
}
|
57
|
+
|
58
|
+
@Override
|
59
|
+
public void onCreate(SQLiteDatabase db) {
|
60
|
+
db.execSQL(VERSION_TABLE_CREATE);
|
61
|
+
}
|
62
|
+
|
63
|
+
@Override
|
64
|
+
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
65
|
+
if (oldVersion != newVersion) {
|
66
|
+
deleteDatabase();
|
67
|
+
onCreate(db);
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Verify the database exists and is open.
|
73
|
+
*/
|
74
|
+
/* package */ synchronized boolean ensureDatabase() {
|
75
|
+
if (mDb != null && mDb.isOpen()) {
|
76
|
+
return true;
|
77
|
+
}
|
78
|
+
// Sometimes retrieving the database fails. We do 2 retries: first without database deletion
|
79
|
+
// and then with deletion.
|
80
|
+
SQLiteException lastSQLiteException = null;
|
81
|
+
for (int tries = 0; tries < 2; tries++) {
|
82
|
+
try {
|
83
|
+
if (tries > 0) {
|
84
|
+
deleteDatabase();
|
85
|
+
}
|
86
|
+
mDb = getWritableDatabase();
|
87
|
+
break;
|
88
|
+
} catch (SQLiteException e) {
|
89
|
+
lastSQLiteException = e;
|
90
|
+
}
|
91
|
+
// Wait before retrying.
|
92
|
+
try {
|
93
|
+
Thread.sleep(SLEEP_TIME_MS);
|
94
|
+
} catch (InterruptedException ie) {
|
95
|
+
Thread.currentThread().interrupt();
|
96
|
+
}
|
97
|
+
}
|
98
|
+
if (mDb == null) {
|
99
|
+
throw lastSQLiteException;
|
100
|
+
}
|
101
|
+
// This is a sane limit to protect the user from the app storing too much data in the database.
|
102
|
+
// This also protects the database from filling up the disk cache and becoming malformed
|
103
|
+
// (endTransaction() calls will throw an exception, not rollback, and leave the db malformed).
|
104
|
+
mDb.setMaximumSize(mMaximumDatabaseSize);
|
105
|
+
return true;
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Create and/or open the database.
|
110
|
+
*/
|
111
|
+
public synchronized SQLiteDatabase get() {
|
112
|
+
ensureDatabase();
|
113
|
+
return mDb;
|
114
|
+
}
|
115
|
+
|
116
|
+
public synchronized void clearAndCloseDatabase() throws RuntimeException {
|
117
|
+
try {
|
118
|
+
clear();
|
119
|
+
closeDatabase();
|
120
|
+
FLog.d(ReactConstants.TAG, "Cleaned " + DATABASE_NAME);
|
121
|
+
} catch (Exception e) {
|
122
|
+
// Clearing the database has failed, delete it instead.
|
123
|
+
if (deleteDatabase()) {
|
124
|
+
FLog.d(ReactConstants.TAG, "Deleted Local Database " + DATABASE_NAME);
|
125
|
+
return;
|
126
|
+
}
|
127
|
+
// Everything failed, throw
|
128
|
+
throw new RuntimeException("Clearing and deleting database " + DATABASE_NAME + " failed");
|
129
|
+
}
|
130
|
+
}
|
131
|
+
|
132
|
+
/* package */ synchronized void clear() {
|
133
|
+
get().delete(TABLE_CATALYST, null, null);
|
134
|
+
}
|
135
|
+
|
136
|
+
/**
|
137
|
+
* Sets the maximum size the database will grow to. The maximum size cannot
|
138
|
+
* be set below the current size.
|
139
|
+
*/
|
140
|
+
public synchronized void setMaximumSize(long size) {
|
141
|
+
mMaximumDatabaseSize = size;
|
142
|
+
if (mDb != null) {
|
143
|
+
mDb.setMaximumSize(mMaximumDatabaseSize);
|
144
|
+
}
|
145
|
+
}
|
146
|
+
|
147
|
+
private synchronized boolean deleteDatabase() {
|
148
|
+
closeDatabase();
|
149
|
+
return mContext.deleteDatabase(DATABASE_NAME);
|
150
|
+
}
|
151
|
+
|
152
|
+
public synchronized void closeDatabase() {
|
153
|
+
if (mDb != null && mDb.isOpen()) {
|
154
|
+
mDb.close();
|
155
|
+
mDb = null;
|
156
|
+
}
|
157
|
+
}
|
158
|
+
|
159
|
+
// For testing purposes only!
|
160
|
+
public static void deleteInstance() {
|
161
|
+
sReactDatabaseSupplierInstance = null;
|
162
|
+
}
|
163
|
+
}
|
@@ -0,0 +1,40 @@
|
|
1
|
+
package com.reactnativecommunity.asyncstorage;
|
2
|
+
|
3
|
+
import java.util.ArrayDeque;
|
4
|
+
import java.util.concurrent.Executor;
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Detox is using this implementation detail in its environment setup,
|
8
|
+
* so in order for Next storage to work, this class has been made public
|
9
|
+
*
|
10
|
+
* Adapted from https://android.googlesource.com/platform/frameworks/base.git/+/1488a3a19d4681a41fb45570c15e14d99db1cb66/core/java/android/os/AsyncTask.java#237
|
11
|
+
*/
|
12
|
+
public class SerialExecutor implements Executor {
|
13
|
+
private final ArrayDeque<Runnable> mTasks = new ArrayDeque<Runnable>();
|
14
|
+
private Runnable mActive;
|
15
|
+
private final Executor executor;
|
16
|
+
|
17
|
+
public SerialExecutor(Executor executor) {
|
18
|
+
this.executor = executor;
|
19
|
+
}
|
20
|
+
|
21
|
+
public synchronized void execute(final Runnable r) {
|
22
|
+
mTasks.offer(new Runnable() {
|
23
|
+
public void run() {
|
24
|
+
try {
|
25
|
+
r.run();
|
26
|
+
} finally {
|
27
|
+
scheduleNext();
|
28
|
+
}
|
29
|
+
}
|
30
|
+
});
|
31
|
+
if (mActive == null) {
|
32
|
+
scheduleNext();
|
33
|
+
}
|
34
|
+
}
|
35
|
+
synchronized void scheduleNext() {
|
36
|
+
if ((mActive = mTasks.poll()) != null) {
|
37
|
+
executor.execute(mActive);
|
38
|
+
}
|
39
|
+
}
|
40
|
+
}
|