mirror of https://github.com/lukechilds/keyv-1.git
Jytesh
3 years ago
34 changed files with 995 additions and 1022 deletions
@ -1,111 +1,111 @@ |
|||
'use strict'; |
|||
'use strict' |
|||
|
|||
const EventEmitter = require('events'); |
|||
const mongodb = require('mongodb'); |
|||
const pify = require('pify'); |
|||
const EventEmitter = require('events') |
|||
const mongodb = require('mongodb') |
|||
const pify = require('pify') |
|||
|
|||
class KeyvMongo extends EventEmitter { |
|||
constructor(url, options) { |
|||
super(); |
|||
this.ttlSupport = false; |
|||
url = url || {}; |
|||
constructor (url, options) { |
|||
super() |
|||
this.ttlSupport = false |
|||
url = url || {} |
|||
if (typeof url === 'string') { |
|||
url = { url }; |
|||
url = { url } |
|||
} |
|||
|
|||
if (url.uri) { |
|||
url = Object.assign({ url: url.uri }, url); |
|||
url = Object.assign({ url: url.uri }, url) |
|||
} |
|||
|
|||
this.options = Object.assign({ |
|||
url: 'mongodb://127.0.0.1:27017', |
|||
collection: 'keyv' |
|||
}, url, options); |
|||
}, url, options) |
|||
|
|||
this.options.mongoOptions = Object.assign({ |
|||
useNewUrlParser: true, |
|||
useUnifiedTopology: true |
|||
}, this.options.mongoOptions); |
|||
}, this.options.mongoOptions) |
|||
|
|||
try { |
|||
this.client = new mongodb.MongoClient(this.options.url, this.options.mongoOptions); |
|||
this.client = new mongodb.MongoClient(this.options.url, this.options.mongoOptions) |
|||
} catch (error) { |
|||
this.emit('error', error); |
|||
this.emit('error', error) |
|||
} |
|||
|
|||
this.mongo = {}; |
|||
let listeningEvents = false; |
|||
this.mongo = {} |
|||
let listeningEvents = false |
|||
// Implementation from sql by lukechilds,
|
|||
this.connect = new Promise(resolve => { |
|||
this.client.connect() |
|||
.then(client => { |
|||
this.db = client.db(this.options.db); |
|||
this.store = this.db.collection(this.options.collection); |
|||
this.db = client.db(this.options.db) |
|||
this.store = this.db.collection(this.options.collection) |
|||
this.store.createIndex({ key: 1 }, { |
|||
unique: true, |
|||
background: true |
|||
}); |
|||
}) |
|||
this.store.createIndex({ expiresAt: 1 }, { |
|||
expireAfterSeconds: 0, |
|||
background: true |
|||
}); |
|||
}) |
|||
for (const method of ['updateOne', 'findOne', 'deleteOne', 'deleteMany']) { |
|||
this.store[method] = pify(this.store[method].bind(this.store)); |
|||
this.store[method] = pify(this.store[method].bind(this.store)) |
|||
} |
|||
|
|||
if (!listeningEvents) { |
|||
this.client.on('error', error => this.emit('error', error)); |
|||
listeningEvents = true; |
|||
this.client.on('error', error => this.emit('error', error)) |
|||
listeningEvents = true |
|||
} |
|||
|
|||
resolve(this.store); |
|||
resolve(this.store) |
|||
}) |
|||
.catch(error => this.emit('error', error)) |
|||
}) |
|||
.catch(error => this.emit('error', error)); |
|||
}); |
|||
} |
|||
|
|||
get(key) { |
|||
get (key) { |
|||
return this.connect |
|||
.then(store => store.findOne({ key: { $eq: key } }) |
|||
.then(doc => { |
|||
if (doc === null) { |
|||
return undefined; |
|||
return undefined |
|||
} |
|||
|
|||
return doc.value; |
|||
return doc.value |
|||
}) |
|||
); |
|||
) |
|||
} |
|||
|
|||
set(key, value, ttl) { |
|||
const expiresAt = (typeof ttl === 'number') ? new Date(Date.now() + ttl) : null; |
|||
set (key, value, ttl) { |
|||
const expiresAt = (typeof ttl === 'number') ? new Date(Date.now() + ttl) : null |
|||
return this.connect |
|||
.then(store => store.updateOne({ key: { $eq: key } }, { $set: { key, value, expiresAt } }, { upsert: true })); |
|||
.then(store => store.updateOne({ key: { $eq: key } }, { $set: { key, value, expiresAt } }, { upsert: true })) |
|||
} |
|||
|
|||
delete(key) { |
|||
delete (key) { |
|||
if (typeof key !== 'string') { |
|||
return Promise.resolve(false); |
|||
return Promise.resolve(false) |
|||
} |
|||
|
|||
return this.connect |
|||
.then(store => store.deleteOne({ key: { $eq: key } }) |
|||
.then(object => object.deletedCount > 0) |
|||
); |
|||
) |
|||
} |
|||
|
|||
clear() { |
|||
clear () { |
|||
return this.connect |
|||
.then(store => store.deleteMany({ key: new RegExp(`^${this.namespace + ':'}`) }) |
|||
.then(() => undefined)); |
|||
.then(() => undefined)) |
|||
} |
|||
|
|||
async * iterator() { |
|||
async * iterator () { |
|||
const iterator = await this.connect |
|||
.then(store => store.find({ key: new RegExp(`^${this.namespace ? this.namespace + ':' : '.*'}`) }).map(x => { |
|||
return [x.key, x.value]; |
|||
})); |
|||
yield * iterator; |
|||
return [x.key, x.value] |
|||
})) |
|||
yield * iterator |
|||
} |
|||
} |
|||
module.exports = KeyvMongo; |
|||
module.exports = KeyvMongo |
|||
|
@ -1,28 +1,28 @@ |
|||
'use strict'; |
|||
'use strict' |
|||
|
|||
const KeyvSql = require('@keyvhq/keyv-sql'); |
|||
const mysql = require('mysql2/promise'); |
|||
const KeyvSql = require('@keyvhq/keyv-sql') |
|||
const mysql = require('mysql2/promise') |
|||
|
|||
class KeyvMysql extends KeyvSql { |
|||
constructor(options) { |
|||
constructor (options) { |
|||
if (typeof options === 'string') { |
|||
options = { uri: options }; |
|||
options = { uri: options } |
|||
} |
|||
|
|||
options = Object.assign({ |
|||
dialect: 'mysql', |
|||
uri: 'mysql://localhost' |
|||
}, options); |
|||
}, options) |
|||
|
|||
options.connect = () => Promise.resolve() |
|||
.then(() => mysql.createConnection(options.uri)) |
|||
.then(connection => { |
|||
return sql => connection.execute(sql) |
|||
.then(data => data[0]); |
|||
}); |
|||
.then(data => data[0]) |
|||
}) |
|||
|
|||
super(options); |
|||
super(options) |
|||
} |
|||
} |
|||
|
|||
module.exports = KeyvMysql; |
|||
module.exports = KeyvMysql |
|||
|
@ -1,9 +1,9 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('@keyvhq/keyv'); |
|||
const KeyvMysql = require('this'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('@keyvhq/keyv') |
|||
const KeyvMysql = require('this') |
|||
|
|||
require('dotenv').config(); |
|||
const dbUrl = process.env.MYSQL_URL || 'mysql://root:root@localhost/keyv_test'; |
|||
const store = () => new KeyvMysql(dbUrl); |
|||
keyvTestSuite(test, Keyv, store); |
|||
require('dotenv').config() |
|||
const dbUrl = process.env.MYSQL_URL || 'mysql://root:root@localhost/keyv_test' |
|||
const store = () => new KeyvMysql(dbUrl) |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,27 +1,27 @@ |
|||
'use strict'; |
|||
'use strict' |
|||
|
|||
const KeyvSql = require('@keyvhq/keyv-sql'); |
|||
const Pool = require('pg').Pool; |
|||
const KeyvSql = require('@keyvhq/keyv-sql') |
|||
const Pool = require('pg').Pool |
|||
|
|||
class KeyvPostgres extends KeyvSql { |
|||
constructor(options) { |
|||
constructor (options) { |
|||
options = Object.assign({ |
|||
dialect: 'postgres', |
|||
uri: 'postgresql://localhost:5432' |
|||
}, options); |
|||
}, options) |
|||
|
|||
options.connect = () => Promise.resolve() |
|||
.then(() => { |
|||
const pool = new Pool({ |
|||
connectionString: options.uri, |
|||
ssl: options.ssl |
|||
}); |
|||
}) |
|||
return sql => pool.query(sql) |
|||
.then(data => data.rows); |
|||
}); |
|||
.then(data => data.rows) |
|||
}) |
|||
|
|||
super(options); |
|||
super(options) |
|||
} |
|||
} |
|||
|
|||
module.exports = KeyvPostgres; |
|||
module.exports = KeyvPostgres |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('@keyvhq/keyv'); |
|||
const KeyvPostgres = require('this'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('@keyvhq/keyv') |
|||
const KeyvPostgres = require('this') |
|||
|
|||
const store = () => new KeyvPostgres({ uri: 'postgresql://postgres:postgres@localhost:5432/keyv_test' }); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvPostgres({ uri: 'postgresql://postgres:postgres@localhost:5432/keyv_test' }) |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,79 +1,79 @@ |
|||
'use strict'; |
|||
'use strict' |
|||
|
|||
const EventEmitter = require('events'); |
|||
const pEvent = require('p-event'); |
|||
const Redis = require('ioredis'); |
|||
const EventEmitter = require('events') |
|||
const pEvent = require('p-event') |
|||
const Redis = require('ioredis') |
|||
|
|||
class KeyvRedis extends EventEmitter { |
|||
constructor(uri, options) { |
|||
super(); |
|||
constructor (uri, options) { |
|||
super() |
|||
|
|||
if (uri instanceof Redis) { |
|||
this.redis = uri; |
|||
this.redis = uri |
|||
} else { |
|||
options = Object.assign( |
|||
{}, |
|||
typeof uri === 'string' ? { uri } : uri, |
|||
options |
|||
); |
|||
this.redis = new Redis(options.uri, options); |
|||
) |
|||
this.redis = new Redis(options.uri, options) |
|||
} |
|||
|
|||
this.redis.on('error', error => this.emit('error', error)); |
|||
this.redis.on('error', error => this.emit('error', error)) |
|||
} |
|||
|
|||
async get(key) { |
|||
const value = await this.redis.get(key); |
|||
return value === null ? undefined : value; |
|||
async get (key) { |
|||
const value = await this.redis.get(key) |
|||
return value === null ? undefined : value |
|||
} |
|||
|
|||
async set(key, value, ttl) { |
|||
async set (key, value, ttl) { |
|||
if (typeof value === 'undefined') { |
|||
return undefined; |
|||
return undefined |
|||
} |
|||
|
|||
return typeof ttl === 'number' ? |
|||
this.redis.set(key, value, 'PX', ttl) : |
|||
this.redis.set(key, value); |
|||
return typeof ttl === 'number' |
|||
? this.redis.set(key, value, 'PX', ttl) |
|||
: this.redis.set(key, value) |
|||
} |
|||
|
|||
async delete(key) { |
|||
const result = await this.redis.unlink(key); |
|||
return result > 0; |
|||
async delete (key) { |
|||
const result = await this.redis.unlink(key) |
|||
return result > 0 |
|||
} |
|||
|
|||
async clear() { |
|||
const stream = this.redis.scanStream({ match: `${this.namespace}:*` }); |
|||
async clear () { |
|||
const stream = this.redis.scanStream({ match: `${this.namespace}:*` }) |
|||
|
|||
const keys = []; |
|||
stream.on('data', matchedKeys => keys.push(...matchedKeys)); |
|||
await pEvent(stream, 'end'); |
|||
const keys = [] |
|||
stream.on('data', matchedKeys => keys.push(...matchedKeys)) |
|||
await pEvent(stream, 'end') |
|||
if (keys.length > 0) { |
|||
await this.redis.unlink(keys); |
|||
await this.redis.unlink(keys) |
|||
} |
|||
} |
|||
|
|||
async * iterator() { |
|||
const scan = this.redis.scan.bind(this.redis); |
|||
const get = this.redis.mget.bind(this.redis); |
|||
async function * iterate(curs, pattern) { |
|||
const [cursor, keys] = await scan(curs, 'MATCH', pattern); |
|||
const values = await get(keys); |
|||
async * iterator () { |
|||
const scan = this.redis.scan.bind(this.redis) |
|||
const get = this.redis.mget.bind(this.redis) |
|||
async function * iterate (curs, pattern) { |
|||
const [cursor, keys] = await scan(curs, 'MATCH', pattern) |
|||
const values = await get(keys) |
|||
for (const i in keys) { |
|||
if (Object.prototype.hasOwnProperty.call(keys, i)) { |
|||
const key = keys[i]; |
|||
const value = values[i]; |
|||
yield [key, value]; |
|||
const key = keys[i] |
|||
const value = values[i] |
|||
yield [key, value] |
|||
} |
|||
} |
|||
|
|||
if (cursor !== '0') { |
|||
yield * iterate(cursor, pattern); |
|||
yield * iterate(cursor, pattern) |
|||
} |
|||
} |
|||
|
|||
yield * iterate(0, `${this.namespace ? this.namespace + ':' : ''}*`); |
|||
yield * iterate(0, `${this.namespace ? this.namespace + ':' : ''}*`) |
|||
} |
|||
} |
|||
|
|||
module.exports = KeyvRedis; |
|||
module.exports = KeyvRedis |
|||
|
@ -1,24 +1,24 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('@keyvhq/keyv'); |
|||
const KeyvRedis = require('this'); |
|||
const Redis = require('ioredis'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('@keyvhq/keyv') |
|||
const KeyvRedis = require('this') |
|||
const Redis = require('ioredis') |
|||
|
|||
require('dotenv').config(); |
|||
const { REDIS_HOST = 'localhost' } = process.env; |
|||
const redisURI = `redis://${REDIS_HOST}`; |
|||
require('dotenv').config() |
|||
const { REDIS_HOST = 'localhost' } = process.env |
|||
const redisURI = `redis://${REDIS_HOST}` |
|||
|
|||
const store = () => new KeyvRedis(redisURI); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvRedis(redisURI) |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
|||
test('reuse a redis instance', async t => { |
|||
const redis = new Redis(redisURI); |
|||
redis.foo = 'bar'; |
|||
const keyv = new KeyvRedis(redis); |
|||
t.is(keyv.redis.foo, 'bar'); |
|||
const redis = new Redis(redisURI) |
|||
redis.foo = 'bar' |
|||
const keyv = new KeyvRedis(redis) |
|||
t.is(keyv.redis.foo, 'bar') |
|||
|
|||
await keyv.set('foo', 'bar'); |
|||
const value = await redis.get('foo'); |
|||
t.true(value === 'bar'); |
|||
t.true(await keyv.get('foo') === value); |
|||
}); |
|||
await keyv.set('foo', 'bar') |
|||
const value = await redis.get('foo') |
|||
t.true(value === 'bar') |
|||
t.true(await keyv.get('foo') === value) |
|||
}) |
|||
|
@ -1,96 +1,96 @@ |
|||
'use strict'; |
|||
'use strict' |
|||
|
|||
const EventEmitter = require('events'); |
|||
const EventEmitter = require('events') |
|||
class KeyvSql extends EventEmitter { |
|||
constructor(options) { |
|||
super(); |
|||
this.ttlSupport = false; |
|||
constructor (options) { |
|||
super() |
|||
this.ttlSupport = false |
|||
|
|||
this.options = Object.assign({ |
|||
table: 'keyv', |
|||
keySize: 255, |
|||
iterationLimit: 10 |
|||
}, options); |
|||
}, 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 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 => this.emit('error', error)) |
|||
|
|||
this.query = sqlString => connected |
|||
.then(query => query(sqlString)); |
|||
.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}')`; |
|||
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]; |
|||
const row = rows[0] |
|||
if (row === undefined) { |
|||
return undefined; |
|||
return undefined |
|||
} |
|||
|
|||
return row.value; |
|||
}); |
|||
return row.value |
|||
}) |
|||
} |
|||
|
|||
set(key, value) { |
|||
set (key, value) { |
|||
if (this.options.dialect === 'mysql') { |
|||
value = value.replace(/\\/g, '\\\\'); |
|||
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); |
|||
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}')`; |
|||
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]; |
|||
const row = rows[0] |
|||
if (row === undefined) { |
|||
return false; |
|||
return false |
|||
} |
|||
|
|||
return this.query(del) |
|||
.then(() => true); |
|||
}); |
|||
.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 + ':' : ''}%')`; |
|||
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); |
|||
.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 `; |
|||
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 ` |
|||
|
|||
async function * iterate(offset, query) { |
|||
const entries = await query(selectChunk + offset); |
|||
async function * iterate (offset, query) { |
|||
const entries = await query(selectChunk + offset) |
|||
if (entries.length === 0) { |
|||
return; |
|||
return |
|||
} |
|||
|
|||
for (const entry of entries) { |
|||
offset += 1; |
|||
yield [entry.key, entry.value]; |
|||
offset += 1 |
|||
yield [entry.key, entry.value] |
|||
} |
|||
|
|||
if (offset !== '0') { |
|||
yield * iterate(offset, query); |
|||
yield * iterate(offset, query) |
|||
} |
|||
} |
|||
|
|||
yield * iterate(0, this.query); |
|||
yield * iterate(0, this.query) |
|||
} |
|||
} |
|||
module.exports = KeyvSql; |
|||
module.exports = KeyvSql |
|||
|
@ -1,33 +1,33 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('@keyvhq/keyv'); |
|||
const KeyvSql = require('this'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('@keyvhq/keyv') |
|||
const KeyvSql = require('this') |
|||
|
|||
const sqlite3 = require('sqlite3'); |
|||
const pify = require('pify'); |
|||
const sqlite3 = require('sqlite3') |
|||
const pify = require('pify') |
|||
|
|||
class TestSqlite extends KeyvSql { |
|||
constructor(options) { |
|||
constructor (options) { |
|||
options = Object.assign({ |
|||
dialect: 'sqlite', |
|||
db: 'test/testdb.sqlite' |
|||
}, options); |
|||
}, options) |
|||
|
|||
options.connect = () => new Promise((resolve, reject) => { |
|||
const db = new sqlite3.Database(options.db, error => { |
|||
if (error) { |
|||
reject(error); |
|||
reject(error) |
|||
} else { |
|||
db.configure('busyTimeout', 30000); |
|||
resolve(db); |
|||
db.configure('busyTimeout', 30000) |
|||
resolve(db) |
|||
} |
|||
}); |
|||
}) |
|||
.then(db => pify(db.all).bind(db)); |
|||
}) |
|||
.then(db => pify(db.all).bind(db)) |
|||
|
|||
super(options); |
|||
super(options) |
|||
} |
|||
} |
|||
|
|||
const store = () => new TestSqlite(); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new TestSqlite() |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,34 +1,34 @@ |
|||
'use strict'; |
|||
'use strict' |
|||
|
|||
const KeyvSql = require('@keyvhq/keyv-sql'); |
|||
const sqlite3 = require('sqlite3'); |
|||
const pify = require('pify'); |
|||
const KeyvSql = require('@keyvhq/keyv-sql') |
|||
const sqlite3 = require('sqlite3') |
|||
const pify = require('pify') |
|||
|
|||
class KeyvSqlite extends KeyvSql { |
|||
constructor(options) { |
|||
constructor (options) { |
|||
options = Object.assign({ |
|||
dialect: 'sqlite', |
|||
uri: 'sqlite://:memory:' |
|||
}, options); |
|||
options.db = options.uri.replace(/^sqlite:\/\//, ''); |
|||
}, options) |
|||
options.db = options.uri.replace(/^sqlite:\/\//, '') |
|||
|
|||
options.connect = () => new Promise((resolve, reject) => { |
|||
const db = new sqlite3.Database(options.db, error => { |
|||
if (error) { |
|||
reject(error); |
|||
reject(error) |
|||
} else { |
|||
if (options.busyTimeout) { |
|||
db.configure('busyTimeout', options.busyTimeout); |
|||
db.configure('busyTimeout', options.busyTimeout) |
|||
} |
|||
|
|||
resolve(db); |
|||
resolve(db) |
|||
} |
|||
}); |
|||
}) |
|||
.then(db => pify(db.all).bind(db)); |
|||
}) |
|||
.then(db => pify(db.all).bind(db)) |
|||
|
|||
super(options); |
|||
super(options) |
|||
} |
|||
} |
|||
|
|||
module.exports = KeyvSqlite; |
|||
module.exports = KeyvSqlite |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('@keyvhq/keyv'); |
|||
const KeyvSqlite = require('../src/index.js'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('@keyvhq/keyv') |
|||
const KeyvSqlite = require('../src/index.js') |
|||
|
|||
const store = () => new KeyvSqlite({ uri: 'sqlite://test/testdb.sqlite', busyTimeout: 30000 }); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvSqlite({ uri: 'sqlite://test/testdb.sqlite', busyTimeout: 30000 }) |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,126 +1,126 @@ |
|||
const tk = require('timekeeper'); |
|||
const delay = require('delay'); |
|||
const tk = require('timekeeper') |
|||
const delay = require('delay') |
|||
|
|||
const keyvApiTests = (test, Keyv, store) => { |
|||
test.beforeEach(async () => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.clear(); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.clear() |
|||
}) |
|||
|
|||
test.serial('.set(key, value) returns a Promise', t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.true(keyv.set('foo', 'bar') instanceof Promise); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.true(keyv.set('foo', 'bar') instanceof Promise) |
|||
}) |
|||
|
|||
test.serial('.set(key, value) resolves to true', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.is(await keyv.set('foo', 'bar'), true); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.is(await keyv.set('foo', 'bar'), true) |
|||
}) |
|||
|
|||
test.serial('.set(key, value) sets a value', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
}) |
|||
|
|||
test.serial('.set(key, value, ttl) sets a value that expires', async t => { |
|||
const ttl = 1000; |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar', ttl); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
const ttl = 1000 |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar', ttl) |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
if (keyv.store.ttlSupport === true) { |
|||
await delay(ttl + 1); |
|||
await delay(ttl + 1) |
|||
} else { |
|||
tk.freeze(Date.now() + ttl + 1); |
|||
tk.freeze(Date.now() + ttl + 1) |
|||
} |
|||
|
|||
t.is(await keyv.get('foo'), undefined); |
|||
tk.reset(); |
|||
}); |
|||
t.is(await keyv.get('foo'), undefined) |
|||
tk.reset() |
|||
}) |
|||
|
|||
test.serial('.get(key) returns a Promise', t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.true(keyv.get('foo') instanceof Promise); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.true(keyv.get('foo') instanceof Promise) |
|||
}) |
|||
|
|||
test.serial('.get(key) resolves to value', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
}) |
|||
|
|||
test.serial('.get(key) with nonexistent key resolves to undefined', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.is(await keyv.get('foo'), undefined); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.is(await keyv.get('foo'), undefined) |
|||
}) |
|||
|
|||
test.serial('.delete(key) returns a Promise', t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.true(keyv.delete('foo') instanceof Promise); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.true(keyv.delete('foo') instanceof Promise) |
|||
}) |
|||
|
|||
test.serial('.delete(key) resolves to true', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.delete('foo'), true); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.delete('foo'), true) |
|||
}) |
|||
|
|||
test.serial('.delete(key) with nonexistent key resolves to false', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.is(await keyv.delete(), false); |
|||
t.is(await keyv.delete('foo'), false); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.is(await keyv.delete(), false) |
|||
t.is(await keyv.delete('foo'), false) |
|||
}) |
|||
|
|||
test.serial('.delete(key) deletes a key', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.delete('foo'), true); |
|||
t.is(await keyv.get('foo'), undefined); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.delete('foo'), true) |
|||
t.is(await keyv.get('foo'), undefined) |
|||
}) |
|||
|
|||
test.serial('.clear() returns a Promise', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
const returnValue = keyv.clear(); |
|||
t.true(returnValue instanceof Promise); |
|||
await returnValue; |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
const returnValue = keyv.clear() |
|||
t.true(returnValue instanceof Promise) |
|||
await returnValue |
|||
}) |
|||
|
|||
test.serial('.clear() resolves to undefined', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.is(await keyv.clear(), undefined); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.clear(), undefined); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.is(await keyv.clear(), undefined) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.clear(), undefined) |
|||
}) |
|||
|
|||
test.serial('.clear() deletes all key/value pairs', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar'); |
|||
await keyv.set('fizz', 'buzz'); |
|||
await keyv.clear(); |
|||
t.is(await keyv.get('foo'), undefined); |
|||
t.is(await keyv.get('fizz'), undefined); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar') |
|||
await keyv.set('fizz', 'buzz') |
|||
await keyv.clear() |
|||
t.is(await keyv.get('foo'), undefined) |
|||
t.is(await keyv.get('fizz'), undefined) |
|||
}) |
|||
|
|||
test.serial('.has(key) returns a Promise', t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.true(keyv.has('foo') instanceof Promise); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.true(keyv.has('foo') instanceof Promise) |
|||
}) |
|||
|
|||
test.serial('.has(key) resolves to true', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.has('foo'), true); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.has('foo'), true) |
|||
}) |
|||
|
|||
test.serial('.has(key) with nonexistent key resolves to false', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.is(await keyv.has('foo'), false); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.is(await keyv.has('foo'), false) |
|||
}) |
|||
|
|||
test.after.always(async () => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.clear(); |
|||
}); |
|||
}; |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.clear() |
|||
}) |
|||
} |
|||
|
|||
module.exports = keyvApiTests; |
|||
module.exports = keyvApiTests |
|||
|
@ -1,20 +1,20 @@ |
|||
const keyvApiTests = require('./api.js'); |
|||
const keyvValueTests = require('./values.js'); |
|||
const keyvNamespaceTests = require('./namespace.js'); |
|||
const keyvIteratorTests = require('./iteration.js'); |
|||
const keyvApiTests = require('./api.js') |
|||
const keyvValueTests = require('./values.js') |
|||
const keyvNamespaceTests = require('./namespace.js') |
|||
const keyvIteratorTests = require('./iteration.js') |
|||
|
|||
const keyvTestSuite = (test, Keyv, store) => { |
|||
keyvIteratorTests(test, Keyv, store); |
|||
keyvApiTests(test, Keyv, store); |
|||
keyvValueTests(test, Keyv, store); |
|||
keyvNamespaceTests(test, Keyv, store); |
|||
}; |
|||
keyvIteratorTests(test, Keyv, store) |
|||
keyvApiTests(test, Keyv, store) |
|||
keyvValueTests(test, Keyv, store) |
|||
keyvNamespaceTests(test, Keyv, store) |
|||
} |
|||
|
|||
Object.assign(keyvTestSuite, { |
|||
keyvApiTests, |
|||
keyvValueTests, |
|||
keyvNamespaceTests, |
|||
keyvIteratorTests |
|||
}); |
|||
}) |
|||
|
|||
module.exports = keyvTestSuite; |
|||
module.exports = keyvTestSuite |
|||
|
@ -1,30 +1,30 @@ |
|||
const keyvIteratorTests = (test, Keyv, store) => { |
|||
test.beforeEach(async () => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.clear(); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.clear() |
|||
}) |
|||
|
|||
test.serial('.iterator() returns an asyncIterator', t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
t.true(typeof keyv.iterator()[Symbol.asyncIterator] === 'function'); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
t.true(typeof keyv.iterator()[Symbol.asyncIterator] === 'function') |
|||
}) |
|||
|
|||
test.serial('iterator() iterates over all values', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
const map = new Map(Array.from({ length: 5 }).fill(0).map((x, i) => [String(i), String(i + 10)])); |
|||
const toResolve = []; |
|||
const keyv = new Keyv({ store: store() }) |
|||
const map = new Map(Array.from({ length: 5 }).fill(0).map((x, i) => [String(i), String(i + 10)])) |
|||
const toResolve = [] |
|||
for (const [key, value] of map) { |
|||
toResolve.push(keyv.set(key, value)); |
|||
toResolve.push(keyv.set(key, value)) |
|||
} |
|||
|
|||
await Promise.all(toResolve); |
|||
t.plan(map.size); |
|||
await Promise.all(toResolve) |
|||
t.plan(map.size) |
|||
for await (const [key, value] of keyv.iterator()) { |
|||
const doesKeyExist = map.has(key); |
|||
const isValueSame = map.get(key) === value; |
|||
t.true(doesKeyExist && isValueSame); |
|||
const doesKeyExist = map.has(key) |
|||
const isValueSame = map.get(key) === value |
|||
t.true(doesKeyExist && isValueSame) |
|||
} |
|||
}); |
|||
}; |
|||
}) |
|||
} |
|||
|
|||
module.exports = keyvIteratorTests; |
|||
module.exports = keyvIteratorTests |
|||
|
@ -1,64 +1,64 @@ |
|||
const keyvNamepsaceTests = (test, Keyv, store) => { |
|||
test.beforeEach(async () => { |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }); |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }); |
|||
await keyv1.clear(); |
|||
await keyv2.clear(); |
|||
}); |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }) |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }) |
|||
await keyv1.clear() |
|||
await keyv2.clear() |
|||
}) |
|||
|
|||
test.serial('namespaced set/get don\'t collide', async t => { |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }); |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }); |
|||
await keyv1.set('foo', 'keyv1'); |
|||
await keyv2.set('foo', 'keyv2'); |
|||
t.is(await keyv1.get('foo'), 'keyv1'); |
|||
t.is(await keyv2.get('foo'), 'keyv2'); |
|||
}); |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }) |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }) |
|||
await keyv1.set('foo', 'keyv1') |
|||
await keyv2.set('foo', 'keyv2') |
|||
t.is(await keyv1.get('foo'), 'keyv1') |
|||
t.is(await keyv2.get('foo'), 'keyv2') |
|||
}) |
|||
|
|||
test.serial('namespaced delete only deletes from current namespace', async t => { |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }); |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }); |
|||
await keyv1.set('foo', 'keyv1'); |
|||
await keyv2.set('foo', 'keyv2'); |
|||
t.is(await keyv1.delete('foo'), true); |
|||
t.is(await keyv1.get('foo'), undefined); |
|||
t.is(await keyv2.get('foo'), 'keyv2'); |
|||
}); |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }) |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }) |
|||
await keyv1.set('foo', 'keyv1') |
|||
await keyv2.set('foo', 'keyv2') |
|||
t.is(await keyv1.delete('foo'), true) |
|||
t.is(await keyv1.get('foo'), undefined) |
|||
t.is(await keyv2.get('foo'), 'keyv2') |
|||
}) |
|||
|
|||
test.serial('namespaced clear only clears current namespace', async t => { |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }); |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }); |
|||
await keyv1.set('foo', 'keyv1'); |
|||
await keyv1.set('bar', 'keyv1'); |
|||
await keyv2.set('foo', 'keyv2'); |
|||
await keyv2.set('bar', 'keyv2'); |
|||
await keyv1.clear(); |
|||
t.is(await keyv1.get('foo'), undefined); |
|||
t.is(await keyv1.get('bar'), undefined); |
|||
t.is(await keyv2.get('foo'), 'keyv2'); |
|||
t.is(await keyv2.get('bar'), 'keyv2'); |
|||
}); |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }) |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }) |
|||
await keyv1.set('foo', 'keyv1') |
|||
await keyv1.set('bar', 'keyv1') |
|||
await keyv2.set('foo', 'keyv2') |
|||
await keyv2.set('bar', 'keyv2') |
|||
await keyv1.clear() |
|||
t.is(await keyv1.get('foo'), undefined) |
|||
t.is(await keyv1.get('bar'), undefined) |
|||
t.is(await keyv2.get('foo'), 'keyv2') |
|||
t.is(await keyv2.get('bar'), 'keyv2') |
|||
}) |
|||
|
|||
test.serial('no namespaced clear doesn\'t clears all stores', async t => { |
|||
const keyv1 = new Keyv({ store: store(), namespace: false }); |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }); |
|||
await keyv1.set('foo', 'keyv1'); |
|||
await keyv1.set('bar', 'keyv1'); |
|||
await keyv2.set('foo', 'keyv2'); |
|||
await keyv2.set('bar', 'keyv2'); |
|||
await keyv1.clear(); |
|||
t.is(await keyv1.get('foo'), 'keyv1'); |
|||
t.is(await keyv1.get('bar'), 'keyv1'); |
|||
t.is(await keyv2.get('foo'), 'keyv2'); |
|||
t.is(await keyv2.get('bar'), 'keyv2'); |
|||
}); |
|||
const keyv1 = new Keyv({ store: store(), namespace: false }) |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }) |
|||
await keyv1.set('foo', 'keyv1') |
|||
await keyv1.set('bar', 'keyv1') |
|||
await keyv2.set('foo', 'keyv2') |
|||
await keyv2.set('bar', 'keyv2') |
|||
await keyv1.clear() |
|||
t.is(await keyv1.get('foo'), 'keyv1') |
|||
t.is(await keyv1.get('bar'), 'keyv1') |
|||
t.is(await keyv2.get('foo'), 'keyv2') |
|||
t.is(await keyv2.get('bar'), 'keyv2') |
|||
}) |
|||
|
|||
test.after.always(async () => { |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }); |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }); |
|||
await keyv1.clear(); |
|||
await keyv2.clear(); |
|||
}); |
|||
}; |
|||
const keyv1 = new Keyv({ store: store(), namespace: 'keyv1' }) |
|||
const keyv2 = new Keyv({ store: store(), namespace: 'keyv2' }) |
|||
await keyv1.clear() |
|||
await keyv2.clear() |
|||
}) |
|||
} |
|||
|
|||
module.exports = keyvNamepsaceTests; |
|||
module.exports = keyvNamepsaceTests |
|||
|
@ -1,65 +1,65 @@ |
|||
const keyvValueTests = (test, Keyv, store) => { |
|||
test.beforeEach(async () => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.clear(); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.clear() |
|||
}) |
|||
|
|||
test.serial('value can be false', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', false); |
|||
t.is(await keyv.get('foo'), false); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', false) |
|||
t.is(await keyv.get('foo'), false) |
|||
}) |
|||
|
|||
test.serial('value can be null', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', null); |
|||
t.is(await keyv.get('foo'), null); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', null) |
|||
t.is(await keyv.get('foo'), null) |
|||
}) |
|||
|
|||
test.serial('value can be undefined', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', undefined); |
|||
t.is(await keyv.get('foo'), undefined); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', undefined) |
|||
t.is(await keyv.get('foo'), undefined) |
|||
}) |
|||
|
|||
test.serial('value can be a number', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.set('foo', 0); |
|||
t.is(await keyv.get('foo'), 0); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.set('foo', 0) |
|||
t.is(await keyv.get('foo'), 0) |
|||
}) |
|||
|
|||
test.serial('value can be an object', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
const value = { fizz: 'buzz' }; |
|||
await keyv.set('foo', value); |
|||
t.deepEqual(await keyv.get('foo'), value); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
const value = { fizz: 'buzz' } |
|||
await keyv.set('foo', value) |
|||
t.deepEqual(await keyv.get('foo'), value) |
|||
}) |
|||
|
|||
test.serial('value can be a buffer', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
const buf = Buffer.from('bar'); |
|||
await keyv.set('foo', buf); |
|||
t.true(buf.equals(await keyv.get('foo'))); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
const buf = Buffer.from('bar') |
|||
await keyv.set('foo', buf) |
|||
t.true(buf.equals(await keyv.get('foo'))) |
|||
}) |
|||
|
|||
test.serial('value can be an object containing a buffer', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
const value = { buff: Buffer.from('buzz') }; |
|||
await keyv.set('foo', value); |
|||
t.deepEqual(await keyv.get('foo'), value); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
const value = { buff: Buffer.from('buzz') } |
|||
await keyv.set('foo', value) |
|||
t.deepEqual(await keyv.get('foo'), value) |
|||
}) |
|||
|
|||
test.serial('value can contain quotes', async t => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
const value = '"'; |
|||
await keyv.set('foo', value); |
|||
t.deepEqual(await keyv.get('foo'), value); |
|||
}); |
|||
const keyv = new Keyv({ store: store() }) |
|||
const value = '"' |
|||
await keyv.set('foo', value) |
|||
t.deepEqual(await keyv.get('foo'), value) |
|||
}) |
|||
|
|||
test.after.always(async () => { |
|||
const keyv = new Keyv({ store: store() }); |
|||
await keyv.clear(); |
|||
}); |
|||
}; |
|||
const keyv = new Keyv({ store: store() }) |
|||
await keyv.clear() |
|||
}) |
|||
} |
|||
|
|||
module.exports = keyvValueTests; |
|||
module.exports = keyvValueTests |
|||
|
@ -1,6 +1,6 @@ |
|||
const test = require('ava'); |
|||
const Keyv = require('@keyvhq/keyv'); |
|||
const keyvTestSuite = require('this'); |
|||
const test = require('ava') |
|||
const Keyv = require('@keyvhq/keyv') |
|||
const keyvTestSuite = require('this') |
|||
|
|||
const store = () => new Map(); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new Map() |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,149 +1,149 @@ |
|||
const test = require('ava'); |
|||
const tk = require('timekeeper'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('this'); |
|||
const test = require('ava') |
|||
const tk = require('timekeeper') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('this') |
|||
|
|||
test.serial('Keyv is a class', t => { |
|||
t.is(typeof Keyv, 'function'); |
|||
t.throws(() => Keyv()); // eslint-disable-line new-cap
|
|||
t.notThrows(() => new Keyv()); |
|||
}); |
|||
t.is(typeof Keyv, 'function') |
|||
t.throws(() => Keyv()) // eslint-disable-line new-cap
|
|||
t.notThrows(() => new Keyv()) |
|||
}) |
|||
|
|||
test.serial('Keyv accepts storage adapters', async t => { |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store }); |
|||
t.is(store.size, 0); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
t.is(store.size, 1); |
|||
}); |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store }) |
|||
t.is(store.size, 0) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
t.is(store.size, 1) |
|||
}) |
|||
|
|||
test.serial('Keyv passes tll info to stores', async t => { |
|||
t.plan(1); |
|||
const store = new Map(); |
|||
const storeSet = store.set; |
|||
t.plan(1) |
|||
const store = new Map() |
|||
const storeSet = store.set |
|||
store.set = (key, value, ttl) => { |
|||
t.is(ttl, 100); |
|||
storeSet.call(store, key, value, ttl); |
|||
}; |
|||
t.is(ttl, 100) |
|||
storeSet.call(store, key, value, ttl) |
|||
} |
|||
|
|||
const keyv = new Keyv({ store }); |
|||
await keyv.set('foo', 'bar', 100); |
|||
}); |
|||
const keyv = new Keyv({ store }) |
|||
await keyv.set('foo', 'bar', 100) |
|||
}) |
|||
|
|||
test.serial('Keyv respects default tll option', async t => { |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store, ttl: 100 }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
tk.freeze(Date.now() + 150); |
|||
t.is(await keyv.get('foo'), undefined); |
|||
t.is(store.size, 0); |
|||
tk.reset(); |
|||
}); |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store, ttl: 100 }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
tk.freeze(Date.now() + 150) |
|||
t.is(await keyv.get('foo'), undefined) |
|||
t.is(store.size, 0) |
|||
tk.reset() |
|||
}) |
|||
|
|||
test.serial('.set(key, value, ttl) overwrites default tll option', async t => { |
|||
const startTime = Date.now(); |
|||
tk.freeze(startTime); |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store, ttl: 200 }); |
|||
await keyv.set('foo', 'bar'); |
|||
await keyv.set('fizz', 'buzz', 100); |
|||
await keyv.set('ping', 'pong', 300); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
t.is(await keyv.get('fizz'), 'buzz'); |
|||
t.is(await keyv.get('ping'), 'pong'); |
|||
tk.freeze(startTime + 150); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
t.is(await keyv.get('fizz'), undefined); |
|||
t.is(await keyv.get('ping'), 'pong'); |
|||
tk.freeze(startTime + 250); |
|||
t.is(await keyv.get('foo'), undefined); |
|||
t.is(await keyv.get('ping'), 'pong'); |
|||
tk.freeze(startTime + 350); |
|||
t.is(await keyv.get('ping'), undefined); |
|||
tk.reset(); |
|||
}); |
|||
const startTime = Date.now() |
|||
tk.freeze(startTime) |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store, ttl: 200 }) |
|||
await keyv.set('foo', 'bar') |
|||
await keyv.set('fizz', 'buzz', 100) |
|||
await keyv.set('ping', 'pong', 300) |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
t.is(await keyv.get('fizz'), 'buzz') |
|||
t.is(await keyv.get('ping'), 'pong') |
|||
tk.freeze(startTime + 150) |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
t.is(await keyv.get('fizz'), undefined) |
|||
t.is(await keyv.get('ping'), 'pong') |
|||
tk.freeze(startTime + 250) |
|||
t.is(await keyv.get('foo'), undefined) |
|||
t.is(await keyv.get('ping'), 'pong') |
|||
tk.freeze(startTime + 350) |
|||
t.is(await keyv.get('ping'), undefined) |
|||
tk.reset() |
|||
}) |
|||
|
|||
test.serial('.set(key, value, ttl) where ttl is "0" overwrites default tll option and sets key to never expire', async t => { |
|||
const startTime = Date.now(); |
|||
tk.freeze(startTime); |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store, ttl: 200 }); |
|||
await keyv.set('foo', 'bar', 0); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
tk.freeze(startTime + 250); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
tk.reset(); |
|||
}); |
|||
const startTime = Date.now() |
|||
tk.freeze(startTime) |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store, ttl: 200 }) |
|||
await keyv.set('foo', 'bar', 0) |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
tk.freeze(startTime + 250) |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
tk.reset() |
|||
}) |
|||
|
|||
test.serial('.get(key, {raw: true}) returns the raw object instead of the value', async t => { |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store }); |
|||
await keyv.set('foo', 'bar'); |
|||
const value = await keyv.get('foo'); |
|||
const rawObject = await keyv.get('foo', { raw: true }); |
|||
t.is(value, 'bar'); |
|||
t.is(rawObject.value, 'bar'); |
|||
}); |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store }) |
|||
await keyv.set('foo', 'bar') |
|||
const value = await keyv.get('foo') |
|||
const rawObject = await keyv.get('foo', { raw: true }) |
|||
t.is(value, 'bar') |
|||
t.is(rawObject.value, 'bar') |
|||
}) |
|||
|
|||
test.serial('Keyv uses custom serializer when provided instead of json-buffer', async t => { |
|||
t.plan(3); |
|||
const store = new Map(); |
|||
t.plan(3) |
|||
const store = new Map() |
|||
const serialize = data => { |
|||
t.pass(); |
|||
return JSON.stringify(data); |
|||
}; |
|||
t.pass() |
|||
return JSON.stringify(data) |
|||
} |
|||
|
|||
const deserialize = data => { |
|||
t.pass(); |
|||
return JSON.parse(data); |
|||
}; |
|||
t.pass() |
|||
return JSON.parse(data) |
|||
} |
|||
|
|||
const keyv = new Keyv({ store, serialize, deserialize }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
}); |
|||
const keyv = new Keyv({ store, serialize, deserialize }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
}) |
|||
|
|||
test.serial('Keyv supports async serializer/deserializer', async t => { |
|||
t.plan(3); |
|||
const store = new Map(); |
|||
t.plan(3) |
|||
const store = new Map() |
|||
|
|||
const serialize = async data => { |
|||
t.pass(); |
|||
return JSON.stringify(data); |
|||
}; |
|||
t.pass() |
|||
return JSON.stringify(data) |
|||
} |
|||
|
|||
const deserialize = async data => { |
|||
t.pass(); |
|||
return JSON.parse(data); |
|||
}; |
|||
t.pass() |
|||
return JSON.parse(data) |
|||
} |
|||
|
|||
const keyv = new Keyv({ store, serialize, deserialize }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is(await keyv.get('foo'), 'bar'); |
|||
}); |
|||
const keyv = new Keyv({ store, serialize, deserialize }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is(await keyv.get('foo'), 'bar') |
|||
}) |
|||
|
|||
test.serial('Keyv uses a default namespace', async t => { |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is([...store.keys()][0], 'keyv:foo'); |
|||
}); |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is([...store.keys()][0], 'keyv:foo') |
|||
}) |
|||
|
|||
test.serial('Default namespace can be overridden', async t => { |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store, namespace: 'magic' }); |
|||
await keyv.set('foo', 'bar'); |
|||
t.is([...store.keys()][0], 'magic:foo'); |
|||
}); |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store, namespace: 'magic' }) |
|||
await keyv.set('foo', 'bar') |
|||
t.is([...store.keys()][0], 'magic:foo') |
|||
}) |
|||
|
|||
test.serial('An empty namespace stores the key as-is', async t => { |
|||
const store = new Map(); |
|||
const keyv = new Keyv({ store, namespace: '' }); |
|||
await keyv.set(42, 'foo'); |
|||
t.is([...store.keys()][0], 42); |
|||
}); |
|||
|
|||
const store = () => new Map(); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = new Map() |
|||
const keyv = new Keyv({ store, namespace: '' }) |
|||
await keyv.set(42, 'foo') |
|||
t.is([...store.keys()][0], 42) |
|||
}) |
|||
|
|||
const store = () => new Map() |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('this'); |
|||
const KeyvMongo = require('@keyvhq/keyv-mongo'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('this') |
|||
const KeyvMongo = require('@keyvhq/keyv-mongo') |
|||
|
|||
const store = () => new KeyvMongo('mongodb://127.0.0.1:27017'); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvMongo('mongodb://127.0.0.1:27017') |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('this'); |
|||
const KeyvMysql = require('@keyvhq/keyv-mysql'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('this') |
|||
const KeyvMysql = require('@keyvhq/keyv-mysql') |
|||
|
|||
const store = () => new KeyvMysql('mysql://mysql@localhost/keyv_test'); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvMysql('mysql://mysql@localhost/keyv_test') |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('this'); |
|||
const KeyvPostgres = require('postgres'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('this') |
|||
const KeyvPostgres = require('postgres') |
|||
|
|||
const store = () => new KeyvPostgres('postgresql://postgres@localhost:5432/keyv_test'); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvPostgres('postgresql://postgres@localhost:5432/keyv_test') |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('this'); |
|||
const KeyvRedis = require('redis'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('this') |
|||
const KeyvRedis = require('redis') |
|||
|
|||
const store = () => new KeyvRedis('redis://localhost'); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvRedis('redis://localhost') |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
@ -1,7 +1,7 @@ |
|||
const test = require('ava'); |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite'); |
|||
const Keyv = require('this'); |
|||
const KeyvSqlite = require('sqlite'); |
|||
const test = require('ava') |
|||
const keyvTestSuite = require('@keyvhq/keyv-test-suite') |
|||
const Keyv = require('this') |
|||
const KeyvSqlite = require('sqlite') |
|||
|
|||
const store = () => new KeyvSqlite('sqlite://test/testdb.sqlite'); |
|||
keyvTestSuite(test, Keyv, store); |
|||
const store = () => new KeyvSqlite('sqlite://test/testdb.sqlite') |
|||
keyvTestSuite(test, Keyv, store) |
|||
|
Loading…
Reference in new issue