Skip to content

Instantly share code, notes, and snippets.

@wcandillon
Created October 17, 2017 19:22
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wcandillon/81995257fc339d7f30d53902e89c1f47 to your computer and use it in GitHub Desktop.
Save wcandillon/81995257fc339d7f30d53902e89c1f47 to your computer and use it in GitHub Desktop.
import * as fb from "firebase";
import { computed, observable, runInAction } from "mobx";
type Query = fb.firestore.Query;
type DocumentReference = fb.firestore.DocumentReference;
type DocumentSnapshot = fb.firestore.DocumentSnapshot;
type LoadingDocumentSnapshot = DocumentSnapshot | undefined;
type Dictionary<T> = { [key: string]: T };
// type QuerySnapshot = fb.firestore.QuerySnapshot;
// type LoadingCollectionSnapshot = QuerySnapshot | undefined;
export interface FireResource<T> {
exists(): boolean;
loading(): boolean;
get(): T;
}
export class FireDocument<T> implements FireResource<T> {
private name: string;
@observable private _snapshot: LoadingDocumentSnapshot = undefined;
@computed get snapshot() { return this._snapshot; }
set snapshot(snapshot: LoadingDocumentSnapshot) { this._snapshot = snapshot; }
constructor(doc: DocumentReference) {
this.load(doc);
}
exists() {
return this.snapshot !== undefined && this.snapshot.exists;
}
loading() {
return this.snapshot === undefined;
}
get(): T {
if (this.snapshot !== undefined && this.snapshot.exists) {
return this.snapshot.data() as T;
} else {
throw new Error(`Snapshot for ${this.name} doesn't exist`);
}
}
private async load(doc: DocumentReference) {
this.snapshot = await doc.get();
}
}
export class FireCollection<T, U = Dictionary<T>> implements FireResource<U> {
private name: string;
private filter: (doc: DocumentSnapshot) => boolean;
private transform: (docs: DocumentSnapshot[]) => U;
@observable private _snapshot: U | undefined = undefined;
@observable private _exists: boolean = false;
@computed get snapshot() { return this._snapshot; }
set snapshot(snapshot: U | undefined) { this._snapshot = snapshot; }
constructor(col: Query) {
this.load(col);
this.transform =
(docs: DocumentSnapshot[]) =>
Object.assign({}, ...docs.map(doc => ({ [doc.id]: doc.data() as T })));
}
loading() {
return this.snapshot === undefined;
}
exists() {
return this._exists;
}
setFilter(filter: (doc: DocumentSnapshot) => boolean) {
this.filter = filter;
}
setTransform(transform: (docs: DocumentSnapshot[]) => U) {
this.transform = transform;
}
get(): U {
if (this.snapshot !== undefined && this.exists()) {
return this.snapshot;
} else {
throw new Error(`Snapshot for ${this.name} doesn't exist`);
}
}
private async load(col: Query) {
const snapshot = await col.get();
const filtered = snapshot.docs.filter(doc => this.filter ? this.filter(doc) : true);
runInAction(() => this._exists = filtered.length > 0);
this.snapshot = this.transform(filtered);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment