text: import { Observable, merge, from, of } from 'rxjs';
  import { delay, map, switchMap, scan, distinctUntilChanged } from 'rxjs/operators';
  import { __assign, __spreadArrays } from 'tslib';
  
  /**
   * @license
   * Copyright 2018 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.
   */
  /**
   * Create an observable from a Database Reference or Database Query.
   * @param ref Database Reference
   * @param event Listen event type ('value', 'added', 'changed', 'removed', 'moved')
   */
  function fromRef(ref, event) {
      return new Observable(function (subscriber) {
          var fn = ref.on(event, function (snapshot, prevKey) {
              subscriber.next({ snapshot: snapshot, prevKey: prevKey, event: event });
          }, subscriber.error.bind(subscriber));
          return {
              unsubscribe: function () {
                  ref.off(event, fn);
              }
          };
      }).pipe(
      // Ensures subscribe on observable is async. This handles
      // a quirk in the SDK where on/once callbacks can happen
      // synchronously.
      delay(0));
  }
  
  /**
   * @license
   * Copyright 2018 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.
   */
  var ListenEvent;
  (function (ListenEvent) {
      ListenEvent["added"] = "child_added";
      ListenEvent["removed"] = "child_removed";
      ListenEvent["changed"] = "child_changed";
      ListenEvent["moved"] = "child_moved";
      ListenEvent["value"] = "value";
  })(ListenEvent || (ListenEvent = {}));
  
  /**
   * @license
   * Copyright 2018 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.
   */
  /**
   * Check the length of the provided array. If it is empty return an array
   * that is populated with all the Realtime Database child events.
   * @param events
   */
  function validateEventsArray(events) {
      if (events == null || events.length === 0) {
          events = [
              ListenEvent.added,
              ListenEvent.removed,
              ListenEvent.changed,
              ListenEvent.moved
          ];
      }
      return events;
  }
  
  /**
   * @license
   * Copyright 2018 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.
   */
  /**
   * Get the snapshot changes of an object
   * @param query
   */
  function object(query) {
      return fromRef(query, ListenEvent.value);
  }
  /**
   * Get an array of object values, optionally with a mapped key
   * @param query object ref or query
   * @param keyField map the object key to a specific field
   */
  function objectVal(query, keyField) {
      return fromRef(query, ListenEvent.value).pipe(map(function (change) { return changeToData(change, keyField); }));
  }
  function changeToData(change, keyField) {
      var _a;
      return __assign(__assign({}, change.snapshot.val()), (keyField ? (_a = {}, _a[keyField] = change.snapshot.key, _a) : null));
  }
  
  /**
   * @license
   * Copyright 2018 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.
   */
  function stateChanges(query, events) {
      events = validateEventsArray(events);
      var childEvent$ = events.map(function (event) { return fromRef(query, event); });
      return merge.apply(void 0, childEvent$);
  }
  function fromOnce(query) {
      return from(query.once(ListenEvent.value)).pipe(map(function (snapshot) {
          var event = ListenEvent.value;
          return { snapshot: snapshot, prevKey: null, event: event };
      }));
  }
  function list(query, events) {
      var eventsList = validateEventsArray(events);
      return fromOnce(query).pipe(switchMap(function (change) {
          var childEvent$ = [of(change)];
          for (var _i = 0, eventsList_1 = eventsList; _i < eventsList_1.length; _i++) {
              var event_1 = eventsList_1[_i];
              childEvent$.push(fromRef(query, event_1));
          }
          return merge.apply(void 0, childEvent$).pipe(scan(buildView, []));
      }), distinctUntilChanged());
  }
  /**
   * Get an object mapped to its value, and optionally its key
   * @param query object ref or query
   * @param keyField map the object key to a specific field
   */
  function listVal(query, keyField) {
      return list(query).pipe(map(function (arr) { return arr.map(function (change) { return changeToData(change, keyField); }); }));
  }
  function positionFor(changes, key) {
      var len = changes.length;
      for (var i = 0; i < len; i++) {
          if (changes[i].snapshot.key === key) {
              return i;
          }
      }
      return -1;
  }
  function positionAfter(changes, prevKey) {
      if (prevKey == null) {
          return 0;
      }
      else {
          var i = positionFor(changes, prevKey);
          if (i === -1) {
              return changes.length;
          }
          else {
              return i + 1;
          }
      }
  }
  function buildView(current, change) {
      var snapshot = change.snapshot, prevKey = change.prevKey, event = change.event;
      var key = snapshot.key;
      var currentKeyPosition = positionFor(current, key);
      var afterPreviousKeyPosition = positionAfter(current, prevKey || undefined);
      switch (event) {
          case ListenEvent.value:
              if (change.snapshot && change.snapshot.exists()) {
                  var prevKey_1 = null;
                  change.snapshot.forEach(function (snapshot) {
                      var action = {
                          snapshot: snapshot,
                          event: ListenEvent.value,
                          prevKey: prevKey_1
                      };
                      prevKey_1 = snapshot.key;
                      current = __spreadArrays(current, [action]);
                      return false;
                  });
              }
              return current;
          case ListenEvent.added:
              if (currentKeyPosition > -1) {
                  // check that the previouskey is what we expect, else reorder
                  var previous = current[currentKeyPosition - 1];
                  if (((previous && previous.snapshot.key) || null) !== prevKey) {
                      current = current.filter(function (x) { return x.snapshot.key !== snapshot.key; });
                      current.splice(afterPreviousKeyPosition, 0, change);
                  }
              }
              else if (prevKey == null) {
                  return __spreadArrays([change], current);
              }
              else {
                  current = current.slice();
                  current.splice(afterPreviousKeyPosition, 0, change);
              }
              return current;
          case ListenEvent.removed:
              return current.filter(function (x) { return x.snapshot.key !== snapshot.key; });
          case ListenEvent.changed:
              return current.map(function (x) { return (x.snapshot.key === key ? change : x); });
          case ListenEvent.moved:
              if (currentKeyPosition > -1) {
                  var data = current.splice(currentKeyPosition, 1)[0];
                  current = current.slice();
                  current.splice(afterPreviousKeyPosition, 0, data);
                  return current;
              }
              return current;
          // default will also remove null results
          default:
              return current;
      }
  }
  
  export { ListenEvent, changeToData, fromRef, list, listVal, object, objectVal, stateChanges };
  //# sourceMappingURL=index.esm.js.map
  