Add support for jobs & queueables, migrations
Some checks failed
continuous-integration/drone/push Build is passing
continuous-integration/drone Build is failing

- 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
This commit is contained in:
2021-08-23 23:51:53 -05:00
parent 26e0444e40
commit 074a3187eb
28 changed files with 962 additions and 56 deletions

View File

@@ -1,5 +1,5 @@
import {Container} from '../../di'
import {Cache} from '../../util'
import {Awaitable, Cache, ErrorWithContext, Maybe} from '../../util'
import {CacheModel} from './CacheModel'
/**
@@ -7,14 +7,7 @@ import {CacheModel} from './CacheModel'
*/
export class ORMCache extends Cache {
public async fetch(key: string): Promise<string | undefined> {
const model = await CacheModel.query<CacheModel>()
.where(CacheModel.qualifyKey(), '=', key)
.where(CacheModel.propertyToColumn('cacheExpires'), '>', new Date())
.first()
if ( model ) {
return model.cacheValue
}
return (await CacheModel.getCacheKey(key))?.cacheValue
}
public async put(key: string, value: string, expires?: Date): Promise<void> {
@@ -31,15 +24,103 @@ export class ORMCache extends Cache {
}
public async has(key: string): Promise<boolean> {
return CacheModel.query()
.where(CacheModel.qualifyKey(), '=', key)
.where(CacheModel.propertyToColumn('cacheExpires'), '>', new Date())
return CacheModel.withCacheKey(key)
.exists()
}
public async drop(key: string): Promise<void> {
await CacheModel.query()
.where(CacheModel.qualifyKey(), '=', key)
.whereKey(key)
.delete()
}
public async pop(key: string): Promise<string> {
return CacheModel.getConnection()
.asTransaction<string>(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<number> {
return CacheModel.getConnection()
.asTransaction<number>(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<number> {
return CacheModel.getConnection()
.asTransaction<number>(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<void> {
await CacheModel.getConnection()
.asTransaction<void>(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<Maybe<string>> {
return CacheModel.getConnection()
.asTransaction<Maybe<string>>(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
})
}
}