Skip to content

Commit e21c604

Browse files
author
Krzysztof Borowy
committed
feat: native module refresher
1 parent f38e0b0 commit e21c604

File tree

10 files changed

+525
-3
lines changed

10 files changed

+525
-3
lines changed

android/build.gradle

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ def useDedicatedExecutor = rootProject.hasProperty('AsyncStorage_dedicatedExecut
1010
buildscript {
1111
def isRootProject = project == rootProject
1212

13-
ext.ktCoroutinesVersion = "1.3.8"
13+
ext.coroutinesVersion = "1.3.8"
14+
ext.roomVersion = "2.2.5"
1415

1516
// kotlin version can be set by setting ext.kotlinVersion or having it in gradle.properties in root
1617
ext.asyncStorageKtVersion = rootProject.ext.has('kotlinVersion')
@@ -53,6 +54,7 @@ if (newDbSize != null && newDbSize.isLong()) {
5354

5455
apply plugin: 'com.android.library'
5556
apply plugin: 'kotlin-android'
57+
apply plugin: 'kotlin-kapt'
5658

5759
android {
5860
compileSdkVersion safeExtGet('compileSdkVersion', 28)
@@ -81,6 +83,11 @@ repositories {
8183
dependencies {
8284
//noinspection GradleDynamicVersion
8385
implementation 'com.facebook.react:react-native:+' // From node_modules
86+
//noinspection GradleDependency
8487
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$asyncStorageKtVersion"
85-
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$ktCoroutinesVersion"
88+
89+
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutinesVersion"
90+
implementation "androidx.room:room-runtime:$roomVersion"
91+
implementation "androidx.room:room-ktx:$roomVersion"
92+
kapt "androidx.room:room-compiler:$roomVersion"
8693
}

android/src/main/java/com/reactnativecommunity/asyncstorage/AsyncStoragePackage.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,15 @@
1616
import java.util.Arrays;
1717
import java.util.Collections;
1818
import java.util.List;
19+
import com.reactnativecommunity.asyncstorage.next.AsyncStorageModuleNext;
1920

2021
public class AsyncStoragePackage implements ReactPackage {
2122
@Override
2223
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
23-
return Arrays.<NativeModule>asList(new AsyncStorageModule(reactContext));
24+
return Arrays.<NativeModule>asList(
25+
new AsyncStorageModule(reactContext),
26+
new AsyncStorageModuleNext(reactContext)
27+
);
2428
}
2529

2630
// Deprecated in RN 0.47
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* Copyright (c) Krzysztof Borowy
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.next
9+
10+
import com.facebook.react.bridge.Promise
11+
import com.facebook.react.bridge.ReactApplicationContext
12+
import com.facebook.react.bridge.ReactContextBaseJavaModule
13+
import com.facebook.react.bridge.ReactMethod
14+
import com.facebook.react.bridge.ReadableArray
15+
import com.facebook.react.bridge.ReadableMap
16+
import kotlinx.coroutines.CoroutineName
17+
import kotlinx.coroutines.CoroutineScope
18+
import kotlinx.coroutines.Dispatchers
19+
import kotlinx.coroutines.launch
20+
import kotlin.coroutines.CoroutineContext
21+
22+
class AsyncStorageModuleNext(reactAppContext: ReactApplicationContext) :
23+
ReactContextBaseJavaModule(reactAppContext), CoroutineScope {
24+
companion object {
25+
const val MODULE_NAME = "RNC_AsyncStorageNext"
26+
}
27+
28+
override val coroutineContext: CoroutineContext
29+
get() = Dispatchers.IO + CoroutineName("AsyncStorageCoroutine")
30+
31+
private val db: ASDao
32+
get() = AsyncStorageDB.getDatabase(reactApplicationContext).getASDao()
33+
34+
override fun getName() = MODULE_NAME
35+
36+
@ReactMethod
37+
fun getSingle(key: String, promise: Promise) {
38+
launch {
39+
val value = db.get(key)
40+
promise.resolve(value)
41+
}
42+
}
43+
44+
@ReactMethod
45+
fun setSingle(key: String, value: String?, promise: Promise) {
46+
val entry = AsyncStorageEntry(key, value)
47+
launch {
48+
db.set(entry)
49+
promise.resolve(true)
50+
}
51+
}
52+
53+
@ReactMethod
54+
fun deleteSingle(key: String, promise: Promise) {
55+
val entry = AsyncStorageEntry(key)
56+
launch {
57+
db.delete(entry)
58+
promise.resolve(true)
59+
}
60+
}
61+
62+
@ReactMethod
63+
fun getMany(keys: ReadableArray, promise: Promise) {
64+
val queryKeys = keys.toKeyList()
65+
66+
launch {
67+
val entries = db.getMany(queryKeys).toReadableMap()
68+
promise.resolve(entries)
69+
}
70+
}
71+
72+
@ReactMethod
73+
fun setMany(entries: ReadableMap, promise: Promise) {
74+
val entryList = entries.toAsyncStorageEntries()
75+
76+
launch {
77+
db.setMany(entryList)
78+
promise.resolve(true)
79+
}
80+
}
81+
82+
@ReactMethod
83+
fun deleteMany(keys: ReadableArray, promise: Promise) {
84+
val keysToDelete = keys.toKeyList()
85+
86+
launch {
87+
db.deleteMany(keysToDelete)
88+
promise.resolve(true)
89+
}
90+
}
91+
92+
@ReactMethod
93+
fun getAllKeys(promise: Promise) {
94+
launch {
95+
val keys = db.keys().toReadableArray()
96+
promise.resolve(keys)
97+
}
98+
}
99+
100+
@ReactMethod
101+
fun dropDatabase(promise: Promise) {
102+
launch {
103+
db.dropDatabase()
104+
promise.resolve(true)
105+
}
106+
}
107+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/**
2+
* Copyright (c) Krzysztof Borowy
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.next
9+
10+
import android.content.Context
11+
import androidx.room.ColumnInfo
12+
import androidx.room.Dao
13+
import androidx.room.Database
14+
import androidx.room.Delete
15+
import androidx.room.Entity
16+
import androidx.room.Insert
17+
import androidx.room.OnConflictStrategy
18+
import androidx.room.PrimaryKey
19+
import androidx.room.Query
20+
import androidx.room.Room
21+
import androidx.room.RoomDatabase
22+
23+
typealias KeyType = String
24+
typealias ValueType = String?
25+
26+
// todo: change those to use old DB
27+
// todo: unit tests
28+
const val DB_NAME = "AsyncStorageNextDB"
29+
const val DB_VERSION = 1
30+
const val TABLE_NAME = "as_table"
31+
const val KEY_COLUMN = "as_keys"
32+
const val VALUE_COLUMN = "as_value"
33+
34+
// The only table in this DB
35+
36+
@Entity(tableName = TABLE_NAME)
37+
data class AsyncStorageEntry(
38+
@PrimaryKey
39+
@ColumnInfo(name = KEY_COLUMN)
40+
val key: String,
41+
@ColumnInfo(name = VALUE_COLUMN)
42+
val value: String? = null
43+
)
44+
45+
@Dao
46+
interface ASDao {
47+
48+
@Query("SELECT $VALUE_COLUMN FROM $TABLE_NAME WHERE $KEY_COLUMN = :key")
49+
suspend fun get(key: KeyType): ValueType
50+
51+
@Insert(onConflict = OnConflictStrategy.REPLACE)
52+
suspend fun set(entry: AsyncStorageEntry)
53+
54+
@Delete
55+
suspend fun delete(entry: AsyncStorageEntry)
56+
57+
@Query("SELECT $KEY_COLUMN FROM $TABLE_NAME")
58+
suspend fun keys(): List<KeyType>
59+
60+
@Query("DELETE from $TABLE_NAME")
61+
suspend fun dropDatabase()
62+
63+
@Insert(onConflict = OnConflictStrategy.REPLACE)
64+
suspend fun setMany(entries: List<AsyncStorageEntry>)
65+
66+
@Query("SELECT * FROM $TABLE_NAME WHERE $KEY_COLUMN in (:keys)")
67+
suspend fun getMany(keys: List<KeyType>): List<AsyncStorageEntry>
68+
69+
@Query("DELETE FROM $TABLE_NAME WHERE $KEY_COLUMN in (:keys)")
70+
suspend fun deleteMany(keys: List<KeyType>)
71+
}
72+
73+
@Database(entities = [AsyncStorageEntry::class], version = DB_VERSION)
74+
abstract class AsyncStorageDB : RoomDatabase() {
75+
76+
companion object {
77+
private var instance: AsyncStorageDB? = null
78+
79+
fun getDatabase(context: Context): AsyncStorageDB {
80+
81+
var inst = instance
82+
83+
if (inst != null) {
84+
return inst
85+
}
86+
synchronized(this) {
87+
inst = Room
88+
.databaseBuilder(context, AsyncStorageDB::class.java, DB_NAME)
89+
.build()
90+
91+
instance = inst
92+
return instance!!
93+
}
94+
}
95+
}
96+
97+
abstract fun getASDao(): ASDao
98+
}
99+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/**
2+
* Copyright (c) Krzysztof Borowy
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.next
9+
10+
import com.facebook.react.bridge.Arguments
11+
import com.facebook.react.bridge.ReadableArray
12+
import com.facebook.react.bridge.ReadableMap
13+
14+
fun ReadableArray.toKeyList(): List<String> {
15+
val keys: MutableList<String> = mutableListOf()
16+
for (index in 0 until this.size()) {
17+
val key = getString(index)
18+
if (key != null) {
19+
keys.add(key)
20+
}
21+
}
22+
return keys
23+
}
24+
25+
fun ReadableMap.toAsyncStorageEntries(): List<AsyncStorageEntry> {
26+
val entryList = mutableListOf<AsyncStorageEntry>()
27+
val keyIterator = keySetIterator()
28+
while (keyIterator.hasNextKey()) {
29+
val key = keyIterator.nextKey()
30+
val value = getString(key)
31+
entryList.add(AsyncStorageEntry(key, value))
32+
}
33+
return entryList
34+
}
35+
36+
fun List<KeyType>.toReadableArray(): ReadableArray {
37+
val keyArray = Arguments.createArray()
38+
forEach { key ->
39+
keyArray.pushString(key)
40+
}
41+
return keyArray
42+
}
43+
44+
fun List<AsyncStorageEntry>.toReadableMap(): ReadableMap {
45+
val result = Arguments.createMap()
46+
forEach {
47+
result.putString(it.key, it.value)
48+
}
49+
return result
50+
}

example/App.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121

2222
import GetSetClear from './examples/GetSetClear';
2323
import MergeItem from './examples/MergeItem';
24+
import AsyncStorageNext from './examples/Next';
2425

2526
const TESTS = {
2627
GetSetClear: {
@@ -39,6 +40,14 @@ const TESTS = {
3940
return <MergeItem />;
4041
},
4142
},
43+
Next: {
44+
title: 'Next AsyncStorage',
45+
testId: 'as-next',
46+
description: 'Use Next version of AsyncStorage',
47+
render() {
48+
return <AsyncStorageNext />;
49+
},
50+
},
4251
};
4352

4453
type Props = {};
@@ -87,6 +96,11 @@ export default class App extends Component<Props, State> {
8796
title="Merge Item"
8897
onPress={() => this._changeTest('MergeItem')}
8998
/>
99+
<Button
100+
testID="testType_next"
101+
title="Next"
102+
onPress={() => this._changeTest('Next')}
103+
/>
90104
</View>
91105

92106
{restarting ? null : (

0 commit comments

Comments
 (0)