UNPKG

firebase-lib-db

Version:

Database Lib to access Firestore (CRUD) and Cache Data

1 lines 18.8 kB
{"version":3,"sources":["../src/logger/index.ts","../src/util/ConnectionPool.ts","../src/v1/cache/Redis.cache.ts","../src/v1/cache/index.ts","../src/v1/database/Firestore.ts","../src/v1/database/index.ts"],"sourcesContent":["import winston, { Logger } from \"winston\";\n\nlet loggerInstance: winston.Logger | null = null;\n\nfunction GetLogger(): Logger {\n if (!loggerInstance) {\n loggerInstance = winston.createLogger({\n level: process.env.LOG_LEVEL || \"info\",\n format: winston.format.json(),\n transports: [new winston.transports.Console()],\n });\n }\n return loggerInstance;\n}\n\nexport const info = (message: string, rest: any) => {\n log(\"info\", message, rest);\n};\n\nexport const warn = (message: string, rest: any) => {\n log(\"warn\", message, rest);\n};\n\nexport const error = (message: string, rest: any) => {\n log(\"error\", message, rest);\n};\n\nexport const debug = (message: string, rest: any) => {\n log(\"debug\", message, rest);\n};\n\nconst log = (\n severity: \"info\" | \"warn\" | \"error\" | \"debug\",\n message: string,\n rest: any\n) => {\n const logger = GetLogger()[severity];\n if (rest.error instanceof Error) {\n rest.error = {\n message: rest.error.message,\n stack: rest.error.stack,\n };\n }\n const metadata = {\n ...rest,\n };\n if (rest.operation) {\n logger(\n `[Database] [${severity.toUpperCase()}] [${rest.operation}] - ${message}`,\n { metadata }\n );\n } else {\n logger(`[Database] [${severity.toUpperCase()}] - ${message}`, {\n metadata,\n });\n }\n};\n\nexport default GetLogger;\n","import { createClient, RedisClientType } from \"redis\";\n\nconst endpoint = process.env.REDISCLOUD_URL;\n\nexport default class RedisPool {\n private static readonly MAX_CONNECTION = 10;\n private static pool: RedisClientType[] = [];\n\n public static async GetConnection(): Promise<RedisClientType> {\n if (RedisPool.pool.length > 0) {\n const connection = RedisPool.pool.pop();\n\n if (connection) return connection;\n }\n\n const newConnection: RedisClientType = createClient({ url: endpoint });\n try {\n await newConnection.connect();\n } catch (err) {\n throw new Error(`Erro ao conectar no Redis - ${err}`);\n }\n\n return newConnection;\n }\n\n public static releaseConnection(connection: RedisClientType): void {\n if (!endpoint || !connection.isOpen) return;\n\n if (RedisPool.pool.length < RedisPool.MAX_CONNECTION) {\n RedisPool.pool.push(connection);\n } else {\n connection.quit();\n }\n }\n}\n","import RedisConnectionPool from \"../../util/ConnectionPool\";\nimport Cache from \"./Cache\";\n\nexport default class RedisRepository implements Cache {\n async del(key: string): Promise<void> {\n if (process.env.REDISCLOUD_URL) {\n const conn = await RedisConnectionPool.GetConnection();\n await conn.DEL(key);\n RedisConnectionPool.releaseConnection(conn);\n }\n }\n\n async get(key: string): Promise<any> {\n if (process.env.REDISCLOUD_URL) {\n const conn = await RedisConnectionPool.GetConnection();\n try {\n const data = await conn.get(key);\n\n if (!data) throw new Error();\n\n return JSON.parse(data);\n } catch (e) {\n return await conn.GET(key);\n } finally {\n RedisConnectionPool.releaseConnection(conn);\n }\n }\n }\n\n async set(key: string, obj: any, ttl?: number): Promise<void> {\n if (process.env.REDISCLOUD_URL) {\n const conn = await RedisConnectionPool.GetConnection();\n if (obj) {\n await conn.SETEX(key, !ttl ? 86400 : ttl, JSON.stringify(obj));\n }\n RedisConnectionPool.releaseConnection(conn);\n }\n }\n\n async delPattern(pattern: string): Promise<void> {\n if (process.env.REDISCLOUD_URL) {\n const conn = await RedisConnectionPool.GetConnection();\n await conn.EVAL(\n \"for _,k in ipairs(redis.call('keys','\" +\n pattern +\n \"')) do redis.call('del',k) end\"\n );\n RedisConnectionPool.releaseConnection(conn);\n }\n }\n\n async getByPattern(pattern: string): Promise<any[]> {\n if (process.env.REDISCLOUD_URL) {\n let cursor: number = 0;\n const keys = [];\n const conn = await RedisConnectionPool.GetConnection();\n do {\n const reply = await conn.scan(cursor, {\n MATCH: pattern,\n COUNT: 100,\n });\n cursor = reply.cursor;\n keys.push(...reply.keys);\n } while (cursor !== 0);\n\n const values = [];\n\n for (const key of keys) {\n const value = await conn.get(key);\n values.push(value);\n }\n\n RedisConnectionPool.releaseConnection(conn);\n return values;\n }\n\n return [];\n }\n}\n","import Cache from \"./Cache\";\nimport RedisRepository from \"./Redis.cache\";\n\nlet cacheInstance: Cache | null = null;\nexport function GetCache(): Cache {\n if (!cacheInstance) {\n cacheInstance = new RedisRepository();\n }\n return cacheInstance;\n}\n\nexport default GetCache;\n\n","import Database from \"./Database\";\nimport { firestore } from \"firebase-admin\";\nimport { error, info, warn } from \"../../logger\";\nimport Cache from \"../cache/Cache\";\nimport GetCache from \"../cache\";\nimport crypto from \"crypto\";\n\nexport class FirestoreDatabase implements Database {\n private _db: firestore.Firestore;\n private _cache: Cache;\n\n constructor(firestore: firestore.Firestore) {\n this._cache = GetCache();\n this._db = firestore;\n }\n\n async Save(collectionName: string, data: any): Promise<string> {\n const operation: string = \"SaveDocument\";\n try {\n if (data.id) {\n await this._db\n .collection(collectionName)\n .doc(data.id)\n .set({ ...data, modified: Date.now() });\n info(\n `The id was provided. Setting document [${data.id}] in collection ${collectionName} instead create a new one.`,\n { operation, collectionName, documentId: data.id }\n );\n await this._cache.delPattern(`${collectionName}::*`); //Clear cache by pattern\n return data.id;\n }\n\n const docRef = await this._db\n .collection(collectionName)\n .add({ ...data, modified: Date.now() });\n info(\n `Creating a new document with id ${docRef.id} in collection ${collectionName}.`,\n { operation, collectionName, documentId: data.id }\n );\n await this._cache.delPattern(`${collectionName}::*`); //Clear cache by pattern\n return docRef.id;\n } catch (err: any) {\n error(`Could not Save Data in ${collectionName} - ${err.message}`, {\n collectionName,\n data,\n operation,\n });\n throw new Error(\"Could not save item in Database\");\n }\n }\n\n async FindOne(collectionName: string, id: string): Promise<any> {\n const operation: string = \"FindOne\";\n try {\n const cacheKey = this.__getCacheKey(collectionName, id);\n const cacheData = await this._cache.get(cacheKey);\n\n if (cacheData) return cacheData;\n\n const docRef = this._db.collection(collectionName).doc(id);\n const docSnapshot = await docRef.get();\n\n if (docSnapshot.exists) {\n info(\n `Fetching data with sucess in collection ${collectionName} with id ${id}`,\n { collectionName, documentId: id, operation }\n );\n const data = docSnapshot.data();\n this._cache.set(cacheKey, data);\n return data;\n }\n\n warn(\n `Don't exists any document in collection ${collectionName} with id ${id}`,\n { collectionName, documentId: id, operation }\n );\n return null;\n } catch (err: any) {\n error(\n `Could not FindOne Data - ${collectionName}[${id}] - ${err.message}`,\n { collectionName, documentId: id, operation }\n );\n\n throw new Error(\"Could not fetch data. Try again later\");\n }\n }\n\n async QueryData(\n collectionName: string,\n wheres: {\n field: string;\n operator: FirebaseFirestore.WhereFilterOp;\n value: any;\n }[],\n orderBy: { field: string; direction: firestore.OrderByDirection },\n noCache?: boolean\n ): Promise<Array<any>> {\n const operation: string = \"QueryData\";\n\n try {\n let queryRef: FirebaseFirestore.Query =\n this._db.collection(collectionName);\n\n wheres?.forEach((where) => {\n queryRef = queryRef.where(where?.field, where?.operator, where?.value);\n });\n\n if (orderBy) {\n queryRef = queryRef.orderBy(orderBy.field, orderBy.direction);\n }\n\n const cacheKey = this.__getCacheKey(collectionName, queryRef);\n\n const cached = await this._cache.get(cacheKey);\n if (cached && !noCache) return cached;\n\n const querySnapshot = await queryRef.get();\n\n const res = querySnapshot.docs.map((doc) => doc.data());\n\n if (!noCache) this._cache.set(cacheKey, res);\n\n return res;\n } catch (err: any) {\n error(\n `Could not Query Data - ${collectionName}[Wheres: ${JSON.stringify(\n wheres\n )}][OrderBy >> Field: ${orderBy?.field} | Direction: ${\n orderBy?.direction\n }] - ${err.message}`,\n { collectionName, operation }\n );\n throw new Error(err.message);\n }\n }\n\n async Delete(\n collectionName: string,\n query: { field: string; value: string }\n ): Promise<any> {\n const operation: string = \"DeleteData\";\n try {\n const idsDeleted: string[] = [];\n const queryResult = this._db\n .collection(collectionName)\n .where(query.field, \"==\", query.value);\n const snapshot = await queryResult.get();\n const batch = this._db.batch();\n\n snapshot.forEach((doc) => {\n batch.delete(doc.ref);\n idsDeleted.push(doc.id);\n });\n\n await batch.commit();\n info(\n `Deleting data in collection ${collectionName}. Ids deleted: ${idsDeleted}`,\n { collectionName, operation }\n );\n\n await this._cache.delPattern(`${collectionName}::*`);\n } catch (err: any) {\n error(\n `Could not Delete Data - ${collectionName}[Wheres: ${JSON.stringify(\n query\n )}] - ${err.message}`,\n { collectionName, operation }\n );\n throw new Error(\"Error while delete. Try again later\");\n }\n }\n\n async Update(collectionName: string, id: string, data: any): Promise<any> {\n const operation: string = \"UpdateDocument\";\n try {\n const docRef = this._db.collection(collectionName).doc(id);\n await docRef.update({ ...data, modified: Date.now() });\n info(`Updating document ${id} in collection ${collectionName}`, {\n operation,\n documentId: id,\n collectionName,\n });\n await this._cache.delPattern(`${collectionName}::*`); //Clear cache by pattern\n return true;\n } catch (err: any) {\n error(\n `Could not Update Document - ${collectionName}[${id}] - ${err.message}`,\n { collectionName, documentId: id, data, operation }\n );\n throw new Error(\"Error while Update data. Try again later.\");\n }\n }\n\n private __getCacheKey = (collectionName: string, data: any) => {\n const hashStr = crypto\n .createHash(\"md5\")\n .update(JSON.stringify(data))\n .digest(\"hex\");\n return `${collectionName}::${hashStr}`;\n };\n}\n","import {firestore} from \"firebase-admin\";\nimport Database from \"./Database\";\nimport {FirestoreDatabase} from \"./Firestore\";\n\nlet databaseInstance: Database | null = null;\n\nfunction GetDatabase(firestore: firestore.Firestore): Database {\n if (!databaseInstance) {\n databaseInstance = new FirestoreDatabase(firestore);\n }\n return databaseInstance;\n}\n\nexport default GetDatabase;\n\n"],"mappings":"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","names":[]}