Browse Source

feat: add emitErrors option

master
Kiko Beats 3 years ago
parent
commit
0c13a187b6
No known key found for this signature in database GPG Key ID: 8FA93B22CCF04B96
  1. 15
      packages/keyv-mongo/src/index.js
  2. 6
      packages/keyv-redis/src/index.js
  3. 116
      packages/keyv-sql/src/index.js
  4. 7
      packages/keyv/README.md
  5. 8
      packages/keyv/src/index.js
  6. 14
      packages/keyv/test/keyv.js

15
packages/keyv-mongo/src/index.js

@ -20,7 +20,8 @@ class KeyvMongo extends EventEmitter {
this.options = Object.assign(
{
url: 'mongodb://127.0.0.1:27017',
collection: 'keyv'
collection: 'keyv',
emitErrors: true
},
url,
options
@ -40,7 +41,7 @@ class KeyvMongo extends EventEmitter {
this.options.mongoOptions
)
} catch (error) {
this.emit('error', error)
if (this.options.emitErrors) this.emit('error', error)
}
this.mongo = {}
@ -76,13 +77,17 @@ class KeyvMongo extends EventEmitter {
}
if (!listeningEvents) {
this.client.on('error', error => this.emit('error', error))
listeningEvents = true
if (this.options.emitErrors) {
this.client.on('error', error => this.emit('error', error))
listeningEvents = true
}
}
resolve(this.store)
})
.catch(error => this.emit('error', error))
.catch(error => {
if (this.options.emitErrors) this.emit('error', error)
})
})
}

6
packages/keyv-redis/src/index.js

