@keyvhq/sql
Version:
Parent class for SQL based Keyv storage adapters
119 lines (100 loc) • 2.77 kB
JavaScript
'use strict'
const { Sql } = require('sql-ts')
class KeyvSql {
constructor (options) {
this.options = Object.assign(
{
table: 'keyv',
keySize: 255,
iterationLimit: 10
},
options
)
const sql = new Sql(options.dialect)
this.entry = sql.define({
name: this.options.table,
columns: [
{
name: 'key',
primaryKey: true,
dataType: `VARCHAR(${Number(this.options.keySize)})`
},
{
name: 'value',
dataType: 'TEXT'
}
]
})
const createTable = this.entry.create().ifNotExists().toString()
const connected = this.options
.connect()
.then(query => query(createTable).then(() => query))
this.query = sqlString => connected.then(query => query(sqlString))
}
get (key) {
const select = this.entry.select().where({ key }).toString()
return this.query(select).then(rows => {
const row = rows[0]
if (row === undefined) {
return undefined
}
return row.value
})
}
set (key, value) {
if (this.options.dialect === 'mysql') {
value = value.replace(/\\/g, '\\\\')
}
const upsert =
this.options.dialect === 'postgres'
? this.entry
.insert({ key, value })
.onConflict({ columns: ['key'], update: ['value'] })
.toString()
: this.entry.replace({ key, value }).toString()
return this.query(upsert)
}
delete (key) {
if (!key) return false
const select = this.entry.select().where({ key }).toString()
const del = this.entry.delete().where({ key }).toString()
return this.query(select).then(rows => {
const row = rows[0]
if (row === undefined) {
return false
}
return this.query(del).then(() => true)
})
}
clear (namespace) {
const del = this.entry
.delete(this.entry.key.like(`${namespace ? namespace + ':' : ''}%`))
.toString()
return this.query(del).then(() => undefined)
}
async * iterator (namespace) {
const limit = Number.parseInt(this.options.iterationLimit, 10)
const entry = this.entry
async function * iterate (offset, query) {
const selectChunk = entry
.select()
.where(entry.key.like(`${namespace ? namespace + ':' : ''}%`))
.limit(limit)
.offset(offset)
.toString()
const entries = await query(selectChunk)
if (entries.length === 0) {
return
}
for (const entry of entries) {
offset += 1
yield [entry.key, entry.value]
}
if (offset !== '0') {
yield * iterate(offset, query)
}
}
yield * iterate(0, this.query)
}
}
module.exports = KeyvSql