UNPKG

service-utilities

Version:

Utility Package for FIORI UI5

255 lines (236 loc) 8.51 kB
/** * @module Firebase * @description Utility class for Firebase integration * @author jpanti * @version 1.0.0 * @created 2025-08-01 * @lastModified 2025-08-01 * @license ISC */ sap.ui.define( [ "./AbstractController", "./ServiceIndexedDB", "./EventRadio", ], (AbstractController, ServiceIndexedDB, EventRadio) => { "use strict"; const eventRadio = new EventRadio("firebase"); var firebaseConfig = {}; class Firebase extends AbstractController { // Set Firebase Config ============================== setConfigs(configs) { Object.entries(configs).map( ([key, value]) => (firebaseConfig[key] = value) ); return this; } setConfig(key, value) { if (firebaseConfig.hasOwnProperty(key)) firebaseConfig[key] = value; return this; } setAPIKey = (value) => this.setConfig("apiKey", value); setAuthDomain = (value) => this.setConfig("authDomain", value); setProjectID = (value) => this.setConfig("projectId", value); setStorageBucket = (value) => this.setConfig("storageBucket", value); setMessagingSenderID = (value) => this.setConfig("messagingSenderId", value); setAppID = (value) => this.setConfig("appId", value); setMeasurementID = (value) => this.setConfig("measurementId", value); setDatabaseURL = (value) => this.setConfig("databaseURL", value); // ================================================== // Initialization =================================== #firebase; #firestore; #persistentDatabase; #state; constructor( oController, persistentDBName, { storageName = "firebase" } = {} ) { // Parent Init super(oController); this.state = "started"; this.stateTransmitter(); // Firebase Init try { this.#firebase = firebase.initializeApp(firebaseConfig); } catch { this.#firebase = firebase; } this.#firestore = firebase.firestore(); this.#persistentDatabase = new ServiceIndexedDB( storageName, persistentDBName ); // Dependency Init this.init().then(() => { this.initListeners(); this.state = "done"; this.stateTransmitter(); }); } async init() { this.#collectionArchive = await this.initArchive("collections"); this.#documentArchive = await this.initArchive("documents"); return this; } getArchive(archiveType) { if (archiveType === "collections") return this.getCollections(); if (archiveType === "documents") return this.getDocuments(); } initArchive = (archiveType, defaultValue) => this.#persistentDatabase.load(archiveType).then((loadedData) => { if (loadedData) return loadedData; loadedData = defaultValue; return this.#persistentDatabase .save(archiveType, this.getArchive(archiveType)) .then(() => this.getArchive(archiveType)); }); // ================================================== // Event Transmitters and Listeners ================= getEventRadio = () => eventRadio; stateTransmitter = (state = "transmit") => eventRadio.transmit(`init-state-${state}`, { state: this.state }); collectionsTransmitter = () => eventRadio.transmit("collections-response", { collections: this.getCollections(), }); documentsTransmitter = () => eventRadio.transmit("documents-response", { documents: this.getDocuments(), }); collectionTransmitter = (...path) => eventRadio.transmit("collection-response", { collection: this.getCollection(...path), }); documentTransmitter = (...path) => eventRadio.transmit("document-response", { document: this.getDocument(...path), }); initListeners() { eventRadio .listen("init-state-request", () => this.stateTransmitter("response")) .listen("collections-request", () => this.collectionsTransmitter()) .listen("documents-request", () => this.documentsTransmitter()) .listen("collection-request", (oData) => this.collectionTransmitter(...oData.path) ) .listen("document-request", (oData) => this.documentTransmitter(...oData.path) ); } // ================================================== // Utilities ======================================== pathSeparator(...path) { return { strFullPath: path.join("/"), strDirPath: path.slice(0, path.length - 1).join("/"), fullPath: path, dirPath: path.slice(0, path.length - 1), token: path[path.length - 1], }; } getBase() { return { firebase: this.#firebase, firestore: this.#firestore }; } // ================================================== // Collections ====================================== #collectionArchive = {}; createOCollection({ documents = [], path = undefined, token = undefined, modelname = undefined, } = {}) { return { documents, path, token, modelname }; } async syncCollection(...path) { var oCollection = this.createOCollection(); if (path.length === 0) return oCollection; const { token, strFullPath, strDirPath } = this.pathSeparator(...path); const refCollection = this.#firestore.collection(strFullPath); const collectionWrapper = await refCollection.get(); oCollection.path = strDirPath; oCollection.token = token; oCollection.documents = collectionWrapper.docs.map((doc) => doc.data()); this.#collectionArchive[strFullPath] = oCollection; await this.#persistentDatabase.save( "collections", this.#collectionArchive ); return oCollection; } async getCollection(...path) { var oCollection = this.createOCollection(); if (path.length === 0) return oCollection; const { strFullPath } = this.pathSeparator(...path); const hasOfflineCopy = this.#collectionArchive.hasOwnProperty(strFullPath); if (hasOfflineCopy) oCollection = this.#collectionArchive[strFullPath]; else oCollection = await this.syncCollection(...path); return oCollection; } getCollections() { return this.#collectionArchive; } // ================================================== // Documents ======================================== #documentArchive = {}; createODocument({ path = undefined, token = undefined, modelname = undefined, } = {}) { return { path, token, modelname }; } async getDocument(...path) { if (path.length === 0 || path.length % 2 === 1) return this.createODocument(); const { token, dirPath, strFullPath } = this.pathSeparator(...path); var oDocument; var hasOfflineCopy = this.#documentArchive.hasOwnProperty(strFullPath); if (!hasOfflineCopy) { const oCollection = await this.getCollection(...dirPath); oDocument = oCollection.documents.find( (document) => document.token === token ); } else oDocument = this.#documentArchive[strFullPath]; this.#documentArchive[strFullPath] = oDocument; if (!hasOfflineCopy) { await this.#persistentDatabase.save( "documents", this.#documentArchive ); } return oDocument; } getDocuments() { return this.#documentArchive; } // ================================================== } var instance; return { getInstance( oController, persistentDBName, { modelname = "firebase" } = {} ) { if (instance) return instance; return this.createInstance(oController, persistentDBName, { modelname, }); }, createInstance( oController, persistentDBName, { modelname = "firebase" } = {} ) { instance = new Firebase(oController, persistentDBName, { modelname }); return instance; }, }; } );