# All files / model document_set.ts

91.18% Statements 62/68
81.25% Branches 13/16
90% Functions 18/20
90.63% Lines 58/64

    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
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158

    2x

    2x

    2x

    2x

    2x
    456x

    8409x
    1050x
    38061x

    7359x
    11x

    8409x
    8409x

    2x
    588x

    2x
    13620x

    2x
    2x

    2x
    89x

    2x
    580x

    2x
    1843x
    1843x

    2x
    661x

    2x
    1782x
    7938x
    7938x

    2x

    5984x
    5984x

    2x
    7375x
    7375x
    6050x

    1325x

    2x
    67x
    66x

    62x
    62x
    62x
    82x
    82x
    82x

    58x

    2x

    2x

    7309x
    7309x
    7309x
    7309x
    7309x

    2x
     /**
     * 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 { SortedMap } from '../util/sorted_map';

    import { documentMap } from './collections';
    import { Document } from './document';
    import { DocumentComparator } from './document_comparator';
    import { DocumentKey } from './document_key';

    /**
     * DocumentSet is an immutable (copy-on-write) collection that holds documents
     * in order specified by the provided comparator. We always add a document key
     * comparator on top of what is provided to guarantee document equality based on
     * the key.
     */

    export class DocumentSet {
      /**
       * Returns an empty copy of the existing DocumentSet, using the same
       * comparator.
       */
      static emptySet(oldSet: DocumentSet): DocumentSet {
        return new DocumentSet(oldSet.comparator);
      }

      private comparator: DocumentComparator;
      private keyedMap: SortedMap<DocumentKey, Document>;
      private sortedSet: SortedMap<Document, null>;

      /** The default ordering is by key if the comparator is omitted */
      constructor(comp?: DocumentComparator) {
        // We are adding document key comparator to the end as it's the only
        // guaranteed unique property of a document.
        if (comp) {
          this.comparator = (d1: Document, d2: Document) =>
            comp(d1, d2) || DocumentKey.comparator(d1.key, d2.key);
        } else {
          this.comparator = (d1: Document, d2: Document) =>
            DocumentKey.comparator(d1.key, d2.key);
        }

        this.keyedMap = documentMap();
        this.sortedSet = new SortedMap<Document, null>(this.comparator);
      }

      has(key: DocumentKey): boolean {
        return this.keyedMap.get(key) != null;
      }

      get(key: DocumentKey): Document | null {
        return this.keyedMap.get(key);
      }

      first(): Document | null {
        return this.sortedSet.minKey();
      }

      last(): Document | null {
        return this.sortedSet.maxKey();
      }

      isEmpty(): boolean {
        return this.sortedSet.isEmpty();
      }

      /**
       * Returns the index of the provided key in the document set, or -1 if the
       * document key is not present in the set;
       */
      indexOf(key: DocumentKey): number {
        const doc = this.keyedMap.get(key);
        return doc ? this.sortedSet.indexOf(doc) : -1;
      }

      get size(): number {
        return this.sortedSet.size;
      }

      /** Iterates documents in order defined by "comparator" */
      forEach(cb: (doc: Document) => void): void {
        this.sortedSet.inorderTraversal((k, v) => {
          cb(k);
          return false;
        });
      }

      /** Inserts or updates a document with the same key */
      add(doc: Document): DocumentSet {
        // First remove the element if we have it.
        const set = this.delete(doc.key);
        return set.copy(
          set.keyedMap.insert(doc.key, doc),
          set.sortedSet.insert(doc, null)
        );
      }

      /** Deletes a document with a given key */
      delete(key: DocumentKey): DocumentSet {
        const doc = this.get(key);
        if (!doc) {
          return this;
        }

        return this.copy(this.keyedMap.remove(key), this.sortedSet.remove(doc));
      }

      isEqual(other: DocumentSet | null | undefined): boolean {
        if (!(other instanceof DocumentSet)) return false;
        if (this.size !== other.size) return false;

        const thisIt = this.sortedSet.getIterator();
        const otherIt = other.sortedSet.getIterator();
        while (thisIt.hasNext()) {
          const thisDoc = thisIt.getNext().key;
          const otherDoc = otherIt.getNext().key;
          if (!thisDoc.isEqual(otherDoc)) return false;
        }
        return true;
      }

      toString(): string {
        const docStrings: string[] = [];
        this.forEach(doc => {
          docStrings.push(doc.toString());
        });
        if (docStrings.length === 0) {
          return 'DocumentSet ()';
        } else {
          return 'DocumentSet (\n  ' + docStrings.join('  \n') + '\n)';
        }
      }

      private copy(
        keyedMap: SortedMap<DocumentKey, Document>,
        sortedSet: SortedMap<Document, null>
      ): DocumentSet {
        const newSet = new DocumentSet();
        newSet.comparator = this.comparator;
        newSet.keyedMap = keyedMap;
        newSet.sortedSet = sortedSet;
        return newSet;
      }
    }