import { from , Observable } from 'rxjs' ; import { keepUnstableUntilFirst } from '@angular/fire' ; import { Action , DocumentData , DocumentReference , DocumentSnapshot , QueryFn , SetOptions } from '../interfaces' ; import { fromDocRef } from '../observable/fromRef' ; import { map } from 'rxjs/operators' ; import { AngularFirestore , associateQuery } from '../firestore' ; import { AngularFirestoreCollection } from '../collection/collection' ; import firebase from 'firebase/compat/app' ; /**
 * AngularFirestoreDocument service
 *
 * This class creates a reference to a Firestore Document. A reference is provided in
 * in the constructor. The class is generic which gives you type safety for data update
 * methods and data streaming.
 *
 * This class uses Symbol.observable to transform into Observable using Observable.from().
 *
 * This class is rarely used directly and should be created from the AngularFirestore service.
 *
 * Example:
 *
 * const fakeStock = new AngularFirestoreDocument<Stock>(doc('stocks/FAKE'));
 * await fakeStock.set({ name: 'FAKE', price: 0.01 });
 * fakeStock.valueChanges().map(snap => {
 *   if(snap.exists) return snap.data();
 *   return null;
 * }).subscribe(value => console.log(value));
 * // OR! Transform using Observable.from() and the data is unwrapped for you
 * Observable.from(fakeStock).subscribe(value => console.log(value));
 */ export class AngularFirestoreDocument < T = DocumentData > { /**
     * The constructor takes in a DocumentReference to provide wrapper methods
     * for data operations, data streaming, and Symbol.observable.
     */ constructor ( public ref , private afs ) { } /**
     * Create or overwrite a single document.
     */ set ( data , options ? ) { return this . ref . set ( data , options ) ; } /**
     * Update some fields of a document without overwriting the entire document.
     */ update ( data ) { return this . ref . update ( data ) ; } /**
     * Delete a document.
     */ delete ( ) { return this . ref . delete ( ) ; } /**
     * Create a reference to a sub-collection given a path and an optional query
     * function.
     */ collection < R = DocumentData > ( path , queryFn ? ) { const collectionRef = this . ref . collection ( path ) as firebase . firestore . CollectionReference < R > ; const { ref , query } = associateQuery ( collectionRef , queryFn ) ; return new AngularFirestoreCollection ( ref , query , this . afs ) ; } /**
     * Listen to snapshot updates from the document.
     */ snapshotChanges ( ) { const scheduledFromDocRef$ = fromDocRef < T > ( this . ref , this . afs . schedulers . outsideAngular ) ; return scheduledFromDocRef$ . pipe ( keepUnstableUntilFirst ) ; } /**
     * Listen to unwrapped snapshot updates from the document.
     *
     * If the `idField` option is provided, document IDs are included and mapped to the
     * provided `idField` property name.
     */ valueChanges ( options ? ) ; valueChanges < K extends string > ( options ) ; valueChanges < K extends string > ( options = { } ) { return this . snapshotChanges ( ) . pipe ( map ( ( { payload } ) => options . idField ? { ... payload . data ( ) , ... { [ options . idField ] : payload . id } } as T & { [ T in K ] : string ; } : payload . data ( ) ) ) ; } /**
     * Retrieve the document once.
     */ get ( options ? ) { return from ( this . ref . get ( options ) ) . pipe ( keepUnstableUntilFirst ) ; } }