all files / firebase/modules/database/ DataSnapshot.js

93.75% Statements 30/32
83.33% Branches 15/18
90% Functions 9/10
96.67% Lines 29/30
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147                                        451×   451× 110×   341×       451× 451× 451×                   287× 127× 160×                   18× 18× 18×                                                                             14×                                                                          
/**
 * @flow
 * DataSnapshot representation wrapper
 */
import { isObject, deepGet, deepExists } from './../../utils';
import type Reference from './Reference';
 
/**
 * @class DataSnapshot
 * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot
 */
export default class DataSnapshot {
  ref: Reference;
  key: string;
 
  _value: any;
  _priority: any;
  _childKeys: Array<string>;
 
  constructor(ref: Reference, snapshot: Object) {
    this.key = snapshot.key;
 
    if (ref.key !== snapshot.key) {
      this.ref = ref.child(snapshot.key);
    } else {
      this.ref = ref;
    }
 
    // internal use only
    this._value = snapshot.value;
    this._priority = snapshot.priority === undefined ? null : snapshot.priority;
    this._childKeys = snapshot.childKeys || [];
  }
 
  /**
   * Extracts a JavaScript value from a DataSnapshot.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#val
   * @returns {any}
   */
  val(): any {
    // clone via JSON stringify/parse - prevent modification of this._value
    if (isObject(this._value) || Array.isArray(this._value))
      return JSON.parse(JSON.stringify(this._value));
    return this._value;
  }
 
  /**
   * Gets another DataSnapshot for the location at the specified relative path.
   * @param path
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach
   * @returns {Snapshot}
   */
  child(path: string): DataSnapshot {
    const value = deepGet(this._value, path);
    const childRef = this.ref.child(path);
    return new DataSnapshot(childRef, {
      value,
      key: childRef.key,
      exists: value !== null,
 
      // todo this is wrong - child keys needs to be the ordered keys, from FB
      // todo potential solution is build up a tree/map of a snapshot and its children
      // todo natively and send that back to JS to be use in this class.
      childKeys: isObject(value) ? Object.keys(value) : [],
    });
  }
 
  /**
   * Returns true if this DataSnapshot contains any data.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#exists
   * @returns {boolean}
   */
  exists(): boolean {
    return this._value !== null;
  }
 
  /**
   * Enumerates the top-level children in the DataSnapshot.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#forEach
   * @param action
   */
  forEach(action: (key: any) => any): boolean {
    Iif (!this._childKeys.length) return false;
    let cancelled = false;
 
    for (let i = 0, len = this._childKeys.length; i < len; i++) {
      const key = this._childKeys[i];
      const childSnapshot = this.child(key);
      const returnValue = action(childSnapshot);
 
      if (returnValue === true) {
        cancelled = true;
        break;
      }
    }
 
    return cancelled;
  }
 
  /**
   * Gets the priority value of the data in this DataSnapshot.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#getPriority
   * @returns {String|Number|null}
   */
  getPriority(): string | number | null {
    return this._priority;
  }
 
  /**
   * Returns true if the specified child path has (non-null) data.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#hasChild
   * @param path
   * @returns {Boolean}
   */
  hasChild(path: string): boolean {
    return deepExists(this._value, path);
  }
 
  /**
   * Returns whether or not the DataSnapshot has any non-null child properties.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#hasChildren
   * @returns {boolean}
   */
  hasChildren(): boolean {
    return this.numChildren() > 0;
  }
 
  /**
   * Returns the number of child properties of this DataSnapshot.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#numChildren
   * @returns {Number}
   */
  numChildren(): number {
    if (!isObject(this._value)) return 0;
    return Object.keys(this._value).length;
  }
 
  /**
   * Returns a JSON-serializable representation of this object.
   * @link https://firebase.google.com/docs/reference/js/firebase.database.DataSnapshot#toJSON
   * @returns {any}
   */
  toJSON(): Object {
    return this.val();
  }
}