import {Container} from '../../di' import {Awaitable, Cache, ErrorWithContext, Maybe} from '../../util' import {CacheModel} from './CacheModel' /** * A cache driver whose records are stored in a database table using the CacheModel. */ export class ORMCache extends Cache { public async fetch(key: string): Promise { return (await CacheModel.getCacheKey(key))?.cacheValue } public async put(key: string, value: string, expires?: Date): Promise { let model = await CacheModel.findByKey(key) if ( !model ) { model = Container.getContainer().make(CacheModel) } model.cacheKey = key model.cacheValue = value model.cacheExpires = expires await model.save() } public async has(key: string): Promise { return CacheModel.withCacheKey(key) .exists() } public async drop(key: string): Promise { await CacheModel.query() .whereKey(key) .delete() } public async pop(key: string): Promise { return CacheModel.getConnection() .asTransaction(async () => { const model = await CacheModel.getCacheKey(key) if ( !model ) { throw new ErrorWithContext('Cannot pop cache value: key does not exist.', { key, }) } await model.delete() return model.cacheValue }) } public increment(key: string, amount = 1): Awaitable { return CacheModel.getConnection() .asTransaction(async () => { const model = await CacheModel.getCacheKey(key) if ( !model ) { await this.put(key, String(amount)) return amount } model.cacheValue = String(parseInt(model.cacheValue, 10) + amount) await model.save() return parseInt(model.cacheValue, 10) }) } public decrement(key: string, amount = 1): Awaitable { return CacheModel.getConnection() .asTransaction(async () => { const model = await CacheModel.getCacheKey(key) if ( !model ) { await this.put(key, String(-amount)) return amount } model.cacheValue = String(parseInt(model.cacheValue, 10) - amount) await model.save() return parseInt(model.cacheValue, 10) }) } public async arrayPush(key: string, value: string): Promise { await CacheModel.getConnection() .asTransaction(async () => { const model = await CacheModel.getCacheKey(key) if ( !model ) { await this.put(key, JSON.stringify([value])) return } const cacheValue = JSON.parse(model.cacheValue) if ( !Array.isArray(cacheValue) ) { throw new ErrorWithContext('Cannot push value to non-array.', { key, }) } cacheValue.push(value) model.cacheValue = JSON.stringify(cacheValue) }) throw new Error('Method not implemented.') } public async arrayPop(key: string): Promise> { return CacheModel.getConnection() .asTransaction>(async () => { const model = await CacheModel.getCacheKey(key) if ( !model ) { return } const cacheValue = JSON.parse(model.cacheValue) if ( !Array.isArray(cacheValue) ) { throw new ErrorWithContext('Cannot pop value from non-array.', { key, }) } const value = cacheValue.pop() model.cacheValue = JSON.stringify(cacheValue) await model.save() return value }) } }