UNPKG

voluptasmollitia

Version:
92 lines (85 loc) 3.04 kB
/** * @license * Copyright 2018 Google LLC * * 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 firebase from 'firebase'; import { Observable } from 'rxjs'; import { QueryChange, ListenEvent } from '../interfaces'; import { fromRef } from '../fromRef'; import { map, withLatestFrom, scan, skipWhile } from 'rxjs/operators'; import { stateChanges } from './index'; type Query = firebase.database.Query; interface LoadedMetadata { data: QueryChange; lastKeyToLoad: unknown; } export function auditTrail( query: Query, events?: ListenEvent[] ): Observable<QueryChange[]> { const auditTrail$ = stateChanges(query, events).pipe( scan<QueryChange, QueryChange[]>( (current, changes) => [...current, changes], [] ) ); return waitForLoaded(query, auditTrail$); } function loadedData(query: Query): Observable<LoadedMetadata> { // Create an observable of loaded values to retrieve the // known dataset. This will allow us to know what key to // emit the "whole" array at when listening for child events. return fromRef(query, ListenEvent.value).pipe( map(data => { // Store the last key in the data set let lastKeyToLoad; // Loop through loaded dataset to find the last key data.snapshot.forEach(child => { lastKeyToLoad = child.key; return false; }); // return data set and the current last key loaded return { data, lastKeyToLoad }; }) ); } function waitForLoaded( query: Query, snap$: Observable<QueryChange[]> ): Observable<QueryChange[]> { const loaded$ = loadedData(query); return loaded$.pipe( withLatestFrom(snap$), // Get the latest values from the "loaded" and "child" datasets // We can use both datasets to form an array of the latest values. map(([loaded, changes]) => { // Store the last key in the data set const lastKeyToLoad = loaded.lastKeyToLoad; // Store all child keys loaded at this point const loadedKeys = changes.map(change => change.snapshot.key); return { changes, lastKeyToLoad, loadedKeys }; }), // This is the magical part, only emit when the last load key // in the dataset has been loaded by a child event. At this point // we can assume the dataset is "whole". skipWhile( meta => meta.loadedKeys.indexOf(meta.lastKeyToLoad as string | null) === -1 ), // Pluck off the meta data because the user only cares // to iterate through the snapshots map(meta => meta.changes) ); }