UNPKG

firebase-lib-db

Version:

Database Lib to access Firestore (CRUD) and Cache Data

411 lines (404 loc) 13.8 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropNames = Object.getOwnPropertyNames; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/v1/index.ts var v1_exports = {}; __export(v1_exports, { GetCache: () => cache_default, GetDatabase: () => database_default }); module.exports = __toCommonJS(v1_exports); // src/logger/index.ts var import_winston = __toESM(require("winston")); var loggerInstance = null; function GetLogger() { if (!loggerInstance) { loggerInstance = import_winston.default.createLogger({ level: process.env.LOG_LEVEL || "info", format: import_winston.default.format.json(), transports: [new import_winston.default.transports.Console()] }); } return loggerInstance; } var info = (message, rest) => { log("info", message, rest); }; var warn = (message, rest) => { log("warn", message, rest); }; var error = (message, rest) => { log("error", message, rest); }; var log = (severity, message, rest) => { const logger = GetLogger()[severity]; if (rest.error instanceof Error) { rest.error = { message: rest.error.message, stack: rest.error.stack }; } const metadata = __spreadValues({}, rest); if (rest.operation) { logger( `[Database] [${severity.toUpperCase()}] [${rest.operation}] - ${message}`, { metadata } ); } else { logger(`[Database] [${severity.toUpperCase()}] - ${message}`, { metadata }); } }; // src/util/ConnectionPool.ts var import_redis = require("redis"); var endpoint = process.env.REDISCLOUD_URL; var _RedisPool = class _RedisPool { static GetConnection() { return __async(this, null, function* () { if (_RedisPool.pool.length > 0) { const connection = _RedisPool.pool.pop(); if (connection) return connection; } const newConnection = (0, import_redis.createClient)({ url: endpoint }); try { yield newConnection.connect(); } catch (err) { throw new Error(`Erro ao conectar no Redis - ${err}`); } return newConnection; }); } static releaseConnection(connection) { if (!endpoint || !connection.isOpen) return; if (_RedisPool.pool.length < _RedisPool.MAX_CONNECTION) { _RedisPool.pool.push(connection); } else { connection.quit(); } } }; _RedisPool.MAX_CONNECTION = 10; _RedisPool.pool = []; var RedisPool = _RedisPool; // src/v1/cache/Redis.cache.ts var RedisRepository = class { del(key) { return __async(this, null, function* () { if (process.env.REDISCLOUD_URL) { const conn = yield RedisPool.GetConnection(); yield conn.DEL(key); RedisPool.releaseConnection(conn); } }); } get(key) { return __async(this, null, function* () { if (process.env.REDISCLOUD_URL) { const conn = yield RedisPool.GetConnection(); try { const data = yield conn.get(key); if (!data) throw new Error(); return JSON.parse(data); } catch (e) { return yield conn.GET(key); } finally { RedisPool.releaseConnection(conn); } } }); } set(key, obj, ttl) { return __async(this, null, function* () { if (process.env.REDISCLOUD_URL) { const conn = yield RedisPool.GetConnection(); if (obj) { yield conn.SETEX(key, !ttl ? 86400 : ttl, JSON.stringify(obj)); } RedisPool.releaseConnection(conn); } }); } delPattern(pattern) { return __async(this, null, function* () { if (process.env.REDISCLOUD_URL) { const conn = yield RedisPool.GetConnection(); yield conn.EVAL( "for _,k in ipairs(redis.call('keys','" + pattern + "')) do redis.call('del',k) end" ); RedisPool.releaseConnection(conn); } }); } getByPattern(pattern) { return __async(this, null, function* () { if (process.env.REDISCLOUD_URL) { let cursor = 0; const keys = []; const conn = yield RedisPool.GetConnection(); do { const reply = yield conn.scan(cursor, { MATCH: pattern, COUNT: 100 }); cursor = reply.cursor; keys.push(...reply.keys); } while (cursor !== 0); const values = []; for (const key of keys) { const value = yield conn.get(key); values.push(value); } RedisPool.releaseConnection(conn); return values; } return []; }); } }; // src/v1/cache/index.ts var cacheInstance = null; function GetCache() { if (!cacheInstance) { cacheInstance = new RedisRepository(); } return cacheInstance; } var cache_default = GetCache; // src/v1/database/Firestore.ts var import_crypto = __toESM(require("crypto")); var FirestoreDatabase = class { constructor(firestore) { this.__getCacheKey = (collectionName, data) => { const hashStr = import_crypto.default.createHash("md5").update(JSON.stringify(data)).digest("hex"); return `${collectionName}::${hashStr}`; }; this._cache = cache_default(); this._db = firestore; } Save(collectionName, data) { return __async(this, null, function* () { const operation = "SaveDocument"; try { if (data.id) { yield this._db.collection(collectionName).doc(data.id).set(__spreadProps(__spreadValues({}, data), { modified: Date.now() })); info( `The id was provided. Setting document [${data.id}] in collection ${collectionName} instead create a new one.`, { operation, collectionName, documentId: data.id } ); yield this._cache.delPattern(`${collectionName}::*`); return data.id; } const docRef = yield this._db.collection(collectionName).add(__spreadProps(__spreadValues({}, data), { modified: Date.now() })); info( `Creating a new document with id ${docRef.id} in collection ${collectionName}.`, { operation, collectionName, documentId: data.id } ); yield this._cache.delPattern(`${collectionName}::*`); return docRef.id; } catch (err) { error(`Could not Save Data in ${collectionName} - ${err.message}`, { collectionName, data, operation }); throw new Error("Could not save item in Database"); } }); } FindOne(collectionName, id) { return __async(this, null, function* () { const operation = "FindOne"; try { const cacheKey = this.__getCacheKey(collectionName, id); const cacheData = yield this._cache.get(cacheKey); if (cacheData) return cacheData; const docRef = this._db.collection(collectionName).doc(id); const docSnapshot = yield docRef.get(); if (docSnapshot.exists) { info( `Fetching data with sucess in collection ${collectionName} with id ${id}`, { collectionName, documentId: id, operation } ); const data = docSnapshot.data(); this._cache.set(cacheKey, data); return data; } warn( `Don't exists any document in collection ${collectionName} with id ${id}`, { collectionName, documentId: id, operation } ); return null; } catch (err) { error( `Could not FindOne Data - ${collectionName}[${id}] - ${err.message}`, { collectionName, documentId: id, operation } ); throw new Error("Could not fetch data. Try again later"); } }); } QueryData(collectionName, wheres, orderBy, noCache) { return __async(this, null, function* () { const operation = "QueryData"; try { let queryRef = this._db.collection(collectionName); wheres == null ? void 0 : wheres.forEach((where) => { queryRef = queryRef.where(where == null ? void 0 : where.field, where == null ? void 0 : where.operator, where == null ? void 0 : where.value); }); if (orderBy) { queryRef = queryRef.orderBy(orderBy.field, orderBy.direction); } const cacheKey = this.__getCacheKey(collectionName, queryRef); const cached = yield this._cache.get(cacheKey); if (cached && !noCache) return cached; const querySnapshot = yield queryRef.get(); const res = querySnapshot.docs.map((doc) => doc.data()); if (!noCache) this._cache.set(cacheKey, res); return res; } catch (err) { error( `Could not Query Data - ${collectionName}[Wheres: ${JSON.stringify( wheres )}][OrderBy >> Field: ${orderBy == null ? void 0 : orderBy.field} | Direction: ${orderBy == null ? void 0 : orderBy.direction}] - ${err.message}`, { collectionName, operation } ); throw new Error(err.message); } }); } Delete(collectionName, query) { return __async(this, null, function* () { const operation = "DeleteData"; try { const idsDeleted = []; const queryResult = this._db.collection(collectionName).where(query.field, "==", query.value); const snapshot = yield queryResult.get(); const batch = this._db.batch(); snapshot.forEach((doc) => { batch.delete(doc.ref); idsDeleted.push(doc.id); }); yield batch.commit(); info( `Deleting data in collection ${collectionName}. Ids deleted: ${idsDeleted}`, { collectionName, operation } ); yield this._cache.delPattern(`${collectionName}::*`); } catch (err) { error( `Could not Delete Data - ${collectionName}[Wheres: ${JSON.stringify( query )}] - ${err.message}`, { collectionName, operation } ); throw new Error("Error while delete. Try again later"); } }); } Update(collectionName, id, data) { return __async(this, null, function* () { const operation = "UpdateDocument"; try { const docRef = this._db.collection(collectionName).doc(id); yield docRef.update(__spreadProps(__spreadValues({}, data), { modified: Date.now() })); info(`Updating document ${id} in collection ${collectionName}`, { operation, documentId: id, collectionName }); yield this._cache.delPattern(`${collectionName}::*`); return true; } catch (err) { error( `Could not Update Document - ${collectionName}[${id}] - ${err.message}`, { collectionName, documentId: id, data, operation } ); throw new Error("Error while Update data. Try again later."); } }); } }; // src/v1/database/index.ts var databaseInstance = null; function GetDatabase(firestore) { if (!databaseInstance) { databaseInstance = new FirestoreDatabase(firestore); } return databaseInstance; } var database_default = GetDatabase; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { GetCache, GetDatabase }); //# sourceMappingURL=index.js.map