From 9028ae4785eb17239ae2ab49d343a39c01a349e7 Mon Sep 17 00:00:00 2001 From: Russell Wheatley Date: Mon, 15 Jul 2024 14:56:38 +0100 Subject: [PATCH] fix(database): set priority on child snapshot if available (#7897) --- .../ReactNativeFirebaseDatabaseCommon.java | 28 ++++++++-- .../database/e2e/snapshot/snapshot.e2e.js | 54 +++++++++++++++++++ .../ios/RNFBDatabase/RNFBDatabaseCommon.m | 13 +++-- packages/database/lib/DatabaseDataSnapshot.js | 16 +++++- 4 files changed, 102 insertions(+), 9 deletions(-) diff --git a/packages/database/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseCommon.java b/packages/database/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseCommon.java index 81dc7dafb9..f905513461 100644 --- a/packages/database/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseCommon.java +++ b/packages/database/android/src/reactnative/java/io/invertase/firebase/database/ReactNativeFirebaseDatabaseCommon.java @@ -24,10 +24,13 @@ import com.facebook.react.bridge.*; import com.google.firebase.database.DataSnapshot; import com.google.firebase.database.MutableData; +import java.util.HashMap; import javax.annotation.Nullable; public class ReactNativeFirebaseDatabaseCommon { private static final String TAG = "DatabaseCommon"; + private static final String childPrioritiesKey = "childPriorities"; + private static final String childKeysKey = "childKeys"; /** * @param promise @@ -61,12 +64,13 @@ public static WritableMap snapshotWithPreviousChildToMap( */ public static WritableMap snapshotToMap(DataSnapshot dataSnapshot) { WritableMap snapshot = Arguments.createMap(); - + HashMap childProperties = getChildProperties(dataSnapshot); snapshot.putString("key", dataSnapshot.getKey()); snapshot.putBoolean("exists", dataSnapshot.exists()); snapshot.putBoolean("hasChildren", dataSnapshot.hasChildren()); snapshot.putDouble("childrenCount", dataSnapshot.getChildrenCount()); - snapshot.putArray("childKeys", getChildKeys(dataSnapshot)); + snapshot.putArray(childKeysKey, (ReadableArray) childProperties.get(childKeysKey)); + snapshot.putMap(childPrioritiesKey, (WritableMap) childProperties.get(childPrioritiesKey)); mapPutValue("priority", dataSnapshot.getPriority(), snapshot); if (!dataSnapshot.hasChildren()) { @@ -369,15 +373,29 @@ private static WritableMap buildMap(MutableData mutableData) { * @param snapshot * @return */ - public static WritableArray getChildKeys(DataSnapshot snapshot) { + public static HashMap getChildProperties(DataSnapshot snapshot) { WritableArray childKeys = Arguments.createArray(); - + WritableMap childPriorities = Arguments.createMap(); + HashMap childProperties = new HashMap<>(); if (snapshot.hasChildren()) { for (DataSnapshot child : snapshot.getChildren()) { childKeys.pushString(child.getKey()); + + Object priority = child.getPriority(); + // Priority can be String, Double or null + if (priority instanceof String) { + childPriorities.putString(child.getKey(), (String) priority); + } else if (priority instanceof Double) { + childPriorities.putDouble(child.getKey(), (Double) priority); + } else if (priority == null) { + childPriorities.putNull(child.getKey()); + } } } - return childKeys; + childProperties.put(childKeysKey, childKeys); + childProperties.put(childPrioritiesKey, childPriorities); + + return childProperties; } } diff --git a/packages/database/e2e/snapshot/snapshot.e2e.js b/packages/database/e2e/snapshot/snapshot.e2e.js index 5c036f2bfe..9a3bd0633a 100644 --- a/packages/database/e2e/snapshot/snapshot.e2e.js +++ b/packages/database/e2e/snapshot/snapshot.e2e.js @@ -265,6 +265,32 @@ describe('database()...snapshot', function () { snapshot1.val().should.equal('foobar'); snapshot2.val().should.eql(jet.contextify(CONTENT.TYPES.object)); }); + + it('should return the correct priority for the child snapshots', async function () { + if (Platform.other) { + // TODO - remove once "other" is fully integrated + this.skip(); + } + const ref = firebase.database().ref(TEST_PATH).child('get-priority-children'); + const child1 = ref.child('child1'); + const child2 = ref.child('child2'); + const child3 = ref.child('child3'); + + await Promise.all([ + child1.set({ foo: 'bar' }), + child2.set({ foo: 'bar' }), + child3.set({ foo: 'bar' }), + ]); + + await child1.setPriority(1); + await child2.setPriority(2); + await child3.setPriority(3); + + const snapshot = await ref.once('value'); + snapshot.child('child1').getPriority().should.equal(1); + snapshot.child('child2').getPriority().should.equal(2); + snapshot.child('child3').getPriority().should.equal(3); + }); }); describe('modular', function () { @@ -530,5 +556,33 @@ describe('database()...snapshot', function () { snapshot1.val().should.equal('foobar'); snapshot2.val().should.eql(jet.contextify(CONTENT.TYPES.object)); }); + + it('should return the correct priority for the child snapshots', async function () { + if (Platform.other) { + // TODO - remove once "other" is fully integrated + this.skip(); + } + const { getDatabase, ref, child, set, setPriority, get } = databaseModular; + const reference = child(ref(getDatabase(), TEST_PATH), 'get-priority-children-mod'); + + const child1 = child(reference, 'child1'); + const child2 = child(reference, 'child2'); + const child3 = child(reference, 'child3'); + + await Promise.all([ + set(child1, { foo: 'bar' }), + set(child2, { foo: 'bar' }), + set(child3, { foo: 'bar' }), + ]); + + await setPriority(child1, 1); + await setPriority(child2, 2); + await setPriority(child3, 3); + + const snapshot = await get(reference); + snapshot.child('child1').getPriority().should.equal(1); + snapshot.child('child2').getPriority().should.equal(2); + snapshot.child('child3').getPriority().should.equal(3); + }); }); }); diff --git a/packages/database/ios/RNFBDatabase/RNFBDatabaseCommon.m b/packages/database/ios/RNFBDatabase/RNFBDatabaseCommon.m index 32845acd36..3df931639c 100644 --- a/packages/database/ios/RNFBDatabase/RNFBDatabaseCommon.m +++ b/packages/database/ios/RNFBDatabase/RNFBDatabaseCommon.m @@ -26,6 +26,9 @@ NSString *const DATABASE_LOGGING_ENABLED = @"firebase_database_logging_enabled"; NSString *const DATABASE_PERSISTENCE_CACHE_SIZE = @"firebase_database_persistence_cache_size_bytes"; +NSString *const childPrioritiesKey = @"childPriorities"; +NSString *const childKeysKey = @"childKeys"; + @implementation RNFBDatabaseCommon + (void)load { @@ -250,28 +253,32 @@ + (NSDictionary *)snapshotToDictionary:(FIRDataSnapshot *)dataSnapshot { } else { [snapshot setValue:[NSNull null] forKey:@"key"]; } + NSMutableDictionary *childProperties = [self getSnapshotChildProperties:dataSnapshot]; [snapshot setValue:@(dataSnapshot.exists) forKey:@"exists"]; [snapshot setValue:@(dataSnapshot.hasChildren) forKey:@"hasChildren"]; [snapshot setValue:@(dataSnapshot.childrenCount) forKey:@"childrenCount"]; - [snapshot setValue:[self getSnapshotChildKeys:dataSnapshot] forKey:@"childKeys"]; + [snapshot setValue:childProperties[childKeysKey] forKey:childKeysKey]; + [snapshot setValue:childProperties[childPrioritiesKey] forKey:childPrioritiesKey]; [snapshot setValue:dataSnapshot.priority forKey:@"priority"]; [snapshot setValue:dataSnapshot.value forKey:@"value"]; return snapshot; } -+ (NSMutableArray *)getSnapshotChildKeys:(FIRDataSnapshot *)dataSnapshot { ++ (NSMutableDictionary *)getSnapshotChildProperties:(FIRDataSnapshot *)dataSnapshot { NSMutableArray *childKeys = [NSMutableArray array]; + NSMutableDictionary *childPriorities = [[NSMutableDictionary alloc] init]; if (dataSnapshot.childrenCount > 0) { NSEnumerator *children = [dataSnapshot children]; FIRDataSnapshot *child; child = [children nextObject]; while (child) { [childKeys addObject:child.key]; + [childPriorities setValue:child.priority forKey:child.key]; child = [children nextObject]; } } - return childKeys; + return @{childKeysKey : childKeys, childPrioritiesKey : childPriorities}; } @end diff --git a/packages/database/lib/DatabaseDataSnapshot.js b/packages/database/lib/DatabaseDataSnapshot.js index 3f3c363b9e..a22698f799 100644 --- a/packages/database/lib/DatabaseDataSnapshot.js +++ b/packages/database/lib/DatabaseDataSnapshot.js @@ -15,7 +15,13 @@ * */ -import { isArray, isFunction, isObject, isString } from '@react-native-firebase/app/lib/common'; +import { + isArray, + isFunction, + isObject, + isString, + isNumber, +} from '@react-native-firebase/app/lib/common'; import { deepGet } from '@react-native-firebase/app/lib/common/deeps'; export default class DatabaseDataSnapshot { @@ -61,11 +67,19 @@ export default class DatabaseDataSnapshot { const childRef = this._ref.child(path); + let childPriority = null; + if (this._snapshot.childPriorities) { + const childPriorityValue = this._snapshot.childPriorities[childRef.key]; + if (isString(childPriorityValue) || isNumber(childPriorityValue)) { + childPriority = childPriorityValue; + } + } return new DatabaseDataSnapshot(childRef, { value, key: childRef.key, exists: value !== null, childKeys: isObject(value) ? Object.keys(value) : [], + priority: childPriority, }); }