You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
loc-chain-backend/src/app/FirebaseResource.ts

138 lines
4.1 KiB

import {Inject, Injectable} from "@extollo/di"
import {collect, Collection, Iterable} from "@extollo/util"
import {FirebaseUnit, RTDBRef} from "./units/FirebaseUnit"
import * as firebase from "firebase-admin"
import {Application} from "@extollo/lib"
/**
* Base interface for an item in a Firebase RTDB collection.
*/
export interface FirebaseResourceItem {
firebaseID?: string;
}
/**
* An asynchronous iterable wrapper that enables us to use AsyncCollection
* to interact with the Firebase realtime database.
*/
@Injectable()
export class FirebaseResource<T extends FirebaseResourceItem> extends Iterable<T> {
protected refName!: RTDBRef
get firebase() {
return Application.getApplication().make<FirebaseUnit>(FirebaseUnit)
}
/** Get the Reference for this resource. */
ref(): firebase.database.Reference {
return Application.getApplication().make<FirebaseUnit>(FirebaseUnit).ref(this.refName)
}
/** Get the record at the ith index. */
async at(i: number): Promise<T | undefined> {
return new Promise<T | undefined>((res, rej) => {
this.ref().orderByKey()
.startAt(i).endAt(i)
.once('value', snapshot => res(this.resolveObject(snapshot.val())[0]), rej)
})
}
/** Fetch an array of records in a range. */
async range(start: number, end: number): Promise<Collection<T>> {
return new Promise<Collection<T>>((res, rej) => {
this.ref().orderByKey()
.startAt(start).endAt(end)
.once('value', snapshot => {
res(new Collection<T>(this.resolveObject(snapshot.val())))
}, rej)
})
}
/** Count the items in the collection. */
async count(): Promise<number> {
console.log('[COUNT CALLED ON FIREBASE RESOURCE]')
return new Promise<number>((res, rej) => {
this.ref().orderByKey()
.once('value', snapshot => {
res(this.resolveObject(snapshot.val()).length)
}, rej)
})
}
/**
* Push a new item into the collection.
* @param item
*/
async push(item: T): Promise<T> {
await this.ref().push(item)
return item
/*await this.ref().transaction((collection) => {
if ( !collection ) collection = []
if ( typeof collection === 'object' ) collection = Object.values(collection)
item.seqID = this.findNextId(collection)
// @ts-ignore
delete item.firebaseID
collection.push(this.filter(item))
console.log('item seqID', collection)
return collection
})
await new Promise<void>(res => {
this.ref()
.orderByChild('seqID')
.startAt(item.seqID)
.limitToFirst(1)
.once('value', snapshot => {
item.firebaseID = snapshot.key || ''
res()
})
})
return item*/
}
/**
* Given the value of a realtime-database snapshot, resolve it to an array of T.
* @param snapshot
* @protected
*/
protected resolveObject(snapshot: any | null | undefined) {
if ( !snapshot ) snapshot = {}
const returns: T[] = []
for ( const key in snapshot ) {
if ( !snapshot.hasOwnProperty(key) ) continue
snapshot[key].firebaseID = key
returns.push(snapshot[key])
}
return returns
}
clone(): Iterable<T> {
const inst = new FirebaseResource<T>()
inst.refName = this.refName
return inst
}
filter(obj: {[key: string]: any}) {
for (let key in obj) {
if (obj[key] === undefined) {
delete obj[key]
continue
}
if (obj[key] && typeof obj[key] === "object") {
this.filter(obj[key])
if (!Object.keys(obj[key]).length) {
delete obj[key]
}
}
}
return obj
}
}