@react-native-firebase/database 20.1.0 → 20.2.1
Sign up to get free protection for your applications and to get access to all the features.
- package/CHANGELOG.md +14 -0
- package/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseCommon.java +23 -5
- package/ios/RNFBDatabase/RNFBDatabaseCommon.m +10 -3
- package/lib/DatabaseDataSnapshot.js +15 -1
- package/lib/DatabaseSyncTree.js +2 -2
- package/lib/DatabaseTransaction.js +6 -1
- package/lib/index.js +6 -0
- package/lib/version.js +1 -1
- package/lib/web/RNFBDatabaseModule.android.js +2 -0
- package/lib/web/RNFBDatabaseModule.ios.js +2 -0
- package/lib/web/RNFBDatabaseModule.js +545 -0
- package/lib/web/query.js +71 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
@@ -3,6 +3,20 @@
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
5
5
|
|
6
|
+
## [20.2.1](https://github.com/invertase/react-native-firebase/compare/v20.2.0...v20.2.1) (2024-07-17)
|
7
|
+
|
8
|
+
**Note:** Version bump only for package @react-native-firebase/database
|
9
|
+
|
10
|
+
## [20.2.0](https://github.com/invertase/react-native-firebase/compare/v20.1.0...v20.2.0) (2024-07-15)
|
11
|
+
|
12
|
+
### Features
|
13
|
+
|
14
|
+
- **other:** Add Database support ([#7887](https://github.com/invertase/react-native-firebase/issues/7887)) ([fbb773a](https://github.com/invertase/react-native-firebase/commit/fbb773a87c167bdc92265fe261aeb777d4660cd7))
|
15
|
+
|
16
|
+
### Bug Fixes
|
17
|
+
|
18
|
+
- **database:** set priority on child snapshot if available ([#7897](https://github.com/invertase/react-native-firebase/issues/7897)) ([9028ae4](https://github.com/invertase/react-native-firebase/commit/9028ae4785eb17239ae2ab49d343a39c01a349e7))
|
19
|
+
|
6
20
|
## [20.1.0](https://github.com/invertase/react-native-firebase/compare/v20.0.0...v20.1.0) (2024-06-04)
|
7
21
|
|
8
22
|
**Note:** Version bump only for package @react-native-firebase/database
|
@@ -24,10 +24,13 @@ import android.util.Log;
|
|
24
24
|
import com.facebook.react.bridge.*;
|
25
25
|
import com.google.firebase.database.DataSnapshot;
|
26
26
|
import com.google.firebase.database.MutableData;
|
27
|
+
import java.util.HashMap;
|
27
28
|
import javax.annotation.Nullable;
|
28
29
|
|
29
30
|
public class ReactNativeFirebaseDatabaseCommon {
|
30
31
|
private static final String TAG = "DatabaseCommon";
|
32
|
+
private static final String childPrioritiesKey = "childPriorities";
|
33
|
+
private static final String childKeysKey = "childKeys";
|
31
34
|
|
32
35
|
/**
|
33
36
|
* @param promise
|
@@ -61,12 +64,13 @@ public class ReactNativeFirebaseDatabaseCommon {
|
|
61
64
|
*/
|
62
65
|
public static WritableMap snapshotToMap(DataSnapshot dataSnapshot) {
|
63
66
|
WritableMap snapshot = Arguments.createMap();
|
64
|
-
|
67
|
+
HashMap<String, Object> childProperties = getChildProperties(dataSnapshot);
|
65
68
|
snapshot.putString("key", dataSnapshot.getKey());
|
66
69
|
snapshot.putBoolean("exists", dataSnapshot.exists());
|
67
70
|
snapshot.putBoolean("hasChildren", dataSnapshot.hasChildren());
|
68
71
|
snapshot.putDouble("childrenCount", dataSnapshot.getChildrenCount());
|
69
|
-
snapshot.putArray(
|
72
|
+
snapshot.putArray(childKeysKey, (ReadableArray) childProperties.get(childKeysKey));
|
73
|
+
snapshot.putMap(childPrioritiesKey, (WritableMap) childProperties.get(childPrioritiesKey));
|
70
74
|
mapPutValue("priority", dataSnapshot.getPriority(), snapshot);
|
71
75
|
|
72
76
|
if (!dataSnapshot.hasChildren()) {
|
@@ -369,15 +373,29 @@ public class ReactNativeFirebaseDatabaseCommon {
|
|
369
373
|
* @param snapshot
|
370
374
|
* @return
|
371
375
|
*/
|
372
|
-
public static
|
376
|
+
public static HashMap<String, Object> getChildProperties(DataSnapshot snapshot) {
|
373
377
|
WritableArray childKeys = Arguments.createArray();
|
374
|
-
|
378
|
+
WritableMap childPriorities = Arguments.createMap();
|
379
|
+
HashMap<String, Object> childProperties = new HashMap<>();
|
375
380
|
if (snapshot.hasChildren()) {
|
376
381
|
for (DataSnapshot child : snapshot.getChildren()) {
|
377
382
|
childKeys.pushString(child.getKey());
|
383
|
+
|
384
|
+
Object priority = child.getPriority();
|
385
|
+
// Priority can be String, Double or null
|
386
|
+
if (priority instanceof String) {
|
387
|
+
childPriorities.putString(child.getKey(), (String) priority);
|
388
|
+
} else if (priority instanceof Double) {
|
389
|
+
childPriorities.putDouble(child.getKey(), (Double) priority);
|
390
|
+
} else if (priority == null) {
|
391
|
+
childPriorities.putNull(child.getKey());
|
392
|
+
}
|
378
393
|
}
|
379
394
|
}
|
380
395
|
|
381
|
-
|
396
|
+
childProperties.put(childKeysKey, childKeys);
|
397
|
+
childProperties.put(childPrioritiesKey, childPriorities);
|
398
|
+
|
399
|
+
return childProperties;
|
382
400
|
}
|
383
401
|
}
|
@@ -26,6 +26,9 @@ NSString *const DATABASE_PERSISTENCE_ENABLED = @"firebase_database_persistence_e
|
|
26
26
|
NSString *const DATABASE_LOGGING_ENABLED = @"firebase_database_logging_enabled";
|
27
27
|
NSString *const DATABASE_PERSISTENCE_CACHE_SIZE = @"firebase_database_persistence_cache_size_bytes";
|
28
28
|
|
29
|
+
NSString *const childPrioritiesKey = @"childPriorities";
|
30
|
+
NSString *const childKeysKey = @"childKeys";
|
31
|
+
|
29
32
|
@implementation RNFBDatabaseCommon
|
30
33
|
|
31
34
|
+ (void)load {
|
@@ -250,28 +253,32 @@ NSString *const DATABASE_PERSISTENCE_CACHE_SIZE = @"firebase_database_persistenc
|
|
250
253
|
} else {
|
251
254
|
[snapshot setValue:[NSNull null] forKey:@"key"];
|
252
255
|
}
|
256
|
+
NSMutableDictionary *childProperties = [self getSnapshotChildProperties:dataSnapshot];
|
253
257
|
[snapshot setValue:@(dataSnapshot.exists) forKey:@"exists"];
|
254
258
|
[snapshot setValue:@(dataSnapshot.hasChildren) forKey:@"hasChildren"];
|
255
259
|
[snapshot setValue:@(dataSnapshot.childrenCount) forKey:@"childrenCount"];
|
256
|
-
[snapshot setValue:[
|
260
|
+
[snapshot setValue:childProperties[childKeysKey] forKey:childKeysKey];
|
261
|
+
[snapshot setValue:childProperties[childPrioritiesKey] forKey:childPrioritiesKey];
|
257
262
|
[snapshot setValue:dataSnapshot.priority forKey:@"priority"];
|
258
263
|
[snapshot setValue:dataSnapshot.value forKey:@"value"];
|
259
264
|
|
260
265
|
return snapshot;
|
261
266
|
}
|
262
267
|
|
263
|
-
+ (
|
268
|
+
+ (NSMutableDictionary *)getSnapshotChildProperties:(FIRDataSnapshot *)dataSnapshot {
|
264
269
|
NSMutableArray *childKeys = [NSMutableArray array];
|
270
|
+
NSMutableDictionary *childPriorities = [[NSMutableDictionary alloc] init];
|
265
271
|
if (dataSnapshot.childrenCount > 0) {
|
266
272
|
NSEnumerator *children = [dataSnapshot children];
|
267
273
|
FIRDataSnapshot *child;
|
268
274
|
child = [children nextObject];
|
269
275
|
while (child) {
|
270
276
|
[childKeys addObject:child.key];
|
277
|
+
[childPriorities setValue:child.priority forKey:child.key];
|
271
278
|
child = [children nextObject];
|
272
279
|
}
|
273
280
|
}
|
274
|
-
return childKeys;
|
281
|
+
return @{childKeysKey : childKeys, childPrioritiesKey : childPriorities};
|
275
282
|
}
|
276
283
|
|
277
284
|
@end
|
@@ -15,7 +15,13 @@
|
|
15
15
|
*
|
16
16
|
*/
|
17
17
|
|
18
|
-
import {
|
18
|
+
import {
|
19
|
+
isArray,
|
20
|
+
isFunction,
|
21
|
+
isObject,
|
22
|
+
isString,
|
23
|
+
isNumber,
|
24
|
+
} from '@react-native-firebase/app/lib/common';
|
19
25
|
import { deepGet } from '@react-native-firebase/app/lib/common/deeps';
|
20
26
|
|
21
27
|
export default class DatabaseDataSnapshot {
|
@@ -61,11 +67,19 @@ export default class DatabaseDataSnapshot {
|
|
61
67
|
|
62
68
|
const childRef = this._ref.child(path);
|
63
69
|
|
70
|
+
let childPriority = null;
|
71
|
+
if (this._snapshot.childPriorities) {
|
72
|
+
const childPriorityValue = this._snapshot.childPriorities[childRef.key];
|
73
|
+
if (isString(childPriorityValue) || isNumber(childPriorityValue)) {
|
74
|
+
childPriority = childPriorityValue;
|
75
|
+
}
|
76
|
+
}
|
64
77
|
return new DatabaseDataSnapshot(childRef, {
|
65
78
|
value,
|
66
79
|
key: childRef.key,
|
67
80
|
exists: value !== null,
|
68
81
|
childKeys: isObject(value) ? Object.keys(value) : [],
|
82
|
+
priority: childPriority,
|
69
83
|
});
|
70
84
|
}
|
71
85
|
|
package/lib/DatabaseSyncTree.js
CHANGED
@@ -16,9 +16,9 @@
|
|
16
16
|
*/
|
17
17
|
|
18
18
|
import { isString } from '@react-native-firebase/app/lib/common';
|
19
|
+
import { getReactNativeModule } from '@react-native-firebase/app/lib/internal/nativeModule';
|
19
20
|
import NativeError from '@react-native-firebase/app/lib/internal/NativeFirebaseError';
|
20
21
|
import SharedEventEmitter from '@react-native-firebase/app/lib/internal/SharedEventEmitter';
|
21
|
-
import { NativeModules } from 'react-native';
|
22
22
|
import DatabaseDataSnapshot from './DatabaseDataSnapshot';
|
23
23
|
|
24
24
|
class DatabaseSyncTree {
|
@@ -39,7 +39,7 @@ class DatabaseSyncTree {
|
|
39
39
|
}
|
40
40
|
|
41
41
|
get native() {
|
42
|
-
return
|
42
|
+
return getReactNativeModule('RNFBDatabaseQueryModule');
|
43
43
|
}
|
44
44
|
|
45
45
|
// from upstream EventEmitter: initialize registrations for an emitter key
|
@@ -16,6 +16,7 @@
|
|
16
16
|
*/
|
17
17
|
|
18
18
|
import NativeError from '@react-native-firebase/app/lib/internal/NativeFirebaseError';
|
19
|
+
import { isOther } from '@react-native-firebase/app/lib/common';
|
19
20
|
|
20
21
|
let transactionId = 0;
|
21
22
|
|
@@ -59,7 +60,11 @@ export default class DatabaseTransaction {
|
|
59
60
|
started: true,
|
60
61
|
};
|
61
62
|
|
62
|
-
|
63
|
+
if (isOther) {
|
64
|
+
this._database.native.transactionStart(reference.path, id, applyLocally, transactionUpdater);
|
65
|
+
} else {
|
66
|
+
this._database.native.transactionStart(reference.path, id, applyLocally);
|
67
|
+
}
|
63
68
|
}
|
64
69
|
|
65
70
|
/**
|
package/lib/index.js
CHANGED
@@ -21,10 +21,12 @@ import {
|
|
21
21
|
FirebaseModule,
|
22
22
|
getFirebaseRoot,
|
23
23
|
} from '@react-native-firebase/app/lib/internal';
|
24
|
+
import { setReactNativeModule } from '@react-native-firebase/app/lib/internal/nativeModule';
|
24
25
|
import DatabaseReference from './DatabaseReference';
|
25
26
|
import DatabaseStatics from './DatabaseStatics';
|
26
27
|
import DatabaseTransaction from './DatabaseTransaction';
|
27
28
|
import version from './version';
|
29
|
+
import fallBackModule from './web/RNFBDatabaseModule';
|
28
30
|
|
29
31
|
const namespace = 'database';
|
30
32
|
|
@@ -222,3 +224,7 @@ export * from './modular';
|
|
222
224
|
// database().X(...);
|
223
225
|
// firebase.database().X(...);
|
224
226
|
export const firebase = getFirebaseRoot();
|
227
|
+
|
228
|
+
for (let i = 0; i < nativeModuleName.length; i++) {
|
229
|
+
setReactNativeModule(nativeModuleName[i], fallBackModule);
|
230
|
+
}
|
package/lib/version.js
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
// Generated by genversion.
|
2
|
-
module.exports = '20.1
|
2
|
+
module.exports = '20.2.1';
|
@@ -0,0 +1,545 @@
|
|
1
|
+
import {
|
2
|
+
getApp,
|
3
|
+
getDatabase,
|
4
|
+
connectDatabaseEmulator,
|
5
|
+
enableLogging,
|
6
|
+
goOnline,
|
7
|
+
goOffline,
|
8
|
+
ref,
|
9
|
+
set,
|
10
|
+
update,
|
11
|
+
setWithPriority,
|
12
|
+
remove,
|
13
|
+
setPriority,
|
14
|
+
onDisconnect,
|
15
|
+
onValue,
|
16
|
+
onChildAdded,
|
17
|
+
onChildChanged,
|
18
|
+
onChildMoved,
|
19
|
+
onChildRemoved,
|
20
|
+
runTransaction,
|
21
|
+
} from '@react-native-firebase/app/lib/internal/web/firebaseDatabase';
|
22
|
+
import { guard, getWebError, emitEvent } from '@react-native-firebase/app/lib/internal/web/utils';
|
23
|
+
import { getQueryInstance } from './query';
|
24
|
+
|
25
|
+
// Converts a DataSnapshot to an object.
|
26
|
+
function snapshotToObject(snapshot) {
|
27
|
+
const childKeys = [];
|
28
|
+
|
29
|
+
if (snapshot.hasChildren()) {
|
30
|
+
snapshot.forEach(childSnapshot => {
|
31
|
+
childKeys.push(childSnapshot.key);
|
32
|
+
});
|
33
|
+
}
|
34
|
+
|
35
|
+
return {
|
36
|
+
key: snapshot.key,
|
37
|
+
exists: snapshot.exists(),
|
38
|
+
hasChildren: snapshot.hasChildren(),
|
39
|
+
childrenCount: snapshot.size,
|
40
|
+
childKeys,
|
41
|
+
priority: snapshot.priority,
|
42
|
+
value: snapshot.val(),
|
43
|
+
};
|
44
|
+
}
|
45
|
+
|
46
|
+
function getDatabaseWebError(error) {
|
47
|
+
// Possible to override messages/codes here if necessary.
|
48
|
+
return getWebError(error);
|
49
|
+
}
|
50
|
+
|
51
|
+
// Converts a DataSnapshot and previous child name to an object.
|
52
|
+
function snapshotWithPreviousChildToObject(snapshot, previousChildName) {
|
53
|
+
return {
|
54
|
+
snapshot: snapshotToObject(snapshot),
|
55
|
+
previousChildName,
|
56
|
+
};
|
57
|
+
}
|
58
|
+
|
59
|
+
const appInstances = {};
|
60
|
+
const databaseInstances = {};
|
61
|
+
const onDisconnectRef = {};
|
62
|
+
const listeners = {};
|
63
|
+
const emulatorForApp = {};
|
64
|
+
|
65
|
+
function getCachedAppInstance(appName) {
|
66
|
+
return (appInstances[appName] ??= getApp(appName));
|
67
|
+
}
|
68
|
+
|
69
|
+
// Returns a cached Database instance.
|
70
|
+
function getCachedDatabaseInstance(appName, dbURL) {
|
71
|
+
let instance = databaseInstances[`${appName}|${dbURL}`];
|
72
|
+
if (!instance) {
|
73
|
+
instance = getDatabase(getCachedAppInstance(appName), dbURL);
|
74
|
+
// Relying on internals here so need to be careful between SDK versions.
|
75
|
+
if (emulatorForApp[appName] && !instance._instanceStarted) {
|
76
|
+
const { host, port } = emulatorForApp[appName];
|
77
|
+
connectDatabaseEmulator(instance, host, port);
|
78
|
+
emulatorForApp[appName].connected = true;
|
79
|
+
}
|
80
|
+
}
|
81
|
+
return instance;
|
82
|
+
}
|
83
|
+
|
84
|
+
// Returns a cached onDisconnect instance.
|
85
|
+
function getCachedOnDisconnectInstance(ref) {
|
86
|
+
return (onDisconnectRef[ref.key] ??= onDisconnect(ref));
|
87
|
+
}
|
88
|
+
|
89
|
+
export default {
|
90
|
+
/**
|
91
|
+
* Reconnects to the server.
|
92
|
+
* @param {string} appName - The app name.
|
93
|
+
* @param {string} dbURL - The database URL.
|
94
|
+
* @returns {Promise<void>}
|
95
|
+
*/
|
96
|
+
goOnline(appName, dbURL) {
|
97
|
+
return guard(async () => {
|
98
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
99
|
+
goOnline(db);
|
100
|
+
});
|
101
|
+
},
|
102
|
+
|
103
|
+
/**
|
104
|
+
* Disconnects from the server.
|
105
|
+
* @param {string} appName - The app name.
|
106
|
+
* @param {string} dbURL - The database URL.
|
107
|
+
* @returns {Promise<void>}
|
108
|
+
*/
|
109
|
+
goOffline(appName, dbURL) {
|
110
|
+
return guard(async () => {
|
111
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
112
|
+
goOffline(db);
|
113
|
+
});
|
114
|
+
},
|
115
|
+
|
116
|
+
setPersistenceEnabled() {
|
117
|
+
if (__DEV__) {
|
118
|
+
// eslint-disable-next-line no-console
|
119
|
+
console.warn(
|
120
|
+
'The Firebase Database `setPersistenceEnabled` method is not available in the this environment.',
|
121
|
+
);
|
122
|
+
}
|
123
|
+
return Promise.resolve();
|
124
|
+
},
|
125
|
+
|
126
|
+
/**
|
127
|
+
* Sets the logging enabled state.
|
128
|
+
* @param {string} appName - The app name, not used.
|
129
|
+
* @param {string} dbURL - The database URL, not used.
|
130
|
+
* @param {boolean} enabled - The logging enabled state.
|
131
|
+
*/
|
132
|
+
setLoggingEnabled(app, dbURL, enabled) {
|
133
|
+
return guard(async () => {
|
134
|
+
enableLogging(enabled);
|
135
|
+
});
|
136
|
+
},
|
137
|
+
|
138
|
+
setPersistenceCacheSizeBytes() {
|
139
|
+
// no-op on other platforms
|
140
|
+
return Promise.resolve();
|
141
|
+
},
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Connects to the Firebase database emulator.
|
145
|
+
* @param {string} appName - The app name.
|
146
|
+
* @param {string} dbURL - The database URL.
|
147
|
+
* @param {string} host - The emulator host.
|
148
|
+
* @param {number} port - The emulator
|
149
|
+
* @returns {Promise<void>}
|
150
|
+
*/
|
151
|
+
useEmulator(appName, dbURL, host, port) {
|
152
|
+
return guard(async () => {
|
153
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
154
|
+
connectDatabaseEmulator(db, host, port);
|
155
|
+
emulatorForApp[appName] = { host, port };
|
156
|
+
});
|
157
|
+
},
|
158
|
+
|
159
|
+
/**
|
160
|
+
* Reference
|
161
|
+
*/
|
162
|
+
|
163
|
+
/**
|
164
|
+
* Sets a value at the specified path.
|
165
|
+
* @param {string} appName - The app name.
|
166
|
+
* @param {string} dbURL - The database URL.
|
167
|
+
* @param {string} path - The path.
|
168
|
+
* @param {object} props - The properties
|
169
|
+
* @returns {Promise<void>}
|
170
|
+
*/
|
171
|
+
set(appName, dbURL, path, props) {
|
172
|
+
return guard(async () => {
|
173
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
174
|
+
const dbRef = ref(db, path);
|
175
|
+
const value = props.value;
|
176
|
+
await set(dbRef, value);
|
177
|
+
});
|
178
|
+
},
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Updates the specified path with the provided values.
|
182
|
+
* @param {string} appName - The app name.
|
183
|
+
* @param {string} dbURL - The database URL.
|
184
|
+
* @param {string} path - The path.
|
185
|
+
* @param {object} props - The properties
|
186
|
+
* @returns {Promise<void>}
|
187
|
+
*/
|
188
|
+
update(appName, dbURL, path, props) {
|
189
|
+
return guard(async () => {
|
190
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
191
|
+
const dbRef = ref(db, path);
|
192
|
+
const values = props.values;
|
193
|
+
await update(dbRef, values);
|
194
|
+
});
|
195
|
+
},
|
196
|
+
|
197
|
+
/**
|
198
|
+
* Sets a value at the specified path with a priority.
|
199
|
+
* @param {string} appName - The app name.
|
200
|
+
* @param {string} dbURL - The database URL.
|
201
|
+
* @param {string} path - The path.
|
202
|
+
* @param {object} props - The properties, including value and priority.
|
203
|
+
* @returns {Promise<void>}
|
204
|
+
*/
|
205
|
+
setWithPriority(appName, dbURL, path, props) {
|
206
|
+
return guard(async () => {
|
207
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
208
|
+
const dbRef = ref(db, path);
|
209
|
+
const value = props.value;
|
210
|
+
const priority = props.priority;
|
211
|
+
await setWithPriority(dbRef, value, priority);
|
212
|
+
});
|
213
|
+
},
|
214
|
+
|
215
|
+
/**
|
216
|
+
* Removes the nodd at the specified path.
|
217
|
+
* @param {string} appName - The app name.
|
218
|
+
* @param {string} dbURL - The database URL.
|
219
|
+
* @param {string} path - The path.
|
220
|
+
* @returns {Promise<void>}
|
221
|
+
*/
|
222
|
+
remove(appName, dbURL, path) {
|
223
|
+
return guard(async () => {
|
224
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
225
|
+
const dbRef = ref(db, path);
|
226
|
+
await remove(dbRef);
|
227
|
+
});
|
228
|
+
},
|
229
|
+
|
230
|
+
/**
|
231
|
+
* Sets the priority of the node at the specified path.
|
232
|
+
* @param {string} appName - The app name.
|
233
|
+
* @param {string} dbURL - The database URL.
|
234
|
+
* @param {string} path - The path.
|
235
|
+
* @param {object} props - The properties, including priority.
|
236
|
+
* @returns {Promise<void>}
|
237
|
+
*/
|
238
|
+
setPriority(appName, dbURL, path, props) {
|
239
|
+
return guard(async () => {
|
240
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
241
|
+
const dbRef = ref(db, path);
|
242
|
+
const priority = props.priority;
|
243
|
+
await setPriority(dbRef, priority);
|
244
|
+
});
|
245
|
+
},
|
246
|
+
|
247
|
+
/**
|
248
|
+
* Query
|
249
|
+
*/
|
250
|
+
|
251
|
+
/**
|
252
|
+
* Listens for data changes at the specified path once.
|
253
|
+
* @param {string} appName - The app name.
|
254
|
+
* @param {string} dbURL - The database URL.
|
255
|
+
* @param {string} path - The path.
|
256
|
+
* @param {object} modifiers - The modifiers.
|
257
|
+
* @param {string} eventType - The event type.
|
258
|
+
* @returns {Promise<object>}
|
259
|
+
*/
|
260
|
+
once(appName, dbURL, path, modifiers, eventType) {
|
261
|
+
return guard(async () => {
|
262
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
263
|
+
const dbRef = ref(db, path);
|
264
|
+
const queryRef = getQueryInstance(dbRef, modifiers);
|
265
|
+
|
266
|
+
if (eventType === 'value') {
|
267
|
+
const snapshot = await new Promise((resolve, reject) => {
|
268
|
+
onValue(queryRef, resolve, reject, { onlyOnce: true });
|
269
|
+
});
|
270
|
+
|
271
|
+
return snapshotToObject(snapshot);
|
272
|
+
} else {
|
273
|
+
let fn = null;
|
274
|
+
|
275
|
+
if (eventType === 'child_added') {
|
276
|
+
fn = onChildAdded;
|
277
|
+
} else if (eventType === 'child_changed') {
|
278
|
+
fn = onChildChanged;
|
279
|
+
} else if (eventType === 'child_removed') {
|
280
|
+
fn = onChildRemoved;
|
281
|
+
} else if (eventType === 'child_moved') {
|
282
|
+
fn = onChildMoved;
|
283
|
+
}
|
284
|
+
|
285
|
+
if (fn) {
|
286
|
+
const { snapshot, previousChildName } = await new Promise((resolve, reject) => {
|
287
|
+
fn(
|
288
|
+
queryRef,
|
289
|
+
(snapshot, previousChildName) => {
|
290
|
+
resolve({ snapshot, previousChildName });
|
291
|
+
},
|
292
|
+
reject,
|
293
|
+
{ onlyOnce: true },
|
294
|
+
);
|
295
|
+
});
|
296
|
+
|
297
|
+
return snapshotWithPreviousChildToObject(snapshot, previousChildName);
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
const snapshot = await get(dbRef, modifiers);
|
302
|
+
return snapshot;
|
303
|
+
});
|
304
|
+
},
|
305
|
+
|
306
|
+
on(appName, dbURL, props) {
|
307
|
+
return guard(async () => {
|
308
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
309
|
+
const { key, modifiers, path, eventType, registration } = props;
|
310
|
+
const { eventRegistrationKey } = registration;
|
311
|
+
const dbRef = ref(db, path);
|
312
|
+
|
313
|
+
const queryRef = getQueryInstance(dbRef, modifiers);
|
314
|
+
|
315
|
+
function sendEvent(data) {
|
316
|
+
const event = {
|
317
|
+
eventName: 'database_sync_event',
|
318
|
+
body: {
|
319
|
+
data,
|
320
|
+
key,
|
321
|
+
registration,
|
322
|
+
eventType,
|
323
|
+
},
|
324
|
+
};
|
325
|
+
|
326
|
+
emitEvent('database_sync_event', event);
|
327
|
+
}
|
328
|
+
|
329
|
+
function sendError(error) {
|
330
|
+
const event = {
|
331
|
+
eventName: 'database_sync_event',
|
332
|
+
body: {
|
333
|
+
key,
|
334
|
+
registration,
|
335
|
+
error: getDatabaseWebError(error),
|
336
|
+
},
|
337
|
+
};
|
338
|
+
|
339
|
+
emitEvent('database_sync_event', event);
|
340
|
+
}
|
341
|
+
|
342
|
+
let listener = null;
|
343
|
+
|
344
|
+
// Ignore if the listener already exists.
|
345
|
+
if (listeners[eventRegistrationKey]) {
|
346
|
+
return;
|
347
|
+
}
|
348
|
+
|
349
|
+
if (eventType === 'value') {
|
350
|
+
listener = onValue(queryRef, snapshot => sendEvent(snapshotToObject(snapshot)), sendError);
|
351
|
+
} else {
|
352
|
+
let fn = null;
|
353
|
+
|
354
|
+
if (eventType === 'child_added') {
|
355
|
+
fn = onChildAdded;
|
356
|
+
} else if (eventType === 'child_changed') {
|
357
|
+
fn = onChildChanged;
|
358
|
+
} else if (eventType === 'child_removed') {
|
359
|
+
fn = onChildRemoved;
|
360
|
+
} else if (eventType === 'child_moved') {
|
361
|
+
fn = onChildMoved;
|
362
|
+
}
|
363
|
+
|
364
|
+
if (fn) {
|
365
|
+
listener = fn(
|
366
|
+
queryRef,
|
367
|
+
(snapshot, previousChildName) => {
|
368
|
+
sendEvent(snapshotWithPreviousChildToObject(snapshot, previousChildName));
|
369
|
+
},
|
370
|
+
sendError,
|
371
|
+
);
|
372
|
+
}
|
373
|
+
}
|
374
|
+
|
375
|
+
listeners[eventRegistrationKey] = listener;
|
376
|
+
});
|
377
|
+
},
|
378
|
+
|
379
|
+
off(queryKey, eventRegistrationKey) {
|
380
|
+
const listener = listeners[eventRegistrationKey];
|
381
|
+
if (listener) {
|
382
|
+
listener();
|
383
|
+
delete listeners[eventRegistrationKey];
|
384
|
+
}
|
385
|
+
},
|
386
|
+
|
387
|
+
keepSynced() {
|
388
|
+
return rejectPromiseWithCodeAndMessage(
|
389
|
+
'unsupported',
|
390
|
+
'This operation is not supported on this environment.',
|
391
|
+
);
|
392
|
+
},
|
393
|
+
|
394
|
+
/**
|
395
|
+
* OnDisconnect
|
396
|
+
*/
|
397
|
+
|
398
|
+
/**
|
399
|
+
* Cancels the onDisconnect instance at the specified path.
|
400
|
+
* @param {string} appName - The app name.
|
401
|
+
* @param {string} dbURL - The database URL.
|
402
|
+
* @param {string} path - The path.
|
403
|
+
* @returns {Promise<void>}
|
404
|
+
*/
|
405
|
+
onDisconnectCancel(appName, dbURL, path) {
|
406
|
+
return guard(async () => {
|
407
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
408
|
+
const dbRef = ref(db, path);
|
409
|
+
const instance = getCachedOnDisconnectInstance(dbRef);
|
410
|
+
await instance.cancel();
|
411
|
+
|
412
|
+
// Delete the onDisconnect instance from the cache.
|
413
|
+
delete onDisconnectRef[dbRef.key];
|
414
|
+
});
|
415
|
+
},
|
416
|
+
|
417
|
+
/**
|
418
|
+
* Sets a value to be written to the database on disconnect.
|
419
|
+
* @param {string} appName - The app name.
|
420
|
+
* @param {string} dbURL - The database URL.
|
421
|
+
* @param {string} path - The path.
|
422
|
+
* @returns {Promise<void>}
|
423
|
+
*/
|
424
|
+
onDisconnectRemove(appName, dbURL, path) {
|
425
|
+
return guard(async () => {
|
426
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
427
|
+
const dbRef = ref(db, path);
|
428
|
+
const instance = getCachedOnDisconnectInstance(dbRef);
|
429
|
+
await instance.remove();
|
430
|
+
});
|
431
|
+
},
|
432
|
+
|
433
|
+
/**
|
434
|
+
* Sets a value to be written to the database on disconnect.
|
435
|
+
* @param {string} appName - The app name.
|
436
|
+
* @param {string} dbURL - The database URL.
|
437
|
+
* @param {string} path - The path.
|
438
|
+
* @param {object} props - The properties, including value.
|
439
|
+
* @returns {Promise<void>}
|
440
|
+
*/
|
441
|
+
onDisconnectSet(appName, dbURL, path, props) {
|
442
|
+
return guard(async () => {
|
443
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
444
|
+
const dbRef = ref(db, path);
|
445
|
+
const instance = getCachedOnDisconnectInstance(dbRef);
|
446
|
+
const value = props.value;
|
447
|
+
await instance.set(value);
|
448
|
+
});
|
449
|
+
},
|
450
|
+
|
451
|
+
/**
|
452
|
+
* Sets a value to be written to the database on disconnect with a priority.
|
453
|
+
* @param {string} appName - The app name.
|
454
|
+
* @param {string} dbURL - The database URL.
|
455
|
+
* @param {string} path - The path.
|
456
|
+
* @param {object} props - The properties, including value and priority.
|
457
|
+
* @returns {Promise<void>}
|
458
|
+
*/
|
459
|
+
onDisconnectSetWithPriority(appName, dbURL, path, props) {
|
460
|
+
return guard(async () => {
|
461
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
462
|
+
const dbRef = ref(db, path);
|
463
|
+
const instance = getCachedOnDisconnectInstance(dbRef);
|
464
|
+
const value = props.value;
|
465
|
+
const priority = props.priority;
|
466
|
+
await instance.setWithPriority(value, priority);
|
467
|
+
});
|
468
|
+
},
|
469
|
+
|
470
|
+
/**
|
471
|
+
* Updates the specified path with the provided values on disconnect.
|
472
|
+
* @param {string} appName - The app name.
|
473
|
+
* @param {string} dbURL - The database URL.
|
474
|
+
* @param {string} path - The path.
|
475
|
+
* @param {object} props - The properties, including values.
|
476
|
+
* @returns {Promise<void>}
|
477
|
+
*/
|
478
|
+
onDisconnectUpdate(appName, dbURL, path, props) {
|
479
|
+
return guard(async () => {
|
480
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
481
|
+
const dbRef = ref(db, path);
|
482
|
+
const instance = getCachedOnDisconnectInstance(dbRef);
|
483
|
+
const values = props.values;
|
484
|
+
await instance.update(values);
|
485
|
+
});
|
486
|
+
},
|
487
|
+
|
488
|
+
/**
|
489
|
+
* Transaction
|
490
|
+
*/
|
491
|
+
|
492
|
+
transactionStart(appName, dbURL, path, transactionId, applyLocally, userExecutor) {
|
493
|
+
return guard(async () => {
|
494
|
+
const db = getCachedDatabaseInstance(appName, dbURL);
|
495
|
+
const dbRef = ref(db, path);
|
496
|
+
|
497
|
+
try {
|
498
|
+
const { committed, snapshot } = await runTransaction(dbRef, userExecutor, {
|
499
|
+
applyLocally,
|
500
|
+
});
|
501
|
+
|
502
|
+
const event = {
|
503
|
+
body: {
|
504
|
+
committed,
|
505
|
+
type: 'complete',
|
506
|
+
snapshot: snapshotToObject(snapshot),
|
507
|
+
},
|
508
|
+
appName,
|
509
|
+
id: transactionId,
|
510
|
+
eventName: 'database_transaction_event',
|
511
|
+
};
|
512
|
+
|
513
|
+
emitEvent('database_transaction_event', event);
|
514
|
+
} catch (e) {
|
515
|
+
const event = {
|
516
|
+
body: {
|
517
|
+
committed: false,
|
518
|
+
type: 'error',
|
519
|
+
error: getDatabaseWebError(e),
|
520
|
+
},
|
521
|
+
appName,
|
522
|
+
id: transactionId,
|
523
|
+
eventName: 'database_transaction_event',
|
524
|
+
};
|
525
|
+
|
526
|
+
emitEvent('database_transaction_event', event);
|
527
|
+
}
|
528
|
+
});
|
529
|
+
},
|
530
|
+
|
531
|
+
/**
|
532
|
+
* Commits the transaction with the specified updates.
|
533
|
+
* @param {string} appName - The app name.
|
534
|
+
* @param {string} dbURL - The database URL.
|
535
|
+
* @param {string} transactionId - The transaction ID.
|
536
|
+
* @param {object} updates - The updates.
|
537
|
+
* @returns {Promise<void>}
|
538
|
+
*/
|
539
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
540
|
+
async transactionTryCommit(appName, dbURL, transactionId, updates) {
|
541
|
+
// We don't need to implement this as for 'Other' platforms
|
542
|
+
// we pass the users transaction function to the Firebase JS SDK directly.
|
543
|
+
throw new Error('Not implemented');
|
544
|
+
},
|
545
|
+
};
|
package/lib/web/query.js
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
import {
|
2
|
+
query,
|
3
|
+
orderByKey,
|
4
|
+
orderByPriority,
|
5
|
+
orderByValue,
|
6
|
+
orderByChild,
|
7
|
+
limitToLast,
|
8
|
+
limitToFirst,
|
9
|
+
endAt,
|
10
|
+
endBefore,
|
11
|
+
startAt,
|
12
|
+
startAfter,
|
13
|
+
} from '@react-native-firebase/app/lib/internal/web/firebaseDatabase';
|
14
|
+
|
15
|
+
export function getQueryInstance(dbRef, modifiers) {
|
16
|
+
const constraints = [];
|
17
|
+
|
18
|
+
for (const modifier of modifiers) {
|
19
|
+
const { type, name } = modifier;
|
20
|
+
|
21
|
+
if (type === 'orderBy') {
|
22
|
+
switch (name) {
|
23
|
+
case 'orderByKey':
|
24
|
+
constraints.push(orderByKey());
|
25
|
+
break;
|
26
|
+
case 'orderByPriority':
|
27
|
+
constraints.push(orderByPriority());
|
28
|
+
break;
|
29
|
+
case 'orderByValue':
|
30
|
+
constraints.push(orderByValue());
|
31
|
+
break;
|
32
|
+
case 'orderByChild':
|
33
|
+
constraints.push(orderByChild(modifier.key));
|
34
|
+
break;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
if (type === 'limit') {
|
39
|
+
const { value } = modifier;
|
40
|
+
|
41
|
+
switch (name) {
|
42
|
+
case 'limitToLast':
|
43
|
+
constraints.push(limitToLast(value));
|
44
|
+
break;
|
45
|
+
case 'limitToFirst':
|
46
|
+
constraints.push(limitToFirst(value));
|
47
|
+
break;
|
48
|
+
}
|
49
|
+
}
|
50
|
+
|
51
|
+
if (type === 'filter') {
|
52
|
+
const { key, value } = modifier;
|
53
|
+
|
54
|
+
switch (name) {
|
55
|
+
case 'endAt':
|
56
|
+
constraints.push(endAt(value, key));
|
57
|
+
break;
|
58
|
+
case 'endBefore':
|
59
|
+
constraints.push(endBefore(value, key));
|
60
|
+
break;
|
61
|
+
case 'startAt':
|
62
|
+
constraints.push(startAt(value, key));
|
63
|
+
break;
|
64
|
+
case 'startAfter':
|
65
|
+
constraints.push(startAfter(value, key));
|
66
|
+
break;
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
return query(dbRef, ...constraints);
|
71
|
+
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@react-native-firebase/database",
|
3
|
-
"version": "20.1
|
3
|
+
"version": "20.2.1",
|
4
4
|
"author": "Invertase <oss@invertase.io> (http://invertase.io)",
|
5
5
|
"description": "React Native Firebase - The Firebase Realtime Database is a cloud-hosted database. Data is stored as JSON and synchronized in realtime to every connected client. React Native Firebase provides native integration with the Android & iOS Firebase SDKs, supporting both realtime data sync and offline capabilities.",
|
6
6
|
"main": "lib/index.js",
|
@@ -25,10 +25,10 @@
|
|
25
25
|
"realtome database"
|
26
26
|
],
|
27
27
|
"peerDependencies": {
|
28
|
-
"@react-native-firebase/app": "20.1
|
28
|
+
"@react-native-firebase/app": "20.2.1"
|
29
29
|
},
|
30
30
|
"publishConfig": {
|
31
31
|
"access": "public"
|
32
32
|
},
|
33
|
-
"gitHead": "
|
33
|
+
"gitHead": "2c787c2dbefbefcc637018e1e5d74a73b39600ab"
|
34
34
|
}
|