Skip to content

Commit

Permalink
fix: Error handling improvements and docs update (#698)
Browse files Browse the repository at this point in the history
* multiGet to propagate errors

* bump Android next versions

* docs: next storage + room

* docs: android limits
  • Loading branch information
Krzysztof authored Nov 4, 2021
1 parent 8dfd16d commit fc34bfa
Show file tree
Hide file tree
Showing 9 changed files with 93 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ cache keys:
brew ios: &key_brew_ios cache-brew-ios-v4-{{ arch }}
brew android: &key_brew_android cache-brew-android-v4-{{ arch }}
yarn: &key_yarn cache-yarn-{{ checksum "package.json" }}-{{ arch }}
gradle: &key_gradle cache-gradle-v1-{{ checksum "example/android/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "package.json" }}-{{ arch }}
gradle: &key_gradle cache-gradle-v2-{{ checksum "example/android/gradle/wrapper/gradle-wrapper.properties" }}-{{ checksum "package.json" }}-{{ arch }}
pods: &key_pods cache-pods-v1-{{ checksum "example/ios/Podfile" }}-{{ checksum "package.json" }}-{{ arch }}

cache:
Expand Down
27 changes: 21 additions & 6 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ def getFlagOrDefault(flagName, defaultValue) {
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] == "true" : defaultValue
}

def getVersionOrDefault(String flagName, String defaultVersion) {
rootProject.hasProperty(flagName) ? rootProject.properties[flagName] : defaultVersion
}

configurations {
compileClasspath
}
Expand All @@ -33,9 +37,7 @@ buildscript {
// kotlin version is dictated by rootProject extension or property in gradle.properties
ext.asyncStorageKtVersion = rootProject.ext.has('kotlinVersion')
? rootProject.ext['kotlinVersion']
: rootProject.hasProperty('AsyncStorage_kotlinVersion')
? rootProject.properties['AsyncStorage_kotlinVersion']
: '1.4.21'
: getVersionOrDefault('AsyncStorage_kotlinVersion', '1.5.31')

repositories {
google()
Expand Down Expand Up @@ -90,6 +92,13 @@ android {
testOptions {
unitTests.returnDefaultValues = true
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = "1.8"
}
}
}

Expand All @@ -106,16 +115,22 @@ repositories {
dependencies {

if (useNextStorage) {
def room_version = "2.2.6"
def coroutines_version = "1.4.2"
def room_version = getVersionOrDefault('AsyncStorage_next_roomVersion', '2.3.0')
def coroutines_version = "1.5.2"
def coroutinesTest_version = "1.5.2"
// if we don't provide explicit dependency on reflection, kotlin plugin
// would add one automatically, probably a version that is not compatible with
// used kotlin
def kotlinReflect_version = project.ext.asyncStorageKtVersion
def junit_version = "4.12"
def robolectric_version = "4.5.1"
def truth_version = "1.1.2"
def androidxtest_version = "1.1.0"
def coroutinesTest_version = "1.4.2"

implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlinReflect_version"

implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
kapt "androidx.room:room-compiler:$room_version"

Expand Down
4 changes: 3 additions & 1 deletion example/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,15 +35,17 @@ buildscript {
rootProject.setProperty("AsyncStorage_useNextStorage", "true")
}
Boolean nextStorageFlag = rootProject.hasProperty("AsyncStorage_useNextStorage") ? rootProject.properties["AsyncStorage_useNextStorage"] == "true" : false
println("[Async Storage] Using Next storage: " + nextStorageFlag)
println("[AsyncStorage] Using Next storage: " + nextStorageFlag)

repositories {
google()
mavenCentral()
jcenter()
}

dependencies {
classpath "com.android.tools.build:gradle:$androidPluginVersion"
// kotlinVersion is applied from react-native-test-app's dependencies.gradle script
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@
"react-native": "0.63.4",
"react-native-builder-bob": "^0.18.0",
"react-native-macos": "^0.63.4",
"react-native-test-app": "^0.9.0",
"react-native-test-app": "^0.9.5",
"react-native-web": "~0.12.0",
"react-native-windows": "^0.63.41",
"react-test-renderer": "16.13.1",
Expand Down
21 changes: 19 additions & 2 deletions src/AsyncStorage.native.js
Original file line number Diff line number Diff line change
Expand Up @@ -282,10 +282,27 @@ const AsyncStorage = {
return value;
});
const reqLength = getRequests.length;

/**
* As mentioned few lines above, this method could be called with the array of potential error,
* in case of anything goes wrong. The problem is, if any of the batched calls fails
* the rest of them would fail too, but the error would be consumed by just one. The rest
* would simply return `undefined` as their result, rendering false negatives.
*
* In order to avoid this situation, in case of any call failing,
* the rest of them will be rejected as well (with the same error).
*/
const errorList = convertErrors(errors);
const error = errorList && errorList.length ? errorList[0] : null;

for (let i = 0; i < reqLength; i++) {
const request = getRequests[i];
const requestKeys = request.keys;
const requestResult = requestKeys.map((key) => [key, map[key]]);
if (error) {
request.callback && request.callback(error);
request.reject && request.reject(error);
continue;
}
const requestResult = request.keys.map((key) => [key, map[key]]);
request.callback && request.callback(null, requestResult);
request.resolve && request.resolve(requestResult);
}
Expand Down
17 changes: 17 additions & 0 deletions website/docs/Limits.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
id: limits
title: Known storage limits
sidebar_label: Known limits
---

## Android

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.


- 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)

- 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).
This means that the single item read at one time cannot be larger than 2 MB. There's no supported workaround from AsyncStorage.
We suggest keeping your data lower than that, by chopping it down into many entries, instead of one massive entry.
This is where [`multiGet`](API.md#multiget) and [`multiSet`](API.md#multiset) APIs can shine.
34 changes: 24 additions & 10 deletions website/docs/advanced/Next.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ Current implementation of persistence layer is created using [SQLiteOpenHelper](
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.

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.
On top of that, it allows to access Async Storage from the native side, useful in [Brownfield integration.](BrownfieldIntegration.md#android)
On top of that, it allows accessing AsyncStorage from the native side, useful in [Brownfield integration.](BrownfieldIntegration.md#android)

### Migration

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.
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.
There's a small drawback to know - the database "recreation" happens **only once**.

#### How it works

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


### Enabling
### Enable

See [Configuration](#configuration) section below to learn more about setting different versions of Kotlin or Room.

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

```diff
buildscript {
ext {
// other extensions
+ kotlinVersion = '1.4.21'
+ kotlinVersion = '1.5.31'
}

dependencies {
Expand All @@ -55,26 +57,38 @@ buildscript {

```

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

```groovy
AsyncStorage_useNextStorage=true
```

**How to specifying Kotlin version**
### Configuration

**Kotlin version**

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

- having an `kotlinVersion` extension on the `rootProject` (recommended):
- add `kotlinVersion` extension to the `rootProject`:

```groovy
rootProject.ext.kotlinVersion = '1.4.21'
rootProject.ext.kotlinVersion = '1.5.31'
```

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

```groovy
AsyncStorage_kotlinVersion=1.4.21
AsyncStorage_kotlinVersion=1.5.31
```

**Room**

Next AsyncStorage uses [Room persistence library](https://developer.android.com/jetpack/androidx/releases/room) to store data.
Currently, tested version is `2.3.0`. You can specify different version, by adding a flag to `gradle.properties`:

```groovy
AsyncStorage_next_roomVersion=2.3.0
```

### Notable changes
Expand Down
2 changes: 1 addition & 1 deletion website/sidebars.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module.exports = {
docs: {
'Getting started': ['install', 'usage', 'link', 'api'],
'Getting started': ['install', 'usage', 'link', 'api', 'limits'],
Advanced: ['advanced/next', 'advanced/jest', 'advanced/brownfield', 'advanced/backup', 'advanced/executor', 'advanced/db_size'],
Debugging: ['debugging/communityPackages'],
Help: ['help/troubleshooting'],
Expand Down
11 changes: 6 additions & 5 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -11835,15 +11835,16 @@ react-native-safe-area-context@~3.0.7:
resolved "https://registry.yarnpkg.com/react-native-safe-area-context/-/react-native-safe-area-context-3.0.7.tgz#0f53de7a30d626d82936000f3f6db374ecc4b800"
integrity sha512-dqhRTlIFe5+P1yxitj0C9XVUxLqOmjomeqzUSSY8sNOWVjtIhEY/fl4ZKYpAVnktd8dt3zl13XmJTmRmy3d0uA==

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

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

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

0 comments on commit fc34bfa

Please sign in to comment.