All files / core/util ServerValues.ts

92.11% Statements 35/38
77.78% Branches 14/18
83.33% Functions 5/6
92.11% Lines 35/38
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                                12x 12x 12x 12x 12x 12x                 12x         540x 540x 540x                   12x       2652x 2650x   2x 2x                     12x       5x 5x           5x                     12x       1509x           1509x     1509x 1143x 1143x 1143x       1x   1142x     366x 366x 366x     366x 958x       958x       366x      
/**
 * Copyright 2017 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
import { assert } from '@firebase/util';
import { Path } from './Path';
import { SparseSnapshotTree } from '../SparseSnapshotTree';
import { LeafNode } from '../snap/LeafNode';
import { nodeFromJSON } from '../snap/nodeFromJSON';
import { PRIORITY_INDEX } from '../snap/indexes/PriorityIndex';
import { Node } from '../snap/Node';
import { ChildrenNode } from '../snap/ChildrenNode';
 
/**
 * Generate placeholders for deferred values.
 * @param {?Object} values
 * @return {!Object}
 */
export const generateWithValues = function(
  values: {
    [k: string]: any;
  } | null
): { [k: string]: any } {
  values = values || {};
  values['timestamp'] = values['timestamp'] || new Date().getTime();
  return values;
};
 
/**
 * Value to use when firing local events. When writing server values, fire
 * local events with an approximate value, otherwise return value as-is.
 * @param {(Object|string|number|boolean)} value
 * @param {!Object} serverValues
 * @return {!(string|number|boolean)}
 */
export const resolveDeferredValue = function(
  value: { [k: string]: any } | string | number | boolean,
  serverValues: { [k: string]: any }
): string | number | boolean {
  if (!value || typeof value !== 'object') {
    return value as string | number | boolean;
  } else {
    assert('.sv' in value, 'Unexpected leaf node or priority contents');
    return serverValues[value['.sv']];
  }
};
 
/**
 * Recursively replace all deferred values and priorities in the tree with the
 * specified generated replacement values.
 * @param {!SparseSnapshotTree} tree
 * @param {!Object} serverValues
 * @return {!SparseSnapshotTree}
 */
export const resolveDeferredValueTree = function(
  tree: SparseSnapshotTree,
  serverValues: Object
): SparseSnapshotTree {
  const resolvedTree = new SparseSnapshotTree();
  tree.forEachTree(new Path(''), function(path, node) {
    resolvedTree.remember(
      path,
      resolveDeferredValueSnapshot(node, serverValues)
    );
  });
  return resolvedTree;
};
 
/**
 * Recursively replace all deferred values and priorities in the node with the
 * specified generated replacement values.  If there are no server values in the node,
 * it'll be returned as-is.
 * @param {!Node} node
 * @param {!Object} serverValues
 * @return {!Node}
 */
export const resolveDeferredValueSnapshot = function(
  node: Node,
  serverValues: Object
): Node {
  const rawPri = node.getPriority().val() as
    | object
    | boolean
    | null
    | number
    | string;
  const priority = resolveDeferredValue(rawPri, serverValues);
  let newNode: Node;
 
  if (node.isLeafNode()) {
    const leafNode = node as LeafNode;
    const value = resolveDeferredValue(leafNode.getValue(), serverValues);
    if (
      value !== leafNode.getValue() ||
      priority !== leafNode.getPriority().val()
    ) {
      return new LeafNode(value, nodeFromJSON(priority));
    } else {
      return node;
    }
  } else {
    const childrenNode = node as ChildrenNode;
    newNode = childrenNode;
    Iif (priority !== childrenNode.getPriority().val()) {
      newNode = newNode.updatePriority(new LeafNode(priority));
    }
    childrenNode.forEachChild(PRIORITY_INDEX, function(childName, childNode) {
      const newChildNode = resolveDeferredValueSnapshot(
        childNode,
        serverValues
      );
      Iif (newChildNode !== childNode) {
        newNode = newNode.updateImmediateChild(childName, newChildNode);
      }
    });
    return newNode;
  }
};