Skip to content

Commit 26ec7de

Browse files
committed
feat(fs): fs observables. action api. limit events
1 parent f8138ba commit 26ec7de

File tree

8 files changed

+297
-202
lines changed

8 files changed

+297
-202
lines changed

src/firestore/collection/changes.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { fromCollectionRef } from '../observable/fromRef';
2+
import { Query, DocumentChangeType } from 'firestore';
3+
import { Observable } from 'rxjs/Observable';
4+
import 'rxjs/add/observable/map';
5+
6+
import { DocumentChangeAction } from '../interfaces';
7+
8+
export function changes(query: Query): Observable<DocumentChangeAction[]> {
9+
return fromCollectionRef(query)
10+
.map(action =>
11+
action.payload.docChanges
12+
.map(change => ({ type: change.type, payload: change })));
13+
}
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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+
}

src/firestore/document/document.ts

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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 { QueryFn, AssociatedReference, Action } from '../interfaces';
7+
import { fromDocRef } from '../observable/fromRef';
8+
import 'rxjs/add/operator/map';
9+
10+
import { Injectable } from '@angular/core';
11+
import { FirebaseApp } from 'angularfire2';
12+
13+
import { associateQuery } from '../firestore';
14+
import { AngularFirestoreCollection } from '../collection/collection';
15+
16+
17+
/**
18+
* AngularFirestoreDocument service
19+
*
20+
* This class creates a reference to a Firestore Document. A reference is provided in
21+
* in the constructor. The class is generic which gives you type safety for data update
22+
* methods and data streaming.
23+
*
24+
* This class uses Symbol.observable to transform into Observable using Observable.from().
25+
*
26+
* This class is rarely used directly and should be created from the AngularFirestore service.
27+
*
28+
* Example:
29+
*
30+
* const fakeStock = new AngularFirestoreDocument<Stock>(firebase.firestore.doc('stocks/FAKE'));
31+
* await fakeStock.set({ name: 'FAKE', price: 0.01 });
32+
* fakeStock.valueChanges().map(snap => {
33+
* if(snap.exists) return snap.data();
34+
* return null;
35+
* }).subscribe(value => console.log(value));
36+
* // OR! Transform using Observable.from() and the data is unwrapped for you
37+
* Observable.from(fakeStock).subscribe(value => console.log(value));
38+
*/
39+
export class AngularFirestoreDocument<T> {
40+
41+
/**
42+
* The contstuctor takes in a DocumentReference to provide wrapper methods
43+
* for data operations, data streaming, and Symbol.observable.
44+
* @param ref
45+
*/
46+
constructor(public ref: DocumentReference) { }
47+
48+
/**
49+
* Create or overwrite a single document.
50+
* @param data
51+
*/
52+
set(data: T): Promise<void> {
53+
return this.ref.set(data);
54+
}
55+
56+
/**
57+
* Update some fields of a document without overwriting the entire document.
58+
* @param data
59+
*/
60+
update(data: T): Promise<void> {
61+
return this.ref.update(data);
62+
}
63+
64+
/**
65+
* Delete a document.
66+
*/
67+
delete(): Promise<void> {
68+
return this.ref.delete();
69+
}
70+
71+
/**
72+
* Create a reference to a sub-collection given a path and an optional query
73+
* function.
74+
* @param path
75+
* @param queryFn
76+
*/
77+
collection<T>(path: string, queryFn?: QueryFn): AngularFirestoreCollection<T> {
78+
const collectionRef = this.ref.collection(path);
79+
const { ref, query } = associateQuery(collectionRef, queryFn);
80+
return new AngularFirestoreCollection<T>(ref, query);
81+
}
82+
83+
/**
84+
* Listen to snapshot updates from the document.
85+
*/
86+
snapshotChanges(): Observable<Action<DocumentSnapshot>> {
87+
return fromDocRef(this.ref);
88+
}
89+
90+
/**
91+
* Listen to unwrapped snapshot updates from the document.
92+
*/
93+
valueChanges(): Observable<T> {
94+
return this.snapshotChanges().map(action => {
95+
return (action.payload.exists ? action.payload.data() : null) as T;
96+
});
97+
}
98+
}

0 commit comments

Comments
 (0)