@ -5,7 +5,7 @@ const pEvent = require('p-event')
const Redis = require('ioredis')
class KeyvRedis extends EventEmitter {
constructor (uri, options) {
constructor (uri, { emitErrors = true, ...options }) {
super()
if (uri instanceof Redis) {
@ -19,7 +19,9 @@ class KeyvRedis extends EventEmitter {
this.redis = new Redis(options.uri, options)
}
this.redis.on('error', error => this.emit('error', error))
if (emitErrors) {
this.redis.on('error', error => this.emit('error', error))
}
}
async get (key) {

116
packages/keyv-sql/src/index.js

@ -6,33 +6,45 @@ class KeyvSql extends EventEmitter {
super()
this.ttlSupport = false
this.options = Object.assign({
table: 'keyv',
keySize: 255,
iterationLimit: 10
}, options)
const createTable = this.options.dialect === 'mysql' ? `CREATE TABLE IF NOT EXISTS \`${this.options.table}\` (\`key\` VARCHAR(${this.options.keySize}) PRIMARY KEY, \`value\` TEXT)` : `CREATE TABLE IF NOT EXISTS "${this.options.table}" ("key" VARCHAR(${this.options.keySize}) PRIMARY KEY, "value" TEXT)`
const connected = this.options.connect()
this.options = Object.assign(
{
table: 'keyv',
keySize: 255,
iterationLimit: 10
},
options
)
const createTable =
this.options.dialect === 'mysql'
? `CREATE TABLE IF NOT EXISTS \`${this.options.table}\` (\`key\` VARCHAR(${this.options.keySize}) PRIMARY KEY, \`value\` TEXT)`
: `CREATE TABLE IF NOT EXISTS "${this.options.table}" ("key" VARCHAR(${this.options.keySize}) PRIMARY KEY, "value" TEXT)`
const connected = this.options
.connect()
.then(query => query(createTable).then(() => query))
.catch(error => this.emit('error', error))
.catch(error => {
if (this.options.emitErrors && typeof this.store.on === 'function') {
this.emit('error', error)
}
})
this.query = sqlString => connected
.then(query => query(sqlString))
this.query = sqlString => connected.then(query => query(sqlString))
}
get (key) {
const select = this.options.dialect === 'mysql' ? `SELECT \`${this.options.table}\`.* FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` = '${key}')` : `SELECT "${this.options.table}".* FROM "${this.options.table}" WHERE ("${this.options.table}"."key" = '${key}')`
return this.query(select)
.then(rows => {
const row = rows[0]
if (row === undefined) {
return undefined
}
const select =
this.options.dialect === 'mysql'
? `SELECT \`${this.options.table}\`.* FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` = '${key}')`
: `SELECT "${this.options.table}".* FROM "${this.options.table}" WHERE ("${this.options.table}"."key" = '${key}')`
return this.query(select).then(rows => {
const row = rows[0]
if (row === undefined) {
return undefined
}
return row.value
})
return row.value
})
}
set (key, value) {
@ -40,39 +52,61 @@ class KeyvSql extends EventEmitter {
value = value.replace(/\\/g, '\\\\')
}
const upsert = this.options.dialect === 'postgres'
? `INSERT INTO "${this.options.table}" ("key", "value") VALUES ('${key}', '${value}') ON CONFLICT ("key") DO UPDATE SET "value" = EXCLUDED."value"`
: (this.options.dialect === 'mysql'
? `REPLACE INTO \`${this.options.table}\` (\`key\`, \`value\`) VALUES ('${key}', '${value}')`
: `REPLACE INTO "${this.options.table}" ("key", "value") VALUES ('${key}', '${value}')`)
const upsert =
this.options.dialect === 'postgres'
? `INSERT INTO "${this.options.table}" ("key", "value") VALUES ('${key}', '${value}') ON CONFLICT ("key") DO UPDATE SET "value" = EXCLUDED."value"`
: this.options.dialect === 'mysql'
? `REPLACE INTO \`${this.options.table}\` (\`key\`, \`value\`) VALUES ('${key}', '${value}')`
: `REPLACE INTO "${this.options.table}" ("key", "value") VALUES ('${key}', '${value}')`
return this.query(upsert)
}
delete (key) {
const select = this.options.dialect === 'mysql' ? `SELECT \`${this.options.table}\`.* FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` = '${key}')` : `SELECT "${this.options.table}".* FROM "${this.options.table}" WHERE ("${this.options.table}"."key" = '${key}')`
const del = this.options.dialect === 'mysql' ? `DELETE FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` = '${key}')` : `DELETE FROM "${this.options.table}" WHERE ("${this.options.table}"."key" = '${key}')`
return this.query(select)
.then(rows => {
const row = rows[0]
if (row === undefined) {
return false
}
const select =
this.options.dialect === 'mysql'
? `SELECT \`${this.options.table}\`.* FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` = '${key}')`
: `SELECT "${this.options.table}".* FROM "${this.options.table}" WHERE ("${this.options.table}"."key" = '${key}')`
const del =
this.options.dialect === 'mysql'
? `DELETE FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` = '${key}')`
: `DELETE FROM "${this.options.table}" WHERE ("${this.options.table}"."key" = '${key}')`
return this.query(select).then(rows => {
const row = rows[0]
if (row === undefined) {
return false
}
return this.query(del)
.then(() => true)
})
return this.query(del).then(() => true)
})
}
clear () {
const del = this.options.dialect === 'mysql' ? `DELETE FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` LIKE '${this.namespace ? this.namespace + ':' : ''}%')` : `DELETE FROM "${this.options.table}" WHERE ("${this.options.table}"."key" LIKE '${this.namespace ? this.namespace + ':' : ''}%')`
return this.query(del)
.then(() => undefined)
const del =
this.options.dialect === 'mysql'
? `DELETE FROM \`${this.options.table}\` WHERE (\`${
this.options.table
}\`.\`key\` LIKE '${this.namespace ? this.namespace + ':' : ''}%')`
: `DELETE FROM "${this.options.table}" WHERE ("${
this.options.table
}"."key" LIKE '${this.namespace ? this.namespace + ':' : ''}%')`
return this.query(del).then(() => undefined)
}
async * iterator () {
const limit = Number.parseInt(this.options.iterationLimit, 10)
const selectChunk = this.options.dialect === 'mysql' ? `SELECT * FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` LIKE '${this.namespace ? this.namespace + ':' : ''}%') LIMIT ${limit} OFFSET ` : `SELECT * FROM "${this.options.table}" WHERE ("${this.options.table}"."key" LIKE '${this.namespace ? this.namespace + ':' : ''}%') LIMIT ${limit} OFFSET `
const selectChunk =
this.options.dialect === 'mysql'
? `SELECT * FROM \`${this.options.table}\` WHERE (\`${
this.options.table
}\`.\`key\` LIKE '${
this.namespace ? this.namespace + ':' : ''
}%') LIMIT ${limit} OFFSET `
: `SELECT * FROM "${this.options.table}" WHERE ("${
this.options.table
}"."key" LIKE '${
this.namespace ? this.namespace + ':' : ''
}%') LIMIT ${limit} OFFSET `
async function * iterate (offset, query) {
const entries = await query(selectChunk + offset)

7
packages/keyv/README.md

@ -232,6 +232,13 @@ Default: `JSONB.parse`
A custom deserialization function.
#### options.emitErrors
Type: `Boolean`<br>
Default: `true`
When it's `true`, errors on `options.store` will be emitted at keyv level.
#### options.store
Type: `Storage adapter instance`<br>

8
packages/keyv/src/index.js

@ -4,22 +4,22 @@ const EventEmitter = require('events')
const JSONB = require('json-buffer')
class Keyv extends EventEmitter {
constructor (options) {
constructor ({ emitErrors = true, ...options }) {
super()
this.options = Object.assign(
{
namespace: 'keyv',
serialize: JSONB.stringify,
deserialize: JSONB.parse
deserialize: JSONB.parse,
emitErrors: true
},
options
)
this.store = this.options.store || new Map()
this.store.namespace = this.options.namespace
if (typeof this.store.on === 'function') {
if (emitErrors) {
this.store.on('error', error => this.emit('error', error))
}

14
packages/keyv/test/keyv.js

@ -157,5 +157,19 @@ test.serial('An empty namespace stores the key as-is', async t => {
t.is([...store.keys()][0], 42)
})
test('emit errors by default', async t => {
const store = new Keyv()
const keyv = new Keyv({ store, namespace: '' })
await keyv.set(42, 'foo')
t.is(store.listenerCount('error'), 1)
})
test('disable emit errors', async t => {
const store = new Keyv({ emitErrors: false })
const keyv = new Keyv({ store, emitErrors: false, namespace: '' })
await keyv.set(42, 'foo')
t.is(keyv.listenerCount('error'), 0)
})
const store = () => new Map()
keyvTestSuite(test, Keyv, store)

Loading…
Cancel
Save