@@ -108,7 +108,7 @@ export function _instanceWithOptions(
108108 */
109109export class InstanceBuilder {
110110 /** @hidden */
111- constructor ( private instance : string , private options : DeploymentOptions ) { }
111+ constructor ( private instance : string , private options : DeploymentOptions ) { }
112112
113113 /**
114114 * @return Firebase Realtime Database reference builder interface.
@@ -134,9 +134,9 @@ export function _refWithOptions(
134134 if ( ! databaseURL ) {
135135 throw new Error (
136136 'Missing expected firebase config value databaseURL, ' +
137- 'config is actually' +
138- JSON . stringify ( firebaseConfig ( ) ) +
139- '\n If you are unit testing, please set process.env.FIREBASE_CONFIG'
137+ 'config is actually' +
138+ JSON . stringify ( firebaseConfig ( ) ) +
139+ '\n If you are unit testing, please set process.env.FIREBASE_CONFIG'
140140 ) ;
141141 }
142142
@@ -174,7 +174,7 @@ export class RefBuilder {
174174 private apps : apps . Apps ,
175175 private triggerResource : ( ) => string ,
176176 private options : DeploymentOptions
177- ) { }
177+ ) { }
178178
179179 /**
180180 * Event handler that fires every time a Firebase Realtime Database write
@@ -325,7 +325,7 @@ export function extractInstanceAndPath(
325325 if ( ! match ) {
326326 throw new Error (
327327 `Unexpected resource string for Firebase Realtime Database event: ${ resource } . ` +
328- 'Expected string in the format of "projects/_/instances/{firebaseioSubdomain}/refs/{ref=**}"'
328+ 'Expected string in the format of "projects/_/instances/{firebaseioSubdomain}/refs/{ref=**}"'
329329 ) ;
330330 }
331331 const [ , project , dbInstanceName , path ] = match ;
@@ -396,7 +396,7 @@ export class DataSnapshot {
396396 // may be unpopulated in user's unit tests
397397 throw new Error (
398398 'Please supply a Firebase app in the constructor for DataSnapshot' +
399- ' in order to use the .ref method.'
399+ ' in order to use the .ref method.'
400400 ) ;
401401 }
402402 if ( ! this . _ref ) {
@@ -471,7 +471,16 @@ export class DataSnapshot {
471471 * @return `true` if this `DataSnapshot` contains any data; otherwise, `false`.
472472 */
473473 exists ( ) : boolean {
474- return ! _ . isNull ( this . val ( ) ) ;
474+ const val = this . val ( ) ;
475+ if ( _ . isNull ( val ) ) {
476+ // Null value
477+ return false ;
478+ }
479+ if ( ( _ . isObjectLike ( val ) || _ . isArray ( val ) ) && _ . isEmpty ( val ) ) {
480+ // Empty object/array
481+ return false ;
482+ }
483+ return true
475484 }
476485
477486 /**
@@ -512,7 +521,7 @@ export class DataSnapshot {
512521 */
513522 forEach ( action : ( a : DataSnapshot ) => boolean | void ) : boolean {
514523 const val = this . val ( ) ;
515- if ( _ . isPlainObject ( val ) ) {
524+ if ( _ . isObjectLike ( val ) || _ . isArray ( val ) ) {
516525 return _ . some (
517526 val ,
518527 ( value , key : string ) => action ( this . child ( key ) ) === true
@@ -546,7 +555,7 @@ export class DataSnapshot {
546555 */
547556 hasChildren ( ) : boolean {
548557 const val = this . val ( ) ;
549- return _ . isPlainObject ( val ) && _ . keys ( val ) . length > 0 ;
558+ return ( _ . isObjectLike ( val ) || _ . isArray ( val ) ) && ! _ . isEmpty ( val ) ;
550559 }
551560
552561 /**
@@ -556,7 +565,7 @@ export class DataSnapshot {
556565 */
557566 numChildren ( ) : number {
558567 const val = this . val ( ) ;
559- return _ . isPlainObject ( val ) ? Object . keys ( val ) . length : 0 ;
568+ return ( _ . isObjectLike ( val ) || _ . isArray ( val ) ) ? _ . keys ( val ) . length : 0 ;
560569 }
561570
562571 /**
@@ -588,7 +597,12 @@ export class DataSnapshot {
588597 continue ;
589598 }
590599 const childNode = node [ key ] ;
591- obj [ key ] = this . _checkAndConvertToArray ( childNode ) ;
600+ const v = this . _checkAndConvertToArray ( childNode ) ;
601+ if ( v === null ) {
602+ // Empty child node
603+ continue ;
604+ }
605+ obj [ key ] = v ;
592606 numKeys ++ ;
593607 const integerRegExp = / ^ ( 0 | [ 1 - 9 ] \d * ) $ / ;
594608 if ( allIntegerKeys && integerRegExp . test ( key ) ) {
@@ -598,6 +612,11 @@ export class DataSnapshot {
598612 }
599613 }
600614
615+ if ( numKeys === 0 ) {
616+ // Empty node
617+ return null ;
618+ }
619+
601620 if ( allIntegerKeys && maxKey < 2 * numKeys ) {
602621 // convert to array.
603622 const array : any = [ ] ;
0 commit comments