lib/src/util/cache/InMemCache.ts

107 lines
3.0 KiB
TypeScript
Raw Normal View History

2021-06-02 01:59:40 +00:00
import { Cache } from './Cache'
import { Collection } from '../collection/Collection'
import {Awaitable, Maybe} from '../support/types'
import {ErrorWithContext} from '../error/ErrorWithContext'
2021-06-02 01:59:40 +00:00
/**
* Base interface for an item stored in a memory cache.
*/
export interface InMemCacheItem {
key: string,
item: string,
}
/**
* A cache implementation stored in memory.
* @extends Cache
*/
export class InMemCache extends Cache {
/**
* The stored cache items.
* @type Collection<InMemCacheItem>
*/
protected items: Collection<InMemCacheItem> = new Collection<InMemCacheItem>()
2021-06-03 03:36:25 +00:00
public async fetch(key: string): Promise<string | undefined> {
2021-06-02 01:59:40 +00:00
const item = this.items.firstWhere('key', '=', key)
2021-06-03 03:36:25 +00:00
if ( item ) {
return item.item
}
2021-06-02 01:59:40 +00:00
}
2021-06-03 03:36:25 +00:00
public async put(key: string, item: string): Promise<void> {
2021-06-02 01:59:40 +00:00
const existing = this.items.firstWhere('key', '=', key)
2021-06-03 03:36:25 +00:00
if ( existing ) {
existing.item = item
} else {
this.items.push({ key,
item })
}
2021-06-02 01:59:40 +00:00
}
2021-06-03 03:36:25 +00:00
public async has(key: string): Promise<boolean> {
2021-06-02 01:59:40 +00:00
return this.items.where('key', '=', key).length > 0
}
2021-06-03 03:36:25 +00:00
public async drop(key: string): Promise<void> {
2021-06-02 01:59:40 +00:00
this.items = this.items.whereNot('key', '=', key)
}
public pop(key: string): Awaitable<Maybe<string>> {
const existing = this.items.firstWhere('key', '=', key)
this.items = this.items.where('key', '!=', key)
return existing?.item
}
public async increment(key: string, amount?: number): Promise<number> {
const next = parseInt((await this.fetch(key)) ?? '0', 10) + (amount ?? 1)
await this.put(key, String(next))
return next
}
public async decrement(key: string, amount?: number): Promise<number> {
const next = parseInt((await this.fetch(key)) ?? '0', 10) - (amount ?? 1)
await this.put(key, String(next))
return next
}
public arrayPush(key: string, value: string): Awaitable<void> {
const existing = this.items.where('key', '=', key).first()
const arr = JSON.parse(existing?.item ?? '[]')
if ( !Array.isArray(arr) ) {
throw new ErrorWithContext('Unable to arrayPush: key is not an array', {
key,
value,
})
}
arr.push(value)
if ( existing ) {
existing.item = JSON.stringify(arr)
} else {
this.items.push({
key,
item: JSON.stringify(arr),
})
}
}
public arrayPop(key: string): Awaitable<Maybe<string>> {
const existing = this.items.where('key', '=', key).first()
const arr = JSON.parse(existing?.item ?? '[]')
const value = arr.pop()
if ( existing ) {
existing.item = JSON.stringify(arr)
} else {
this.items.push({
key,
item: JSON.stringify(arr),
})
}
return value
}
2021-06-02 01:59:40 +00:00
}