-
-
Save elranu/80fd18e8f03f9fd5789856682b073003 to your computer and use it in GitHub Desktop.
Firestore Service
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable } from '@angular/core'; | |
import * as firebase from 'firebase/app'; | |
import { AngularFirestore, AngularFirestoreDocument, AngularFirestoreCollection } from 'angularfire2/firestore'; | |
import { Observable } from 'rxjs/Observable'; | |
import 'rxjs/add/operator/map'; | |
import 'rxjs/add/operator/do'; | |
import 'rxjs/add/operator/take'; | |
import 'rxjs/add/operator/toPromise'; | |
import 'rxjs/add/operator/switchMap'; | |
type CollectionPredicate<T> = string | AngularFirestoreCollection<T>; | |
type DocPredicate<T> = string | AngularFirestoreDocument<T>; | |
@Injectable() | |
export class FirestoreService { | |
constructor(private db: AngularFirestore) { } | |
/// ************** | |
/// Get a Reference | |
/// ************** | |
public col<T>(ref: CollectionPredicate<T>, queryFn?): AngularFirestoreCollection<T> { | |
return typeof ref === 'string' ? this.db.collection<T>(ref, queryFn) : ref; | |
} | |
public doc<T>(ref: DocPredicate<T>): AngularFirestoreDocument<T> { | |
return typeof ref === 'string' ? this.db.doc<T>(ref) : ref; | |
} | |
/// ************** | |
/// Get Data | |
/// ************** | |
public doc$<T>(ref: DocPredicate<T>): Observable<T> { | |
return this.doc(ref).snapshotChanges().map(doc => { | |
return doc.payload.data() as T; | |
}); | |
} | |
public col$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<T[]> { | |
return this.col(ref, queryFn).snapshotChanges().map(docs => { | |
return docs.map(a => a.payload.doc.data()) as T[]; | |
}); | |
} | |
/// with Ids | |
public colWithIds$<T>(ref: CollectionPredicate<T>, queryFn?): Observable<any[]> { | |
return this.col(ref, queryFn).snapshotChanges().map(actions => { | |
return actions.map(a => { | |
const data = a.payload.doc.data(); | |
const id = a.payload.doc.id; | |
return { id, ...data }; | |
}); | |
}); | |
} | |
/// with Ids | |
public docWithIds$<T>(ref: DocPredicate<T>): Observable<any> { | |
return this.doc(ref).snapshotChanges().map(a => { | |
// return actions.map(a => { | |
// }); | |
const data = a.payload.data(); | |
const id = a.payload.id; | |
return { id, ...data }; | |
}); | |
} | |
/// ************** | |
/// Write Data | |
/// ************** | |
/// Firebase Server Timestamp | |
get timestamp() { | |
return firebase.firestore.FieldValue.serverTimestamp(); | |
} | |
set<T>(ref: DocPredicate<T>, data: any) { | |
const timestamp = this.timestamp; | |
return this.doc(ref).set({ | |
...data, | |
updated_at: timestamp, | |
created_at: timestamp | |
}); | |
} | |
update<T>(ref: DocPredicate<T>, data: any) { | |
return this.doc(ref).update({ | |
...data, | |
updated_at: this.timestamp | |
}); | |
} | |
delete<T>(ref: DocPredicate<T>) { | |
return this.doc(ref).delete(); | |
} | |
public add<T>(ref: CollectionPredicate<T>, data) { | |
const timestamp = this.timestamp; | |
return this.col(ref).add({ | |
...data, | |
updated_at: timestamp, | |
created_at: timestamp | |
}); | |
} | |
geopoint(lat: number, lng: number) { | |
return new firebase.firestore.GeoPoint(lat, lng); | |
} | |
/// If doc exists update, otherwise set | |
upsert<T>(ref: DocPredicate<T>, data: any) { | |
const doc = this.doc(ref).snapshotChanges().take(1).toPromise(); | |
return doc.then(snap => { | |
return snap.payload.exists ? this.update(ref, data) : this.set(ref, data); | |
}); | |
} | |
/// ************** | |
/// Inspect Data | |
/// ************** | |
inspectDoc(ref: DocPredicate<any>): void { | |
const tick = new Date().getTime(); | |
this.doc(ref).snapshotChanges() | |
.take(1) | |
.do(d => { | |
const tock = new Date().getTime() - tick; | |
console.log(`Loaded Document in ${tock}ms`, d); | |
}) | |
.subscribe(); | |
} | |
inspectCol(ref: CollectionPredicate<any>): void { | |
const tick = new Date().getTime(); | |
this.col(ref).snapshotChanges() | |
.take(1) | |
.do(c => { | |
const tock = new Date().getTime() - tick; | |
console.log(`Loaded Collection in ${tock}ms`, c); | |
}) | |
.subscribe(); | |
} | |
/// ************** | |
/// Create and read doc references | |
/// ************** | |
/// create a reference between two documents | |
connect(host: DocPredicate<any>, key: string, doc: DocPredicate<any>) { | |
return this.doc(host).update({ [key]: this.doc(doc).ref }); | |
} | |
/// returns a documents references mapped to AngularFirestoreDocument | |
docWithRefs$<T>(ref: DocPredicate<T>) { | |
return this.doc$(ref).map(doc => { | |
for (const k of Object.keys(doc)) { | |
if (doc[k] instanceof firebase.firestore.DocumentReference) { | |
doc[k] = this.doc(doc[k].path); | |
} | |
} | |
return doc; | |
}); | |
} | |
/// ************** | |
/// Atomic batch example | |
/// ************** | |
/// Just an example, you will need to customize this method. | |
atomic() { | |
const batch = firebase.firestore().batch(); | |
/// add your operations here | |
const itemDoc = firebase.firestore().doc('items/myCoolItem'); | |
const userDoc = firebase.firestore().doc('users/userId'); | |
const currentTime = this.timestamp; | |
batch.update(itemDoc, { timestamp: currentTime }); | |
batch.update(userDoc, { timestamp: currentTime }); | |
/// commit operations | |
return batch.commit(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment