garrettmills
074a3187eb
- Create migration directives & migrators - Modify Cache classes to support array manipulation - Create Redis unit and RedisCache implementation - Create Queueable base class and Queue class that uses Cache backend
107 lines
3.0 KiB
TypeScript
107 lines
3.0 KiB
TypeScript
import { Cache } from './Cache'
|
|
import { Collection } from '../collection/Collection'
|
|
import {Awaitable, Maybe} from '../support/types'
|
|
import {ErrorWithContext} from '../error/ErrorWithContext'
|
|
|
|
/**
|
|
* 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>()
|
|
|
|
public async fetch(key: string): Promise<string | undefined> {
|
|
const item = this.items.firstWhere('key', '=', key)
|
|
if ( item ) {
|
|
return item.item
|
|
}
|
|
}
|
|
|
|
public async put(key: string, item: string): Promise<void> {
|
|
const existing = this.items.firstWhere('key', '=', key)
|
|
if ( existing ) {
|
|
existing.item = item
|
|
} else {
|
|
this.items.push({ key,
|
|
item })
|
|
}
|
|
}
|
|
|
|
public async has(key: string): Promise<boolean> {
|
|
return this.items.where('key', '=', key).length > 0
|
|
}
|
|
|
|
public async drop(key: string): Promise<void> {
|
|
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
|
|
}
|
|
}
|