UNPKG

prisma-cache-nosql

Version:

<div> <a href="https://www.npmjs.com/package/prisma-cache-nosql"> <img alt="npm" src="https://img.shields.io/npm/v/prisma-cache-nosql?logo=npm&logoColor=white"> </a> <a href="https://github.com/BearToCode/prisma-cache-nosql/blob/master/LICENSE"> <i

119 lines (116 loc) 5.49 kB
import { Logger } from './utils/logger.js'; import { Prisma } from '@prisma/client'; import { DefaultCacheConfig } from './types.js'; export { SupportedOperations } from './types.js'; export { adapterAceBase } from './storage/acebase.js'; export { adapterMemory } from './storage/memory.js'; function cache(opts) { const logger = new Logger(opts?.logLevel); const db = opts.adapter({ logger }); return Prisma.defineExtension((client) => { /** * Call the base prisma client method. * @param model The model name * @param operation The operation to perform * @returns The base result. */ const callBaseMethod = async (model, operation, args) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any return client[model][operation](args); }; /** * Overwrite a prisma client method with caching. * @param operation The operation to perform * @returns The overwritten method. */ const overrideMethod = (operation) => { return async function (args) { const context = Prisma.getExtensionContext(this); const model = context.$name; if (!model) { logger.error(`context.$name is undefined`); throw new Error('context.$name is undefined'); } let queryCacheArgs = undefined; if (typeof args === 'object' && args !== null && !Array.isArray(args)) { // If we don't do this TypeScript complains about wrong types // Maybe there is a better way. const _args = args; queryCacheArgs = _args.cache ?? undefined; delete _args.cache; } const cacheConfig = queryCacheArgs ?? opts.models?.[model] ?? opts.default ?? DefaultCacheConfig; logger.debug(`Cache config for model ${model} with operation ${operation}: `, cacheConfig); if (cacheConfig.get) { const cached = await db.get({ model, operation, args }); const useCache = cached && (cached._cache.expires_at === false || cached._cache.expires_at > Date.now()) && (cacheConfig.get === true || cached._cache.cached_at + cacheConfig.get.max > Date.now()); if (useCache) { logger.log(`Found cached value for model ${model} with operation ${operation}`); logger.debug(`Found cached value with age ${(new Date().getTime() - cached._cache.cached_at).toFixed(0)}ms: `, cached); return cached.result; } } const base = await callBaseMethod(model, operation, args); if (cacheConfig.set) { const cached_at = Date.now(); const expires_at = cacheConfig.set === true ? false : cached_at + cacheConfig.set.ttl; const pack = { result: base, _cache: { cached_at, expires_at } }; logger.log(`Set cache for model ${model} with operation ${operation}`); logger.debug(`Set cache: `, pack); await db.set({ model, operation, args }, pack); } return base; }; }; return client.$extends({ name: 'prisma-cache', model: { $allModels: { async findUnique(args) { return overrideMethod('findUnique').call(this, args); }, async findUniqueOrThrow(args) { return overrideMethod('findUniqueOrThrow').call(this, args); }, async findFirst(args) { return overrideMethod('findFirst').call(this, args); }, async findFirstOrThrow(args) { return overrideMethod('findFirstOrThrow').call(this, args); }, async findMany(args) { return overrideMethod('findMany').call(this, args); }, async count(args) { return overrideMethod('count').call(this, args); }, async aggregate(args) { return overrideMethod('aggregate').call(this, args); }, async groupBy(args) { return overrideMethod('groupBy').call(this, args); }, async clearCache() { const context = Prisma.getExtensionContext(this); const model = context.$name; if (!model) { logger.error(`context.$name is undefined`); throw new Error('context.$name is undefined'); } return db.clear(model); } } }, client: { async clearCache() { return db.clearAll(); } } }); }); } export { DefaultCacheConfig, cache }; //# sourceMappingURL=index.js.map