Skip to content

Commit fc34bfa

Browse files
author
Krzysztof
authored
fix: Error handling improvements and docs update (#698)
* multiGet to propagate errors * bump Android next versions * docs: next storage + room * docs: android limits
1 parent 8dfd16d commit fc34bfa

File tree

9 files changed

+93
-27
lines changed

9 files changed

+93
-27
lines changed

.circleci/config.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ cache keys:
5252
brew ios: &key_brew_ios cache-brew-ios-v4-{{ arch }}
5353
brew android: &key_brew_android cache-brew-android-v4-{{ arch }}
5454
yarn: &key_yarn cache-yarn-{{ checksum "package.json" }}-{{ arch }}
55-
gradle: &key_gradle cache-gradle-v1-{{ checksum "example/android/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "package.json" }}-{{ arch }}
55+
gradle: &key_gradle cache-gradle-v2-{{ checksum "example/android/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "package.json" }}-{{ arch }}
5656
pods: &key_pods cache-pods-v1-{{ checksum "example/ios/Podfile" }}-{{ checksum "package.json" }}-{{ arch }}
5757

5858
cache:

android/build.gradle

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ def getFlagOrDefault(flagName, defaultValue) {
2525
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] == "true" : defaultValue
2626
}
2727

28+
def getVersionOrDefault(String flagName, String defaultVersion) {
29+
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] : defaultVersion
30+
}
31+
2832
configurations {
2933
compileClasspath
3034
}
@@ -33,9 +37,7 @@ buildscript {
3337
// kotlin version is dictated by rootProject extension or property in gradle.properties
3438
ext.asyncStorageKtVersion = rootProject.ext.has('kotlinVersion')
3539
? rootProject.ext['kotlinVersion']
36-
: rootProject.hasProperty('AsyncStorage_kotlinVersion')
37-
? rootProject.properties['AsyncStorage_kotlinVersion']
38-
: '1.4.21'
40+
: getVersionOrDefault('AsyncStorage_kotlinVersion', '1.5.31')
3941

4042
repositories {
4143
google()
@@ -90,6 +92,13 @@ android {
9092
testOptions {
9193
unitTests.returnDefaultValues = true
9294
}
95+
compileOptions {
96+
sourceCompatibility JavaVersion.VERSION_1_8
97+
targetCompatibility JavaVersion.VERSION_1_8
98+
}
99+
kotlinOptions {
100+
jvmTarget = "1.8"
101+
}
93102
}
94103
}
95104

@@ -106,16 +115,22 @@ repositories {
106115
dependencies {
107116

108117
if (useNextStorage) {
109-
def room_version = "2.2.6"
110-
def coroutines_version = "1.4.2"
118+
def room_version = getVersionOrDefault('AsyncStorage_next_roomVersion', '2.3.0')
119+
def coroutines_version = "1.5.2"
120+
def coroutinesTest_version = "1.5.2"
121+
// if we don't provide explicit dependency on reflection, kotlin plugin
122+
// would add one automatically, probably a version that is not compatible with
123+
// used kotlin
124+
def kotlinReflect_version = project.ext.asyncStorageKtVersion
111125
def junit_version = "4.12"
112126
def robolectric_version = "4.5.1"
113127
def truth_version = "1.1.2"
114128
def androidxtest_version = "1.1.0"
115-
def coroutinesTest_version = "1.4.2"
116129

117130
implementation "androidx.room:room-runtime:$room_version"
118131
implementation "androidx.room:room-ktx:$room_version"
132+
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinReflect_version"
133+
119134
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
120135
kapt "androidx.room:room-compiler:$room_version"
121136

example/android/build.gradle

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,17 @@ buildscript {
3535
rootProject.setProperty("AsyncStorage_useNextStorage", "true")
3636
}
3737
Boolean nextStorageFlag = rootProject.hasProperty("AsyncStorage_useNextStorage") ? rootProject.properties["AsyncStorage_useNextStorage"] == "true" : false
38-
println("[Async Storage] Using Next storage: " + nextStorageFlag)
38+
println("[AsyncStorage] Using Next storage: " + nextStorageFlag)
3939

4040
repositories {
4141
google()
4242
mavenCentral()
4343
jcenter()
4444
}
45+
4546
dependencies {
4647
classpath "com.android.tools.build:gradle:$androidPluginVersion"
48+
// kotlinVersion is applied from react-native-test-app's dependencies.gradle script
4749
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
4850
}
4951
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
"react-native": "0.63.4",
8989
"react-native-builder-bob": "^0.18.0",
9090
"react-native-macos": "^0.63.4",
91-
"react-native-test-app": "^0.9.0",
91+
"react-native-test-app": "^0.9.5",
9292
"react-native-web": "~0.12.0",
9393
"react-native-windows": "^0.63.41",
9494
"react-test-renderer": "16.13.1",

src/AsyncStorage.native.js

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,27 @@ const AsyncStorage = {
282282
return value;
283283
});
284284
const reqLength = getRequests.length;
285+
286+
/**
287+
* As mentioned few lines above, this method could be called with the array of potential error,
288+
* in case of anything goes wrong. The problem is, if any of the batched calls fails
289+
* the rest of them would fail too, but the error would be consumed by just one. The rest
290+
* would simply return `undefined` as their result, rendering false negatives.
291+
*
292+
* In order to avoid this situation, in case of any call failing,
293+
* the rest of them will be rejected as well (with the same error).
294+
*/
295+
const errorList = convertErrors(errors);
296+
const error = errorList && errorList.length ? errorList[0] : null;
297+
285298
for (let i = 0; i < reqLength; i++) {
286299
const request = getRequests[i];
287-
const requestKeys = request.keys;
288-
const requestResult = requestKeys.map((key) => [key, map[key]]);
300+
if (error) {
301+
request.callback && request.callback(error);
302+
request.reject && request.reject(error);
303+
continue;
304+
}
305+
const requestResult = request.keys.map((key) => [key, map[key]]);
289306
request.callback && request.callback(null, requestResult);
290307
request.resolve && request.resolve(requestResult);
291308
}

website/docs/Limits.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
---
2+
id: limits
3+
title: Known storage limits
4+
sidebar_label: Known limits
5+
---
6+
7+
## Android
8+
9+
AsyncStorage for Android uses SQLite for storage backend. While it has [its own size limits](https://www.sqlite.org/limits.html), Android system also have two known limits: total storage size and per-entry size limit.
10+
11+
12+
- Total storage size is capped at 6 MB by default. You can increase this size by [specifying a new size using feature flag.](advanced/IncreaseDbSize.md)
13+
14+
- Per-entry is limited by a size of a WindowCursor, a buffer used to read data from SQLite. [Currently it's size is around 2 MB](https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/res/res/values/config.xml;l=2103).
15+
This means that the single item read at one time cannot be larger than 2 MB. There's no supported workaround from AsyncStorage.
16+
We suggest keeping your data lower than that, by chopping it down into many entries, instead of one massive entry.
17+
This is where [`multiGet`](API.md#multiget) and [`multiSet`](API.md#multiset) APIs can shine.

website/docs/advanced/Next.md

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ Current implementation of persistence layer is created using [SQLiteOpenHelper](
1616
a helper class that manages database creation and migrations. Even if this approach is powerful, the lack of compile time query verification and a big boilerplate of mapping SQLite queries to actual values make this implementation prone to many errors.
1717

1818
This Async Storage feature improves the persistence layer, using modern approaches to access SQLite (using [Room](https://developer.android.com/training/data-storage/room)), to reduce possible anomalies to the minimum.
19-
On top of that, it allows to access Async Storage from the native side, useful in [Brownfield integration.](BrownfieldIntegration.md#android)
19+
On top of that, it allows accessing AsyncStorage from the native side, useful in [Brownfield integration.](BrownfieldIntegration.md#android)
2020

2121
### Migration
2222

2323
This feature requires no migration from the developer perspective - the current database will be recreated (based on the current one), meaning user won't lose any data if you decide to opt in.
24-
There's a small drawback to know - the database "recreation" happens **only once**. Unless you want to disable the feature in the future, there's nothing to worry about.
24+
There's a small drawback to know - the database "recreation" happens **only once**.
2525

2626
#### How it works
2727

@@ -36,15 +36,17 @@ If you decide to disable the feature, your users will be back using old database
3636
When you enable the feature again, the new database is **not** recreated, because it already exists, and no data is copied over.
3737

3838

39-
### Enabling
39+
### Enable
40+
41+
See [Configuration](#configuration) section below to learn more about setting different versions of Kotlin or Room.
4042

4143
1. In your project's `android` directory, locate root `build.gradle` file. Add Kotlin dependency to the `buildscript`:
4244

4345
```diff
4446
buildscript {
4547
ext {
4648
// other extensions
47-
+ kotlinVersion = '1.4.21'
49+
+ kotlinVersion = '1.5.31'
4850
}
4951

5052
dependencies {
@@ -55,26 +57,38 @@ buildscript {
5557

5658
```
5759

58-
2. In the same directory (normally `android`) locate `gradle.properties` file (if does not exists, create one) and add the line:
60+
2. In the same directory (normally `android`) locate `gradle.properties` file (if it does not exist, create one) and add the line:
5961

6062
```groovy
6163
AsyncStorage_useNextStorage=true
6264
```
6365

64-
**How to specifying Kotlin version**
66+
### Configuration
67+
68+
**Kotlin version**
6569

66-
Supported Kotlin versions are `1.4.x`. You can specify which one to use in two ways:
70+
Next storage is tested against Kotlin version `1.5.31`.
71+
You can specify different version, in one of two ways:
6772

68-
- having an `kotlinVersion` extension on the `rootProject` (recommended):
73+
- add `kotlinVersion` extension to the `rootProject`:
6974

7075
```groovy
71-
rootProject.ext.kotlinVersion = '1.4.21'
76+
rootProject.ext.kotlinVersion = '1.5.31'
7277
```
7378

7479
- specify `AsyncStorage_kotlinVersion` in `gradle.properties`:
7580

7681
```groovy
77-
AsyncStorage_kotlinVersion=1.4.21
82+
AsyncStorage_kotlinVersion=1.5.31
83+
```
84+
85+
**Room**
86+
87+
Next AsyncStorage uses [Room persistence library](https://developer.android.com/jetpack/androidx/releases/room) to store data.
88+
Currently, tested version is `2.3.0`. You can specify different version, by adding a flag to `gradle.properties`:
89+
90+
```groovy
91+
AsyncStorage_next_roomVersion=2.3.0
7892
```
7993

8094
### Notable changes

website/sidebars.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
module.exports = {
22
docs: {
3-
'Getting started': ['install', 'usage', 'link', 'api'],
3+
'Getting started': ['install', 'usage', 'link', 'api', 'limits'],
44
Advanced: ['advanced/next', 'advanced/jest', 'advanced/brownfield', 'advanced/backup', 'advanced/executor', 'advanced/db_size'],
55
Debugging: ['debugging/communityPackages'],
66
Help: ['help/troubleshooting'],

yarn.lock

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11835,15 +11835,16 @@ react-native-safe-area-context@~3.0.7:
1183511835
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.0.7.tgz#0f53de7a30d626d82936000f3f6db374ecc4b800"
1183611836
integrity sha512-dqhRTlIFe5+P1yxitj0C9XVUxLqOmjomeqzUSSY8sNOWVjtIhEY/fl4ZKYpAVnktd8dt3zl13XmJTmRmy3d0uA==
1183711837

11838-
react-native-test-app@^0.9.0:
11839-
version "0.9.0"
11840-
resolved "https://registry.yarnpkg.com/react-native-test-app/-/react-native-test-app-0.9.0.tgz#fd8669fd34703a02bfdab9ba7a98268002cc2fa4"
11841-
integrity sha512-HMI15lJqWZEOA1O5VvzxYG7mEzuKhkztxarWqVibUhcgOsK3U8fidq2+b18E1BiFpaDI+4zppkib/+/5LTjReQ==
11838+
react-native-test-app@^0.9.5:
11839+
version "0.9.11"
11840+
resolved "https://registry.yarnpkg.com/react-native-test-app/-/react-native-test-app-0.9.11.tgz#685c1252a4133531ba9590dbed0fa92c9fa5da35"
11841+
integrity sha512-XpysqX3UBb182ctcm02keNc0gjrS+Ae8kYfhZzR53zm3JqMY3gAluAmHwEKFzeHrGaL0mWtvvMTutex+VF1Ttw==
1184211842
dependencies:
1184311843
chalk "^4.1.0"
1184411844
prompts "^2.4.0"
1184511845
rimraf "^3.0.0"
1184611846
semver "^7.3.5"
11847+
uuid "^8.3.2"
1184711848
yargs "^16.0.0"
1184811849

1184911850
react-native-web@~0.12.0:
@@ -14122,7 +14123,7 @@ uuid@^7.0.3:
1412214123
resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b"
1412314124
integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg==
1412414125

14125-
uuid@^8.3.0:
14126+
uuid@^8.3.0, uuid@^8.3.2:
1412614127
version "8.3.2"
1412714128
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
1412814129
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==

0 commit comments

Comments
 (0)