|
| 1 | +import * as firebase from 'firebase/app'; |
| 2 | +import 'firestore'; |
| 3 | +import { Firestore, CollectionReference, DocumentReference, Query, DocumentChangeType, SnapshotMetadata, DocumentSnapshot, QuerySnapshot, DocumentChange } from 'firestore'; |
| 4 | +import { Observable } from 'rxjs/Observable'; |
| 5 | +import { Subscriber } from 'rxjs/Subscriber'; |
| 6 | +import { fromCollectionRef } from '../observable/fromRef'; |
| 7 | +import 'rxjs/add/operator/map'; |
| 8 | + |
| 9 | +import { Injectable } from '@angular/core'; |
| 10 | +import { FirebaseApp } from 'angularfire2'; |
| 11 | + |
| 12 | +import { QueryFn, AssociatedReference, DocumentChangeAction } from '../interfaces'; |
| 13 | +import { changes } from './changes'; |
| 14 | +import { AngularFirestoreDocument } from '../document/document'; |
| 15 | + |
| 16 | +export function validateEventsArray(events?: DocumentChangeType[]) { |
| 17 | + if(!events || events!.length === 0) { |
| 18 | + events = ['added', 'removed', 'modified']; |
| 19 | + } |
| 20 | + return events; |
| 21 | +} |
| 22 | + |
| 23 | + |
| 24 | +/** |
| 25 | + * AngularFirestoreCollection service |
| 26 | + * |
| 27 | + * This class creates a reference to a Firestore Collection. A reference and a query are provided in |
| 28 | + * in the constructor. The query can be the unqueried reference if no query is desired.The class |
| 29 | + * is generic which gives you type safety for data update methods and data streaming. |
| 30 | + * |
| 31 | + * This class uses Symbol.observable to transform into Observable using Observable.from(). |
| 32 | + * |
| 33 | + * This class is rarely used directly and should be created from the AngularFirestore service. |
| 34 | + * |
| 35 | + * Example: |
| 36 | + * |
| 37 | + * const collectionRef = firebase.firestore.collection('stocks'); |
| 38 | + * const query = collectionRef.where('price', '>', '0.01'); |
| 39 | + * const fakeStock = new AngularFirestoreCollection<Stock>(collectionRef, query); |
| 40 | + * |
| 41 | + * // NOTE!: the updates are performed on the reference not the query |
| 42 | + * await fakeStock.add({ name: 'FAKE', price: 0.01 }); |
| 43 | + * |
| 44 | + * // Subscribe to changes as snapshots. This provides you data updates as well as delta updates. |
| 45 | + * fakeStock.valueChanges().map(snap => snap.docs.map(doc => doc.data()).subscribe(value => console.log(value)); |
| 46 | + * // OR! Avoid unwrapping and transform from an Observable |
| 47 | + * Observable.from(fakeStock).subscribe(value => console.log(value)); |
| 48 | + */ |
| 49 | +export class AngularFirestoreCollection<T> { |
| 50 | + /** |
| 51 | + * The contstuctor takes in a CollectionReference and Query to provide wrapper methods |
| 52 | + * for data operations, data streaming, and Symbol.observable. |
| 53 | + * |
| 54 | + * Note: Data operation methods are done on the reference not the query. This means |
| 55 | + * when you update data it is not updating data to the window of your query unless |
| 56 | + * the data fits the criteria of the query. See the AssociatedRefence type for details |
| 57 | + * on this implication. |
| 58 | + * @param ref |
| 59 | + */ |
| 60 | + constructor( |
| 61 | + public readonly ref: CollectionReference, |
| 62 | + private readonly query: Query) { } |
| 63 | + |
| 64 | + /** |
| 65 | + * Listen to all documents in the collection and its possible query as an Observable. |
| 66 | + * This method returns a stream of DocumentSnapshots which gives the ability to get |
| 67 | + * the data set back as array and/or the delta updates in the collection. |
| 68 | + */ |
| 69 | + snapshotChanges(events?: DocumentChangeType[]): Observable<DocumentChangeAction[]> { |
| 70 | + if(!events || events.length === 0) { |
| 71 | + return changes(this.query); |
| 72 | + } |
| 73 | + return changes(this.query) |
| 74 | + .map(actions => actions.filter(change => events.indexOf(change.type) > -1)) |
| 75 | + .filter(changes => changes.length > 0); |
| 76 | + } |
| 77 | + |
| 78 | + /** |
| 79 | + * Listen to all documents in the collection and its possible query as an Observable. |
| 80 | + * This method returns a stream of unwrapped snapshots. |
| 81 | + */ |
| 82 | + valueChanges(events?: DocumentChangeType[]): Observable<T[]> { |
| 83 | + return this.snapshotChanges() |
| 84 | + .map(actions => actions.map(a => a.payload.doc.data()) as T[]); |
| 85 | + } |
| 86 | + |
| 87 | + /** |
| 88 | + * Add data to a collection reference. |
| 89 | + * |
| 90 | + * Note: Data operation methods are done on the reference not the query. This means |
| 91 | + * when you update data it is not updating data to the window of your query unless |
| 92 | + * the data fits the criteria of the query. |
| 93 | + */ |
| 94 | + add(data: T) { |
| 95 | + return this.ref.add(data); |
| 96 | + } |
| 97 | + |
| 98 | + /** |
| 99 | + * Create a reference to a single document in a collection. |
| 100 | + * @param path |
| 101 | + */ |
| 102 | + doc(path: string) { |
| 103 | + return new AngularFirestoreDocument(this.ref.doc(path)); |
| 104 | + } |
| 105 | +} |
0 commit comments