From 2fdb73656eac045084a9b9caa5160f843839774c Mon Sep 17 00:00:00 2001 From: Chris Bianca Date: Fri, 16 Jun 2017 13:10:11 +0100 Subject: [PATCH] [android][database] Fix hanging db when querying object with large numerical keys --- .../java/io/invertase/firebase/Utils.java | 16 +++++++++-- .../tests/database/ref/issueSpecificTests.js | 27 +++++++++++++----- tests/src/tests/support/DatabaseContents.js | 28 +++++++++++++++++++ 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/android/src/main/java/io/invertase/firebase/Utils.java b/android/src/main/java/io/invertase/firebase/Utils.java index 96287961..b2b07b99 100644 --- a/android/src/main/java/io/invertase/firebase/Utils.java +++ b/android/src/main/java/io/invertase/firebase/Utils.java @@ -213,16 +213,22 @@ public class Utils { } /** + * Data should be treated as an array if: + * 1) All the keys are integers + * 2) More than half the keys between 0 and the maximum key in the object have non-empty values + * + * Definition from: https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html * * @param snapshot * @return */ private static boolean isArray(DataSnapshot snapshot) { long expectedKey = -1; + long maxAllowedKey = (snapshot.getChildrenCount() * 2) - 1; for (DataSnapshot child : snapshot.getChildren()) { try { long key = Long.parseLong(child.getKey()); - if (key > expectedKey) { + if (key > expectedKey && key <= maxAllowedKey) { expectedKey = key; } else { return false; @@ -235,16 +241,22 @@ public class Utils { } /** + * Data should be treated as an array if: + * 1) All the keys are integers + * 2) More than half the keys between 0 and the maximum key in the object have non-empty values + * + * Definition from: https://firebase.googleblog.com/2014/04/best-practices-arrays-in-firebase.html * * @param mutableData * @return */ private static boolean isArray(MutableData mutableData) { long expectedKey = -1; + long maxAllowedKey = (mutableData.getChildrenCount() * 2) - 1; for (MutableData child : mutableData.getChildren()) { try { long key = Long.parseLong(child.getKey()); - if (key > expectedKey) { + if (key > expectedKey && key <= maxAllowedKey) { expectedKey++; } else { return false; diff --git a/tests/src/tests/database/ref/issueSpecificTests.js b/tests/src/tests/database/ref/issueSpecificTests.js index 346b060b..9338ac3c 100644 --- a/tests/src/tests/database/ref/issueSpecificTests.js +++ b/tests/src/tests/database/ref/issueSpecificTests.js @@ -1,10 +1,10 @@ import should from 'should'; import DatabaseContents from '../../support/DatabaseContents'; -function issueTests({ fdescribe, describe, it, context, firebase }) { +function issueTests({ describe, it, context, firebase }) { describe('issue_100', () => { context('array-like values should', () => { - it('return null in returned array at positions where a key is missing', async() => { + it('return null in returned array at positions where a key is missing', async () => { // Setup const ref = firebase.native.database().ref('tests/issues/100'); @@ -12,9 +12,6 @@ function issueTests({ fdescribe, describe, it, context, firebase }) { // Test return ref.once('value').then((snapshot) => { - // Assertion - // console.warn(JSON.stringify(snapshot.val())); - snapshot.val().should.eql([null, DatabaseContents.ISSUES[100][1], DatabaseContents.ISSUES[100][2], DatabaseContents.ISSUES[100][3]]); }); }); @@ -23,7 +20,7 @@ function issueTests({ fdescribe, describe, it, context, firebase }) { describe('issue_108', () => { context('filters using floats', () => { - it('return correct results', async() => { + it('return correct results', async () => { // Setup const ref = firebase.native.database().ref('tests/issues/108'); @@ -45,7 +42,7 @@ function issueTests({ fdescribe, describe, it, context, firebase }) { }); }); - it('return correct results when not using float values', async() => { + it('return correct results when not using float values', async () => { // Setup const ref = firebase.native.database().ref('tests/issues/108'); @@ -69,6 +66,22 @@ function issueTests({ fdescribe, describe, it, context, firebase }) { }); }); }); + + describe('issue_171', () => { + context('non array-like values should', () => { + it('return as objects', async () => { + // Setup + + const ref = firebase.native.database().ref('tests/issues/171'); + + // Test + + return ref.once('value').then((snapshot) => { + snapshot.val().should.eql(DatabaseContents.ISSUES[171]); + }); + }); + }); + }); } export default issueTests; diff --git a/tests/src/tests/support/DatabaseContents.js b/tests/src/tests/support/DatabaseContents.js index 0e60433e..a4a913c9 100644 --- a/tests/src/tests/support/DatabaseContents.js +++ b/tests/src/tests/support/DatabaseContents.js @@ -63,5 +63,33 @@ export default { latitude: 37, }, }, + + // https://github.com/invertase/react-native-firebase/issues/171 + 171: { + 10053768200609241: { + email: 'emaila@hotmail.com', + name: 'Sek Ranger', + profile_picture: 'https://url.to/picture', + uid: 'n6V8vACidyW4OKxnELkBbW83JaS2', + }, + 10053925505239749: { + email: 'emailb@hotmail.com', + name: 'Gu Hungry', + profile_picture: 'https://url.to/picture', + uid: 'Qq4Pwm7H2kO6sJIMLAJxuhAGGh22', + }, + 10106631429240929: { + email: 'emailc@gmail.com', + name: 'Chwang', + profile_picture: 'https://url.to/picture', + uid: 'T7VVrveS0dPs3idmgetLUfQsLZs1', + }, + 10106631429240930: { + email: 'emaild@gmail.com', + name: 'Introv Bigs', + profile_picture: 'https://url.to/picture', + uid: 'aNYxLexOb2WsXGOPiEAu47q5bxH3', + }, + }, }, };