3
\$\begingroup\$

I've written a service for firebase that handles all my Firestore calls. The goal is to only read the database once on app init( load() function) and then keep a copy of the database inside local storage so that we won't be charged for unnecessary database reads every time we write to the database, this code works and does exactly what I want it to however I find myself wanting to refactor to make it more maintainable and adhere to programing conventions; however I am self taught so I have no idea what I am doing as it regards to how its supposed to be done, so what I'm looking for is for people to pick this code apart and give me feedback on what to do better. PS: the dataControl class used all over this service is defined at the end of the service code.

TL;DR
please review this code, and tell me where I can improve.

import { Injectable } from '@angular/core';
import { AngularFirestore } from '@angular/fire/firestore';
import { take } from 'rxjs/operators';
import { combineLatest, BehaviorSubject } from 'rxjs';

@Injectable({
    providedIn: 'root'
})
export class DatabaseService {
    constructor(private afs: AngularFirestore) {}

//allows me to subscribe to the 'local database' just as I would to firestore
    private subject: BehaviorSubject<any> = new BehaviorSubject('');
    stream$ = this.subject.asObservable();




//Loads the 'local database' from firestore with APP_INITALIZER in module

    load() {
        return new Promise(resolve => {
            console.log('run');
            localStorage.clear();
            var docs = this.afs.collection('Developers').valueChanges();
            var locs = this.afs.collection('Locations').valueChanges();
            var rules = this.afs.collection('Rules').valueChanges();
            var combined = combineLatest(docs, locs, rules);
            combined.pipe(take(1)).subscribe((_val: any) => {
                var OBJ = {
                    Developers: _val[0],
                    Locations: _val[1],
                    Rules: _val[2]
                };
                localStorage.setItem('adminData', JSON.stringify(OBJ));
                this.subject.next(OBJ);
            });
            resolve();
        });
    }

//returns either a collection from the 'local database' or a specific document

    read(_path: string) {
        var control = new dataControl(_path);
        return !control.doc ? control.collectionData : control.documentData;
    }


//deletes a document from the 'local database' and firestore, calls next on the stream so all values from stream$ are changed

    delete(_path: string) {
        var control = new dataControl(_path);
        if (control.doc) {
            control.collectionData.splice(control.index, 1);
            control.return();
            this.subject.next(JSON.parse(localStorage.getItem('adminData')));
            this.afs
                .collection(control.collection)
                .doc(control.doc)
                .delete();
        }
    }


//writes data to the 'local database' and firestore calls next on the stream so all values from stream$ are changed
    write(_data: any, _path: string) {
        var control = new dataControl(_path);
        _data.meta = control.doc;
        var dataExists = control.index !== -1;
        if (dataExists) {
            control.collectionData = control.collectionData.map((_obj: any) => {
                if (_obj.meta === control.doc) {
                    return { ..._obj, ..._data };
                } else {
                    return _obj;
                }
            });
        } else {
            control.collectionData = [_data, ...control.collectionData];
        }
        control.return();
        this.subject.next(JSON.parse(localStorage.getItem('adminData')));
        this.afs
            .collection(control.collection)
            .doc(control.doc)
            .set(_data, { merge: true });
    }
}



export class dataControl {
    constructor(_path: string) {
        this.cache = _path.split('/');
        this.collection = this.cache[0];
        this.doc = this.cache[1];
        this.og = JSON.parse(localStorage.getItem('adminData'));
        this.initializeData(_path);
    }
    private cache: string[];
    private cd: any[];
    private dd: object;
    private og: any;
    collection: string;
    doc: string;
    index: number;
    get collectionData() {
        if (!!this.cd) {
            return this.cd;
        } else {
            console.log('CollectionData is undefined');
        }
    }
    get original() {
        return this.og;
    }
    set collectionData(dat) {
        this.cd = dat;
    }
    get documentData() {
        if (!!this.dd) {
            return this.dd;
        } else {
            console.log('documentData is undefined');
        }
    }
    private initializeData(_path: string): void {
        this.cd = this.original[this.collection];
        if (this.doc) {
            var metaMap = this.original[this.collection].map((_val: any) => {
                return _val.meta;
            });
            this.index = metaMap.indexOf(this.doc);
            this.dd = this.original[this.collection][this.index];
        }
    }
    return() {
        this.original[this.collection] = this.collectionData;
        localStorage.setItem('adminData', JSON.stringify(this.original));
    }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.