dobo-redis
Version:
Redis driver for Dobo
168 lines (146 loc) • 5.96 kB
JavaScript
import { createClient } from 'redis'
import queryBuilder from '../../../lib/query-builder.js'
async function redisDriverFactory () {
const { DoboDriver } = this.app.baseClass
const { isEmpty, omit, merge } = this.app.lib._
class DoboRedisDriver extends DoboDriver {
constructor (plugin, name, options) {
super(plugin, name, options)
this.idField.name = 'id'
this.support.propType.datetime = false
}
async sanitizeConnection (item) {
await super.sanitizeConnection(item)
item.port = item.port ?? 6379
item.host = item.host ?? '127.0.0.1'
item.database = item.database ?? '0'
}
_getIndexName (model) {
return `${model.plugin.ns}:idx:${model.name}`
}
_getPrefixName (model) {
return `${model.plugin.ns}:${model.name}`
}
async connect (connection, noRebuild) {
const { host, port, user, password, database } = connection.options
const url = new URL(`redis://${host}:${port}/${database}`)
if (user) {
url.username = user
url.password = password ?? ''
}
connection.client = await createClient({ url })
connection.client.connect()
}
async modelExists (model, options = {}) {
const name = this._getIndexName(model)
const indexes = await model.connection.client.ft._list()
return { data: indexes.includes(name) }
}
async buildModel (model, options = {}) {
const name = this._getIndexName(model)
const body = { id: { type: 'TEXT', sortable: true } }
for (const index of model.indexes) {
for (const field of index.fields) {
const sortable = model.sortables.includes(field)
const prop = model.properties.find(p => p.name === field)
let type = 'TEXT'
if (['float', 'double', 'integer', 'smallint'].includes(prop.type)) type = 'NUMERIC'
body[prop.name] = { sortable, type }
}
}
if (isEmpty(body)) return
const opts = { ON: 'HASH', PREFIX: this._getPrefixName(model) }
await model.connection.client.ft.create(name, body, opts)
return { data: true }
}
async dropModel (model, options = {}) {
const name = this._getIndexName(model)
await this.clearRecord(model, options)
await model.connection.client.ft.dropIndex(name)
return { data: true }
}
async createRecord (model, body = {}, options = {}) {
const prefix = this._getPrefixName(model)
const key = `${prefix}:${body.id}`
await model.connection.client.hSet(key, body)
if (options.noResult) return
const result = await this.getRecord(model, body.id)
return result
}
async getRecord (model, id, options = {}) {
const prefix = this._getPrefixName(model)
const key = `${prefix}:${id}`
const result = await model.connection.client.hGetAll(key)
return { data: result }
}
async updateRecord (model, id, body = {}, options = {}) {
const prefix = this._getPrefixName(model)
const key = `${prefix}:${id}`
const old = options.noResult ? undefined : options._data
const nbody = omit(merge({}, old, body), ['id'])
await model.connection.client.hSet(key, nbody)
if (options.noResult) return
const result = await this.getRecord(model, id)
return { oldData: old.data, data: result.data }
}
async removeRecord (model, id, options = {}) {
const prefix = this._getPrefixName(model)
const key = `${prefix}:${id}`
const rec = options.noResult ? undefined : options._data
await model.connection.client.del(key)
if (options.noResult) return
return { oldData: rec }
}
async clearRecord (model, options = {}) {
const client = model.connection.client
const prefix = this._getPrefixName(model)
const keys = await client.keys(prefix + '*')
for (const key of keys) {
await model.connection.client.del(key)
}
return { data: true }
}
async findRecord (model, filter = {}, options = {}) {
const { paginate } = this.app.lib.aneka
const { limit, page } = filter
const resp = await this.findAllRecord(model, filter, options)
let result = paginate(resp.data, { page, limit })
if (!options.count) result = omit(result, ['count', 'pages'])
return result
}
async findAllRecord (model, filter = {}, options = {}) {
const { sort } = filter
const index = this._getIndexName(model)
const key = Object.keys(sort)[0]
let sortBy
if (key) sortBy = { SORTBY: { BY: key, DIRECTION: sort[key] < 0 ? 'DESC' : 'ASC' } }
const query = queryBuilder.call(this, filter.query ?? {}, model)
const resp = await model.connection.client.ft.search(index, query, sortBy)
const result = {
data: resp.documents.map(d => d.value)
}
if (options.count) result.count = result.data.length
return result
}
async countRecord (model, filter = {}, options = {}) {
const index = this._getIndexName(model)
const query = queryBuilder.call(this, filter.query ?? {}, model)
const resp = await model.connection.client.ft.search(index, query)
const data = resp.documents.map(d => d.value)
return { data: data.length }
}
async createAggregate (model, filter = {}, params = {}, options = {}) {
const item = await this.findAllRecord(model, filter, options)
const result = this.app.dobo.calcAggregate({ data: item.data, ...params })
return { data: result }
}
async createHistogram (model, filter = {}, params = {}, options = {}) {
const item = await this.findAllRecord(model, filter, options)
const result = this.app.dobo.calcHistogram({ data: item.data, ...params })
return { data: result }
}
}
this.app.baseClass.DoboRedisDriver = DoboRedisDriver
return DoboRedisDriver
}
export default redisDriverFactory