@react-native-firebase/database 26.3.3 → 27.0.0
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/CHANGELOG.md +27 -0
- package/RNFBDatabase.podspec +10 -2
- package/android/build.gradle +7 -0
- package/android/src/main/java/io/invertase/firebase/database/DatabaseAbortable.java +22 -0
- package/android/src/main/java/io/invertase/firebase/database/DatabaseQueryHandle.java +24 -0
- package/android/src/main/java/io/invertase/firebase/database/RNFBDatabaseKeepSyncedRegistry.java +106 -0
- package/android/src/main/java/io/invertase/firebase/database/RNFBDatabaseListenerRegistry.kt +133 -0
- package/android/src/main/java/io/invertase/firebase/database/RNFBDatabaseQueryRegistry.kt +76 -0
- package/android/src/main/java/io/invertase/firebase/database/RNFBDatabaseTransactionRegistry.kt +67 -0
- package/android/src/main/java/io/invertase/firebase/database/UniversalFirebaseDatabaseOnDisconnectModule.java +102 -9
- package/android/src/reactnative/java/io/invertase/firebase/database/NativeRNFBTurboDatabaseOnDisconnect.java +6 -11
- package/android/src/reactnative/java/io/invertase/firebase/database/NativeRNFBTurboDatabaseQuery.java +111 -24
- package/android/src/reactnative/java/io/invertase/firebase/database/NativeRNFBTurboDatabaseTransaction.java +12 -25
- package/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseQuery.java +30 -33
- package/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseTransactionHandler.java +3 -3
- package/android/src/reactnative/java/io/invertase/firebase/database/generated/java/com/facebook/fbreact/specs/NativeRNFBTurboDatabaseQuerySpec.java +4 -0
- package/android/src/reactnative/java/io/invertase/firebase/database/generated/jni/RNFBDatabaseTurboModules-generated.cpp +6 -0
- package/android/src/reactnative/java/io/invertase/firebase/database/generated/jni/react/renderer/components/RNFBDatabaseTurboModules/RNFBDatabaseTurboModulesJSI.h +12 -0
- package/android/src/test/java/io/invertase/firebase/database/RNFBDatabaseKeepSyncedRegistryTest.java +174 -0
- package/android/src/test/java/io/invertase/firebase/database/RNFBDatabaseListenerRegistryTest.java +191 -0
- package/android/src/test/java/io/invertase/firebase/database/RNFBDatabaseQueryRegistryTest.java +489 -0
- package/android/src/test/java/io/invertase/firebase/database/RNFBDatabaseTransactionRegistryTest.java +199 -0
- package/android/src/test/java/io/invertase/firebase/database/UniversalFirebaseDatabaseOnDisconnectCancelErrorTest.java +137 -0
- package/dist/module/DatabaseQuery.js +52 -1
- package/dist/module/DatabaseQuery.js.map +1 -1
- package/dist/module/DatabaseSyncTree.js +1 -1
- package/dist/module/DatabaseSyncTree.js.map +1 -1
- package/dist/module/index.js +1 -2
- package/dist/module/index.js.map +1 -1
- package/dist/module/modular/query.js +1 -1
- package/dist/module/modular/query.js.map +1 -1
- package/dist/module/version.js +1 -1
- package/dist/module/web/RNFBDatabaseModule.js +7 -0
- package/dist/module/web/RNFBDatabaseModule.js.map +1 -1
- package/dist/typescript/lib/DatabaseQuery.d.ts +25 -0
- package/dist/typescript/lib/DatabaseQuery.d.ts.map +1 -1
- package/dist/typescript/lib/index.d.ts +1 -1
- package/dist/typescript/lib/types/internal.d.ts +2 -0
- package/dist/typescript/lib/types/internal.d.ts.map +1 -1
- package/dist/typescript/lib/version.d.ts +1 -1
- package/dist/typescript/lib/web/RNFBDatabaseModule.d.ts.map +1 -1
- package/ios/RNFBDatabase/RNFBDatabaseListenerRegistry.h +37 -0
- package/ios/RNFBDatabase/RNFBDatabaseListenerRegistry.m +91 -0
- package/ios/RNFBDatabase/RNFBDatabaseListenerRegistryStorage.swift +81 -0
- package/ios/RNFBDatabase/RNFBDatabaseNullSentinelDecoder.h +36 -0
- package/ios/RNFBDatabase/RNFBDatabaseNullSentinelDecoder.m +48 -0
- package/ios/RNFBDatabase/RNFBDatabaseOnDisconnectHelper.m +29 -26
- package/ios/RNFBDatabase/RNFBDatabaseQuery.h +3 -2
- package/ios/RNFBDatabase/RNFBDatabaseQuery.m +14 -13
- package/ios/RNFBDatabase/RNFBDatabaseQueryHelper.h +7 -0
- package/ios/RNFBDatabase/RNFBDatabaseQueryHelper.m +44 -21
- package/ios/RNFBDatabase/RNFBDatabaseQueryModule.mm +14 -0
- package/ios/RNFBDatabase/RNFBDatabaseQueryRegistry.h +37 -0
- package/ios/RNFBDatabase/RNFBDatabaseQueryRegistry.m +79 -0
- package/ios/RNFBDatabase/RNFBDatabaseQueryRegistryStorage.swift +104 -0
- package/ios/RNFBDatabase/RNFBDatabaseReferenceHelper.m +14 -12
- package/ios/RNFBDatabase/RNFBDatabaseTransactionHelper.m +3 -1
- package/ios/RNFBDatabase.xcodeproj/project.pbxproj +12 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseListenerRegistryStorageTests.swift +86 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseListenerRegistryTests.m +90 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseNullSentinelDecodeTests.m +118 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseQueryRegistryStorageTests.swift +181 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseQueryRegistryTests.m +390 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseUnitTests.xcodeproj/project.pbxproj +303 -0
- package/ios/RNFBDatabaseUnitTests/RNFBDatabaseUnitTests.xcodeproj/xcshareddata/xcschemes/RNFBDatabaseUnitTests.xcscheme +69 -0
- package/ios/generated/RNFBDatabaseTurboModules/RNFBDatabaseTurboModules-generated.mm +7 -0
- package/ios/generated/RNFBDatabaseTurboModules/RNFBDatabaseTurboModules.h +6 -0
- package/ios/generated/RNFBDatabaseTurboModulesJSI.h +12 -0
- package/lib/DatabaseQuery.ts +56 -0
- package/lib/DatabaseSyncTree.ts +1 -1
- package/lib/index.ts +1 -1
- package/lib/modular/query.ts +1 -1
- package/lib/types/internal.ts +2 -0
- package/lib/version.ts +1 -1
- package/lib/web/RNFBDatabaseModule.ts +13 -0
- package/package.json +5 -4
- package/specs/NativeRNFBTurboDatabaseQuery.ts +1 -0
|
@@ -18,12 +18,12 @@ package io.invertase.firebase.database;
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
20
|
import static io.invertase.firebase.common.RCTConvertFirebase.toHashMap;
|
|
21
|
+
import static io.invertase.firebase.database.ReactNativeFirebaseDatabaseCommon.rejectPromiseDatabaseException;
|
|
21
22
|
|
|
22
23
|
import com.facebook.fbreact.specs.NativeRNFBTurboDatabaseOnDisconnectSpec;
|
|
23
24
|
import com.facebook.react.bridge.Promise;
|
|
24
25
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
25
26
|
import com.facebook.react.bridge.ReadableMap;
|
|
26
|
-
import io.invertase.firebase.common.ReactNativeFirebaseModule;
|
|
27
27
|
import java.util.Map;
|
|
28
28
|
|
|
29
29
|
public class NativeRNFBTurboDatabaseOnDisconnect extends NativeRNFBTurboDatabaseOnDisconnectSpec {
|
|
@@ -44,8 +44,7 @@ public class NativeRNFBTurboDatabaseOnDisconnect extends NativeRNFBTurboDatabase
|
|
|
44
44
|
if (task.isSuccessful()) {
|
|
45
45
|
promise.resolve(task.getResult());
|
|
46
46
|
} else {
|
|
47
|
-
|
|
48
|
-
promise, task.getException());
|
|
47
|
+
rejectPromiseDatabaseException(promise, task.getException());
|
|
49
48
|
}
|
|
50
49
|
});
|
|
51
50
|
}
|
|
@@ -59,8 +58,7 @@ public class NativeRNFBTurboDatabaseOnDisconnect extends NativeRNFBTurboDatabase
|
|
|
59
58
|
if (task.isSuccessful()) {
|
|
60
59
|
promise.resolve(task.getResult());
|
|
61
60
|
} else {
|
|
62
|
-
|
|
63
|
-
promise, task.getException());
|
|
61
|
+
rejectPromiseDatabaseException(promise, task.getException());
|
|
64
62
|
}
|
|
65
63
|
});
|
|
66
64
|
}
|
|
@@ -75,8 +73,7 @@ public class NativeRNFBTurboDatabaseOnDisconnect extends NativeRNFBTurboDatabase
|
|
|
75
73
|
if (task.isSuccessful()) {
|
|
76
74
|
promise.resolve(task.getResult());
|
|
77
75
|
} else {
|
|
78
|
-
|
|
79
|
-
promise, task.getException());
|
|
76
|
+
rejectPromiseDatabaseException(promise, task.getException());
|
|
80
77
|
}
|
|
81
78
|
});
|
|
82
79
|
}
|
|
@@ -92,8 +89,7 @@ public class NativeRNFBTurboDatabaseOnDisconnect extends NativeRNFBTurboDatabase
|
|
|
92
89
|
if (task.isSuccessful()) {
|
|
93
90
|
promise.resolve(task.getResult());
|
|
94
91
|
} else {
|
|
95
|
-
|
|
96
|
-
promise, task.getException());
|
|
92
|
+
rejectPromiseDatabaseException(promise, task.getException());
|
|
97
93
|
}
|
|
98
94
|
});
|
|
99
95
|
}
|
|
@@ -110,8 +106,7 @@ public class NativeRNFBTurboDatabaseOnDisconnect extends NativeRNFBTurboDatabase
|
|
|
110
106
|
if (task.isSuccessful()) {
|
|
111
107
|
promise.resolve(task.getResult());
|
|
112
108
|
} else {
|
|
113
|
-
|
|
114
|
-
promise, task.getException());
|
|
109
|
+
rejectPromiseDatabaseException(promise, task.getException());
|
|
115
110
|
}
|
|
116
111
|
});
|
|
117
112
|
}
|
|
@@ -26,11 +26,10 @@ import com.facebook.fbreact.specs.NativeRNFBTurboDatabaseQuerySpec;
|
|
|
26
26
|
import com.facebook.react.bridge.*;
|
|
27
27
|
import com.google.android.gms.tasks.Tasks;
|
|
28
28
|
import com.google.firebase.database.*;
|
|
29
|
+
import io.invertase.firebase.common.RNFBHandleCollisionException;
|
|
29
30
|
import io.invertase.firebase.common.ReactNativeFirebaseEventEmitter;
|
|
30
31
|
import io.invertase.firebase.common.ReactNativeFirebaseModule;
|
|
31
|
-
import
|
|
32
|
-
import java.util.Iterator;
|
|
33
|
-
import java.util.Map;
|
|
32
|
+
import io.invertase.firebase.common.UniversalFirebasePreferences;
|
|
34
33
|
import java.util.Objects;
|
|
35
34
|
import javax.annotation.Nonnull;
|
|
36
35
|
import javax.annotation.Nullable;
|
|
@@ -38,7 +37,7 @@ import javax.annotation.Nullable;
|
|
|
38
37
|
public class NativeRNFBTurboDatabaseQuery extends NativeRNFBTurboDatabaseQuerySpec {
|
|
39
38
|
private final DatabaseTurboModuleSupport turboSupport =
|
|
40
39
|
new DatabaseTurboModuleSupport("RNFBDatabaseQuery");
|
|
41
|
-
private
|
|
40
|
+
private final RNFBDatabaseQueryRegistry queryMap = new RNFBDatabaseQueryRegistry();
|
|
42
41
|
|
|
43
42
|
public NativeRNFBTurboDatabaseQuery(ReactApplicationContext reactContext) {
|
|
44
43
|
super(reactContext);
|
|
@@ -47,14 +46,7 @@ public class NativeRNFBTurboDatabaseQuery extends NativeRNFBTurboDatabaseQuerySp
|
|
|
47
46
|
@Override
|
|
48
47
|
@CallSuper
|
|
49
48
|
public void invalidate() {
|
|
50
|
-
|
|
51
|
-
while (refIterator.hasNext()) {
|
|
52
|
-
Map.Entry pair = (Map.Entry) refIterator.next();
|
|
53
|
-
ReactNativeFirebaseDatabaseQuery databaseQuery =
|
|
54
|
-
(ReactNativeFirebaseDatabaseQuery) pair.getValue();
|
|
55
|
-
databaseQuery.removeAllEventListeners();
|
|
56
|
-
refIterator.remove();
|
|
57
|
-
}
|
|
49
|
+
queryMap.takeAllAndRemove();
|
|
58
50
|
|
|
59
51
|
turboSupport.invalidate();
|
|
60
52
|
super.invalidate();
|
|
@@ -67,16 +59,23 @@ public class NativeRNFBTurboDatabaseQuery extends NativeRNFBTurboDatabaseQuerySp
|
|
|
67
59
|
|
|
68
60
|
private ReactNativeFirebaseDatabaseQuery getDatabaseQueryInstance(
|
|
69
61
|
String key, DatabaseReference reference, ReadableArray modifiers) {
|
|
70
|
-
|
|
62
|
+
DatabaseQueryHandle cached = queryMap.get(key);
|
|
71
63
|
|
|
72
|
-
if (
|
|
73
|
-
return
|
|
64
|
+
if (cached instanceof ReactNativeFirebaseDatabaseQuery) {
|
|
65
|
+
return (ReactNativeFirebaseDatabaseQuery) cached;
|
|
74
66
|
}
|
|
75
67
|
|
|
76
68
|
ReactNativeFirebaseDatabaseQuery databaseQuery =
|
|
77
69
|
new ReactNativeFirebaseDatabaseQuery(reference, modifiers);
|
|
78
70
|
|
|
79
|
-
|
|
71
|
+
try {
|
|
72
|
+
queryMap.put(key, databaseQuery);
|
|
73
|
+
} catch (RNFBHandleCollisionException collision) {
|
|
74
|
+
DatabaseQueryHandle winner = queryMap.get(key);
|
|
75
|
+
if (winner instanceof ReactNativeFirebaseDatabaseQuery) {
|
|
76
|
+
return (ReactNativeFirebaseDatabaseQuery) winner;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
80
79
|
return databaseQuery;
|
|
81
80
|
}
|
|
82
81
|
|
|
@@ -376,6 +375,88 @@ public class NativeRNFBTurboDatabaseQuery extends NativeRNFBTurboDatabaseQuerySp
|
|
|
376
375
|
}
|
|
377
376
|
}
|
|
378
377
|
|
|
378
|
+
// Static because the SDK keeps keepSynced registrations across a JS reload.
|
|
379
|
+
private static final RNFBDatabaseKeepSyncedRegistry keepSyncedRegistry =
|
|
380
|
+
new RNFBDatabaseKeepSyncedRegistry();
|
|
381
|
+
|
|
382
|
+
// reference.toString() is the full URL, so a null dbURL and the default URL give the same key.
|
|
383
|
+
private static String locationKey(String app, DatabaseReference reference) {
|
|
384
|
+
return app + "|" + reference;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
private static final java.util.regex.Pattern PERMISSION_DENIED_REASON =
|
|
388
|
+
java.util.regex.Pattern.compile(
|
|
389
|
+
"permission.?denied", java.util.regex.Pattern.CASE_INSENSITIVE);
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Single request/response read backing modular get(). Offline, Query.get() waits for the
|
|
393
|
+
* connection, like once(). It uses once() instead when:
|
|
394
|
+
*
|
|
395
|
+
* <ul>
|
|
396
|
+
* <li>disk persistence is on: Query.get() then resolves from disk after 3s, even online;
|
|
397
|
+
* <li>RTDB debug logging is on: a get in flight when the socket drops is resent on reconnect
|
|
398
|
+
* only because PersistentConnectionImpl.sendGet's early return sits inside {@code if
|
|
399
|
+
* (logger.logsDebug())};
|
|
400
|
+
* <li>the app keeps anything at this location synced (see RNFBDatabaseKeepSyncedRegistry).
|
|
401
|
+
* </ul>
|
|
402
|
+
*/
|
|
403
|
+
@Override
|
|
404
|
+
public void get(String app, String dbURL, String path, ReadableArray modifiers, Promise promise) {
|
|
405
|
+
DatabaseReference reference = getDatabaseForApp(app, dbURL).getReference(path);
|
|
406
|
+
ReactNativeFirebaseDatabaseQuery databaseQuery = getDatabaseQueryInstance(reference, modifiers);
|
|
407
|
+
|
|
408
|
+
UniversalFirebasePreferences preferences = UniversalFirebasePreferences.getSharedInstance();
|
|
409
|
+
String location = locationKey(app, reference);
|
|
410
|
+
if (modifiers.size() > 0
|
|
411
|
+
|| preferences.getBooleanValue(UniversalDatabaseStatics.DATABASE_PERSISTENCE_ENABLED, false)
|
|
412
|
+
|| preferences.getBooleanValue(UniversalDatabaseStatics.DATABASE_LOGGING_ENABLED, false)
|
|
413
|
+
|| !keepSyncedRegistry.beginNativeGet(location)) {
|
|
414
|
+
addOnceValueEventListener(databaseQuery, promise);
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
databaseQuery
|
|
419
|
+
.query
|
|
420
|
+
.get()
|
|
421
|
+
.addOnCompleteListener(
|
|
422
|
+
getTask -> {
|
|
423
|
+
keepSyncedRegistry.endNativeGet(location);
|
|
424
|
+
if (!getTask.isSuccessful()) {
|
|
425
|
+
Exception exception = getTask.getException();
|
|
426
|
+
// Query.get() surfaces a server error as a plain Exception carrying only the
|
|
427
|
+
// reply's reason text. Map a denial to the error once() gives, so callers see the
|
|
428
|
+
// same code and DatabaseQuery._get need not re-ask the server.
|
|
429
|
+
if (exception != null
|
|
430
|
+
&& exception.getMessage() != null
|
|
431
|
+
&& PERMISSION_DENIED_REASON.matcher(exception.getMessage()).find()) {
|
|
432
|
+
rejectPromiseDatabaseException(
|
|
433
|
+
promise,
|
|
434
|
+
new UniversalDatabaseException(
|
|
435
|
+
DatabaseError.PERMISSION_DENIED, exception.getMessage(), exception));
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(promise, exception);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
DataSnapshot dataSnapshot = getTask.getResult();
|
|
442
|
+
// Serialise off the main thread, as addOnceValueEventListener does.
|
|
443
|
+
try {
|
|
444
|
+
Tasks.call(turboSupport.getExecutor(), () -> snapshotToMap(dataSnapshot))
|
|
445
|
+
.addOnCompleteListener(
|
|
446
|
+
task -> {
|
|
447
|
+
if (task.isSuccessful()) {
|
|
448
|
+
promise.resolve(task.getResult());
|
|
449
|
+
} else {
|
|
450
|
+
ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(
|
|
451
|
+
promise, task.getException());
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
} catch (java.util.concurrent.RejectedExecutionException e) {
|
|
455
|
+
ReactNativeFirebaseModule.rejectPromiseWithExceptionMap(promise, e);
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
|
|
379
460
|
@Override
|
|
380
461
|
public void on(String app, String dbURL, ReadableMap props) {
|
|
381
462
|
String key = props.getString("key");
|
|
@@ -396,15 +477,13 @@ public class NativeRNFBTurboDatabaseQuery extends NativeRNFBTurboDatabaseQuerySp
|
|
|
396
477
|
|
|
397
478
|
@Override
|
|
398
479
|
public void off(String queryKey, String eventRegistrationKey) {
|
|
399
|
-
|
|
480
|
+
DatabaseQueryHandle handle = queryMap.get(queryKey);
|
|
400
481
|
|
|
401
|
-
if (
|
|
482
|
+
if (handle instanceof ReactNativeFirebaseDatabaseQuery) {
|
|
483
|
+
ReactNativeFirebaseDatabaseQuery databaseQuery = (ReactNativeFirebaseDatabaseQuery) handle;
|
|
402
484
|
databaseQuery.removeEventListener(eventRegistrationKey);
|
|
403
485
|
turboSupport.removeEventListeningExecutor(eventRegistrationKey);
|
|
404
|
-
|
|
405
|
-
if (!databaseQuery.hasListeners()) {
|
|
406
|
-
queryMap.remove(queryKey);
|
|
407
|
-
}
|
|
486
|
+
queryMap.takeIfIdle(queryKey);
|
|
408
487
|
}
|
|
409
488
|
}
|
|
410
489
|
|
|
@@ -418,7 +497,15 @@ public class NativeRNFBTurboDatabaseQuery extends NativeRNFBTurboDatabaseQuerySp
|
|
|
418
497
|
boolean enabled,
|
|
419
498
|
Promise promise) {
|
|
420
499
|
DatabaseReference reference = getDatabaseForApp(app, dbURL).getReference(path);
|
|
421
|
-
getDatabaseQueryInstance(key, reference, modifiers).query
|
|
422
|
-
|
|
500
|
+
Query query = getDatabaseQueryInstance(key, reference, modifiers).query;
|
|
501
|
+
// Resolve only after the SDK apply runs (now, or after endNativeGet when deferred).
|
|
502
|
+
keepSyncedRegistry.keepSynced(
|
|
503
|
+
locationKey(app, reference),
|
|
504
|
+
key,
|
|
505
|
+
enabled,
|
|
506
|
+
() -> {
|
|
507
|
+
query.keepSynced(enabled);
|
|
508
|
+
promise.resolve(null);
|
|
509
|
+
});
|
|
423
510
|
}
|
|
424
511
|
}
|
|
@@ -20,7 +20,6 @@ package io.invertase.firebase.database;
|
|
|
20
20
|
import static io.invertase.firebase.database.UniversalFirebaseDatabaseCommon.getDatabaseForApp;
|
|
21
21
|
|
|
22
22
|
import android.os.AsyncTask;
|
|
23
|
-
import android.util.SparseArray;
|
|
24
23
|
import com.facebook.fbreact.specs.NativeRNFBTurboDatabaseTransactionSpec;
|
|
25
24
|
import com.facebook.react.bridge.ReactApplicationContext;
|
|
26
25
|
import com.facebook.react.bridge.ReadableMap;
|
|
@@ -31,8 +30,8 @@ import javax.annotation.Nonnull;
|
|
|
31
30
|
|
|
32
31
|
public class NativeRNFBTurboDatabaseTransaction extends NativeRNFBTurboDatabaseTransactionSpec {
|
|
33
32
|
private static final String SERVICE_NAME = "DatabaseTransaction";
|
|
34
|
-
private static
|
|
35
|
-
new
|
|
33
|
+
private static final RNFBDatabaseTransactionRegistry transactionHandlers =
|
|
34
|
+
new RNFBDatabaseTransactionRegistry();
|
|
36
35
|
private final DatabaseTurboModuleSupport turboSupport =
|
|
37
36
|
new DatabaseTurboModuleSupport("RNFBDatabaseTransaction");
|
|
38
37
|
|
|
@@ -42,17 +41,7 @@ public class NativeRNFBTurboDatabaseTransaction extends NativeRNFBTurboDatabaseT
|
|
|
42
41
|
|
|
43
42
|
@Override
|
|
44
43
|
public void invalidate() {
|
|
45
|
-
|
|
46
|
-
int key = transactionHandlers.keyAt(i);
|
|
47
|
-
ReactNativeFirebaseDatabaseTransactionHandler transactionHandler =
|
|
48
|
-
transactionHandlers.get(key);
|
|
49
|
-
|
|
50
|
-
if (transactionHandler != null) {
|
|
51
|
-
transactionHandler.abort();
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
transactionHandlers.clear();
|
|
44
|
+
transactionHandlers.takeAllAndAbort();
|
|
56
45
|
turboSupport.invalidate();
|
|
57
46
|
}
|
|
58
47
|
|
|
@@ -71,7 +60,7 @@ public class NativeRNFBTurboDatabaseTransaction extends NativeRNFBTurboDatabaseT
|
|
|
71
60
|
final ReactNativeFirebaseDatabaseTransactionHandler transactionHandler =
|
|
72
61
|
new ReactNativeFirebaseDatabaseTransactionHandler(
|
|
73
62
|
(int) transactionId, app, dbURL);
|
|
74
|
-
transactionHandlers.
|
|
63
|
+
transactionHandlers.registerReplacing((int) transactionId, transactionHandler);
|
|
75
64
|
final WritableMap updatesMap = transactionHandler.createUpdateMap(mutableData);
|
|
76
65
|
|
|
77
66
|
AsyncTask.execute(
|
|
@@ -109,14 +98,15 @@ public class NativeRNFBTurboDatabaseTransaction extends NativeRNFBTurboDatabaseT
|
|
|
109
98
|
@Override
|
|
110
99
|
public void onComplete(
|
|
111
100
|
DatabaseError error, boolean committed, DataSnapshot snapshot) {
|
|
112
|
-
|
|
113
|
-
transactionHandlers.get((int) transactionId);
|
|
101
|
+
DatabaseAbortable abortable = transactionHandlers.take((int) transactionId);
|
|
114
102
|
|
|
115
|
-
if (
|
|
116
|
-
transactionHandlers.delete((int) transactionId);
|
|
103
|
+
if (!(abortable instanceof ReactNativeFirebaseDatabaseTransactionHandler)) {
|
|
117
104
|
return;
|
|
118
105
|
}
|
|
119
106
|
|
|
107
|
+
ReactNativeFirebaseDatabaseTransactionHandler transactionHandler =
|
|
108
|
+
(ReactNativeFirebaseDatabaseTransactionHandler) abortable;
|
|
109
|
+
|
|
120
110
|
WritableMap resultMap =
|
|
121
111
|
transactionHandler.createResultMap(error, committed, snapshot);
|
|
122
112
|
|
|
@@ -129,8 +119,6 @@ public class NativeRNFBTurboDatabaseTransaction extends NativeRNFBTurboDatabaseT
|
|
|
129
119
|
resultMap,
|
|
130
120
|
app,
|
|
131
121
|
(int) transactionId));
|
|
132
|
-
|
|
133
|
-
transactionHandlers.delete((int) transactionId);
|
|
134
122
|
}
|
|
135
123
|
},
|
|
136
124
|
applyLocally);
|
|
@@ -140,11 +128,10 @@ public class NativeRNFBTurboDatabaseTransaction extends NativeRNFBTurboDatabaseT
|
|
|
140
128
|
@Override
|
|
141
129
|
public void transactionTryCommit(
|
|
142
130
|
String app, String dbURL, double transactionId, ReadableMap updates) {
|
|
143
|
-
|
|
144
|
-
transactionHandlers.get((int) transactionId);
|
|
131
|
+
DatabaseAbortable abortable = transactionHandlers.get((int) transactionId);
|
|
145
132
|
|
|
146
|
-
if (
|
|
147
|
-
|
|
133
|
+
if (abortable instanceof ReactNativeFirebaseDatabaseTransactionHandler) {
|
|
134
|
+
((ReactNativeFirebaseDatabaseTransactionHandler) abortable).signalUpdateReceived(updates);
|
|
148
135
|
}
|
|
149
136
|
}
|
|
150
137
|
}
|
|
@@ -25,15 +25,14 @@ import com.google.firebase.database.ChildEventListener;
|
|
|
25
25
|
import com.google.firebase.database.DatabaseReference;
|
|
26
26
|
import com.google.firebase.database.Query;
|
|
27
27
|
import com.google.firebase.database.ValueEventListener;
|
|
28
|
-
import
|
|
29
|
-
import java.util.
|
|
28
|
+
import io.invertase.firebase.common.RNFBHandleCollisionException;
|
|
29
|
+
import java.util.List;
|
|
30
30
|
import java.util.Map;
|
|
31
31
|
|
|
32
|
-
public class ReactNativeFirebaseDatabaseQuery {
|
|
32
|
+
public class ReactNativeFirebaseDatabaseQuery implements DatabaseQueryHandle {
|
|
33
33
|
|
|
34
34
|
public Query query;
|
|
35
|
-
|
|
36
|
-
private HashMap<String, ValueEventListener> valueEventListeners = new HashMap<>();
|
|
35
|
+
final RNFBDatabaseListenerRegistry listeners = new RNFBDatabaseListenerRegistry();
|
|
37
36
|
|
|
38
37
|
ReactNativeFirebaseDatabaseQuery(DatabaseReference reference, ReadableArray modifiers) {
|
|
39
38
|
this.query = reference;
|
|
@@ -78,7 +77,11 @@ public class ReactNativeFirebaseDatabaseQuery {
|
|
|
78
77
|
* @param listener
|
|
79
78
|
*/
|
|
80
79
|
public void addEventListener(String eventRegistrationKey, ValueEventListener listener) {
|
|
81
|
-
|
|
80
|
+
try {
|
|
81
|
+
listeners.putValue(eventRegistrationKey, listener);
|
|
82
|
+
} catch (RNFBHandleCollisionException | NullPointerException collision) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
82
85
|
query.addValueEventListener(listener);
|
|
83
86
|
}
|
|
84
87
|
|
|
@@ -89,7 +92,11 @@ public class ReactNativeFirebaseDatabaseQuery {
|
|
|
89
92
|
* @param listener
|
|
90
93
|
*/
|
|
91
94
|
public void addEventListener(String eventRegistrationKey, ChildEventListener listener) {
|
|
92
|
-
|
|
95
|
+
try {
|
|
96
|
+
listeners.putChild(eventRegistrationKey, listener);
|
|
97
|
+
} catch (RNFBHandleCollisionException | NullPointerException collision) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
93
100
|
query.addChildEventListener(listener);
|
|
94
101
|
}
|
|
95
102
|
|
|
@@ -117,36 +124,26 @@ public class ReactNativeFirebaseDatabaseQuery {
|
|
|
117
124
|
* @param eventRegistrationKey
|
|
118
125
|
*/
|
|
119
126
|
public void removeEventListener(String eventRegistrationKey) {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
127
|
+
Object valueListener = listeners.takeValue(eventRegistrationKey);
|
|
128
|
+
if (valueListener instanceof ValueEventListener) {
|
|
129
|
+
query.removeEventListener((ValueEventListener) valueListener);
|
|
123
130
|
}
|
|
124
131
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
132
|
+
Object childListener = listeners.takeChild(eventRegistrationKey);
|
|
133
|
+
if (childListener instanceof ChildEventListener) {
|
|
134
|
+
query.removeEventListener((ChildEventListener) childListener);
|
|
128
135
|
}
|
|
129
136
|
}
|
|
130
137
|
|
|
131
138
|
/** Iterates over all current event listeners on the current query and removes each one */
|
|
139
|
+
@Override
|
|
132
140
|
public void removeAllEventListeners() {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
query.removeEventListener(valueEventListener);
|
|
140
|
-
valueIterator.remove();
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
Iterator childIterator = childEventListeners.entrySet().iterator();
|
|
144
|
-
|
|
145
|
-
while (childIterator.hasNext()) {
|
|
146
|
-
Map.Entry pair = (Map.Entry) childIterator.next();
|
|
147
|
-
ChildEventListener childEventListener = (ChildEventListener) pair.getValue();
|
|
148
|
-
query.removeEventListener(childEventListener);
|
|
149
|
-
childIterator.remove();
|
|
141
|
+
List<Object> remaining = listeners.takeAll();
|
|
142
|
+
for (Object listener : remaining) {
|
|
143
|
+
if (listener instanceof ValueEventListener) {
|
|
144
|
+
query.removeEventListener((ValueEventListener) listener);
|
|
145
|
+
} else if (listener instanceof ChildEventListener) {
|
|
146
|
+
query.removeEventListener((ChildEventListener) listener);
|
|
150
147
|
}
|
|
151
148
|
}
|
|
152
149
|
}
|
|
@@ -158,8 +155,7 @@ public class ReactNativeFirebaseDatabaseQuery {
|
|
|
158
155
|
* @return
|
|
159
156
|
*/
|
|
160
157
|
public Boolean hasEventListener(String eventRegistrationKey) {
|
|
161
|
-
return
|
|
162
|
-
|| childEventListeners.containsKey(eventRegistrationKey);
|
|
158
|
+
return listeners.hasEventListener(eventRegistrationKey);
|
|
163
159
|
}
|
|
164
160
|
|
|
165
161
|
/**
|
|
@@ -167,8 +163,9 @@ public class ReactNativeFirebaseDatabaseQuery {
|
|
|
167
163
|
*
|
|
168
164
|
* @return
|
|
169
165
|
*/
|
|
166
|
+
@Override
|
|
170
167
|
public Boolean hasListeners() {
|
|
171
|
-
return
|
|
168
|
+
return listeners.hasListeners();
|
|
172
169
|
}
|
|
173
170
|
|
|
174
171
|
/**
|
|
@@ -32,7 +32,7 @@ import java.util.concurrent.locks.Condition;
|
|
|
32
32
|
import java.util.concurrent.locks.ReentrantLock;
|
|
33
33
|
import javax.annotation.Nullable;
|
|
34
34
|
|
|
35
|
-
public class ReactNativeFirebaseDatabaseTransactionHandler {
|
|
35
|
+
public class ReactNativeFirebaseDatabaseTransactionHandler implements DatabaseAbortable {
|
|
36
36
|
private final ReentrantLock lock;
|
|
37
37
|
private final Condition condition;
|
|
38
38
|
public Object value;
|
|
@@ -81,8 +81,8 @@ public class ReactNativeFirebaseDatabaseTransactionHandler {
|
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
|
|
85
|
-
void abort() {
|
|
84
|
+
@Override
|
|
85
|
+
public void abort() {
|
|
86
86
|
lock.lock();
|
|
87
87
|
try {
|
|
88
88
|
abort = true;
|
|
@@ -38,6 +38,10 @@ public abstract class NativeRNFBTurboDatabaseQuerySpec extends ReactContextBaseJ
|
|
|
38
38
|
@DoNotStrip
|
|
39
39
|
public abstract void once(String app, String dbURL, String path, ReadableArray modifiers, String eventType, Promise promise);
|
|
40
40
|
|
|
41
|
+
@ReactMethod
|
|
42
|
+
@DoNotStrip
|
|
43
|
+
public abstract void get(String app, String dbURL, String path, ReadableArray modifiers, Promise promise);
|
|
44
|
+
|
|
41
45
|
@ReactMethod
|
|
42
46
|
@DoNotStrip
|
|
43
47
|
public abstract void on(String app, String dbURL, ReadableMap props);
|
|
@@ -89,6 +89,11 @@ static facebook::jsi::Value __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_o
|
|
|
89
89
|
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "once", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Ljava/lang/String;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
static facebook::jsi::Value __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_get(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
93
|
+
static jmethodID cachedMethodId = nullptr;
|
|
94
|
+
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, PromiseKind, "get", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableArray;Lcom/facebook/react/bridge/Promise;)V", args, count, cachedMethodId);
|
|
95
|
+
}
|
|
96
|
+
|
|
92
97
|
static facebook::jsi::Value __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_on(facebook::jsi::Runtime& rt, TurboModule &turboModule, const facebook::jsi::Value* args, size_t count) {
|
|
93
98
|
static jmethodID cachedMethodId = nullptr;
|
|
94
99
|
return static_cast<JavaTurboModule &>(turboModule).invokeJavaMethod(rt, VoidKind, "on", "(Ljava/lang/String;Ljava/lang/String;Lcom/facebook/react/bridge/ReadableMap;)V", args, count, cachedMethodId);
|
|
@@ -107,6 +112,7 @@ static facebook::jsi::Value __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_k
|
|
|
107
112
|
NativeRNFBTurboDatabaseQuerySpecJSI::NativeRNFBTurboDatabaseQuerySpecJSI(const JavaTurboModule::InitParams ¶ms)
|
|
108
113
|
: JavaTurboModule(params) {
|
|
109
114
|
methodMap_["once"] = MethodMetadata {5, __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_once};
|
|
115
|
+
methodMap_["get"] = MethodMetadata {4, __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_get};
|
|
110
116
|
methodMap_["on"] = MethodMetadata {3, __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_on};
|
|
111
117
|
methodMap_["off"] = MethodMetadata {2, __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_off};
|
|
112
118
|
methodMap_["keepSynced"] = MethodMetadata {6, __hostFunction_NativeRNFBTurboDatabaseQuerySpecJSI_keepSynced};
|
|
@@ -170,6 +170,7 @@ public:
|
|
|
170
170
|
protected:
|
|
171
171
|
NativeRNFBTurboDatabaseQueryCxxSpec(std::shared_ptr<CallInvoker> jsInvoker) : TurboModule(std::string{NativeRNFBTurboDatabaseQueryCxxSpec::kModuleName}, jsInvoker) {
|
|
172
172
|
methodMap_["once"] = MethodMetadata {.argCount = 5, .invoker = __once};
|
|
173
|
+
methodMap_["get"] = MethodMetadata {.argCount = 4, .invoker = __get};
|
|
173
174
|
methodMap_["on"] = MethodMetadata {.argCount = 3, .invoker = __on};
|
|
174
175
|
methodMap_["off"] = MethodMetadata {.argCount = 2, .invoker = __off};
|
|
175
176
|
methodMap_["keepSynced"] = MethodMetadata {.argCount = 6, .invoker = __keepSynced};
|
|
@@ -188,6 +189,17 @@ private:
|
|
|
188
189
|
count <= 4 ? throw jsi::JSError(rt, "Expected argument in position 4 to be passed") : args[4].asString(rt));
|
|
189
190
|
}
|
|
190
191
|
|
|
192
|
+
static jsi::Value __get(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
|
|
193
|
+
static_assert(
|
|
194
|
+
bridging::getParameterCount(&T::get) == 5,
|
|
195
|
+
"Expected get(...) to have 5 parameters");
|
|
196
|
+
return bridging::callFromJs<jsi::Value>(rt, &T::get, static_cast<NativeRNFBTurboDatabaseQueryCxxSpec*>(&turboModule)->jsInvoker_, static_cast<T*>(&turboModule),
|
|
197
|
+
count <= 0 ? throw jsi::JSError(rt, "Expected argument in position 0 to be passed") : args[0].asString(rt),
|
|
198
|
+
count <= 1 ? throw jsi::JSError(rt, "Expected argument in position 1 to be passed") : args[1].asString(rt),
|
|
199
|
+
count <= 2 ? throw jsi::JSError(rt, "Expected argument in position 2 to be passed") : args[2].asString(rt),
|
|
200
|
+
count <= 3 ? throw jsi::JSError(rt, "Expected argument in position 3 to be passed") : args[3].asObject(rt).asArray(rt));
|
|
201
|
+
}
|
|
202
|
+
|
|
191
203
|
static jsi::Value __on(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
|
|
192
204
|
static_assert(
|
|
193
205
|
bridging::getParameterCount(&T::on) == 4,
|