Skip to content

Commit

Permalink
Merge a93f612 into 0f5da85
Browse files Browse the repository at this point in the history
  • Loading branch information
Kikobeats committed May 30, 2021
2 parents 0f5da85 + a93f612 commit 2774f88
Show file tree
Hide file tree
Showing 9 changed files with 67 additions and 49 deletions.
4 changes: 2 additions & 2 deletions packages/keyv-mongo/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@ class KeyvMongo extends EventEmitter {

clear() {
return this.connect
.then(store => store.deleteMany({ key: new RegExp(`^${this.namespace}:`) })
.then(store => store.deleteMany({ key: new RegExp(`^${this.namespace}`) })
.then(() => undefined));
}

async * iterator() {
const iterator = await this.connect
.then(store => store.find({ key: new RegExp(`^${this.namespace}:`) }).map(x => {
.then(store => store.find({ key: new RegExp(`^${this.namespace}`) }).map(x => {
return [x.key, x.value];
}));
yield * iterator;
Expand Down
3 changes: 2 additions & 1 deletion packages/keyv-redis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
},
"homepage": "https://github.com/keyvhq/keyv",
"dependencies": {
"ioredis": "~4.17.1"
"ioredis": "~4.17.1",
"p-event": "~4.2.0"
},
"gitHead": "a4e2c1f285236a753de13eb8a42d9a98690526cc"
}
71 changes: 33 additions & 38 deletions packages/keyv-redis/src/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict';

const EventEmitter = require('events');
const pEvent = require('p-event');
const Redis = require('ioredis');
const pify = require('pify');

class KeyvRedis extends EventEmitter {
constructor(uri, options) {
Expand All @@ -11,60 +11,55 @@ class KeyvRedis extends EventEmitter {
if (uri instanceof Redis) {
this.redis = uri;
} else {
options = Object.assign({}, typeof uri === 'string' ? { uri } : uri, options);
options = Object.assign(
{},
typeof uri === 'string' ? { uri } : uri,
options
);
this.redis = new Redis(options.uri, options);
}

this.redis.on('error', error => this.emit('error', error));
}

_getNamespace() {
return `namespace:${this.namespace}`;
async get(key) {
const value = await this.redis.get(key);
return value === null ? undefined : value;
}

get(key) {
return this.redis.get(key)
.then(value => {
if (value === null) {
return undefined;
}

return value;
});
}

set(key, value, ttl) {
async set(key, value, ttl) {
if (typeof value === 'undefined') {
return Promise.resolve(undefined);
return undefined;
}

return Promise.resolve()
.then(() => {
if (typeof ttl === 'number') {
return this.redis.set(key, value, 'PX', ttl);
}

return this.redis.set(key, value);
})
.then(() => this.redis.sadd(this._getNamespace(), key));
return typeof ttl === 'number' ?
this.redis.set(key, value, 'PX', ttl) :
this.redis.set(key, value);
}

delete(key) {
return this.redis.del(key)
.then(items => {
return this.redis.srem(this._getNamespace(), key)
.then(() => items > 0);
});
async delete(key) {
const result = await this.redis.unlink(key);
return result > 0;
}

clear() {
return this.redis.smembers(this._getNamespace())
.then(keys => this.redis.del(keys.concat(this._getNamespace())))
.then(() => undefined);
async clear() {
if (this.namespace === undefined) {
await this.redis.flushall();
return undefined;
}

const stream = this.redis.scanStream({ match: `${this.namespace}*` });

const keys = [];
stream.on('data', matchedKeys => keys.push(...matchedKeys));
await pEvent(stream, 'end');
if (keys.length > 0) {
await this.redis.unlink(keys);
}
}

async * iterator() {
const scan = pify(this.redis.scan).bind(this.redis);
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);
Expand All @@ -82,7 +77,7 @@ class KeyvRedis extends EventEmitter {
}
}

yield * iterate(0, `${this.namespace}:*`);
yield * iterate(0, `${this.namespace}*`);
}
}

Expand Down
4 changes: 2 additions & 2 deletions packages/keyv-sql/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ class KeyvSql extends EventEmitter {
}

clear() {
const del = this.options.dialect === 'mysql' ? `DELETE FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` LIKE '${this.namespace}:%')` : `DELETE FROM "${this.options.table}" WHERE ("${this.options.table}"."key" LIKE '${this.namespace}:%')`;
const del = this.options.dialect === 'mysql' ? `DELETE FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` LIKE '${this.namespace}%')` : `DELETE FROM "${this.options.table}" WHERE ("${this.options.table}"."key" LIKE '${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}:%') LIMIT ${limit} OFFSET ` : `SELECT * FROM "${this.options.table}" WHERE ("${this.options.table}"."key" LIKE '${this.namespace}:%') LIMIT ${limit} OFFSET `;
const selectChunk = this.options.dialect === 'mysql' ? `SELECT * FROM \`${this.options.table}\` WHERE (\`${this.options.table}\`.\`key\` LIKE '${this.namespace}%') LIMIT ${limit} OFFSET ` : `SELECT * FROM "${this.options.table}" WHERE ("${this.options.table}"."key" LIKE '${this.namespace}%') LIMIT ${limit} OFFSET `;

async function * iterate(offset, query) {
const entries = await query(selectChunk + offset);
Expand Down
1 change: 1 addition & 0 deletions packages/keyv-test-suite/src/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const keyvApiTests = (test, Keyv, store) => {

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);
});

Expand Down
6 changes: 3 additions & 3 deletions packages/keyv-test-suite/src/index.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
const keyvApiTests = require('./api.js');
const keyvValueTests = require('./values.js');
const keyvNamepsaceTests = require('./namespace.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);
keyvNamepsaceTests(test, Keyv, store);
keyvNamespaceTests(test, Keyv, store);
};

Object.assign(keyvTestSuite, {
keyvApiTests,
keyvValueTests,
keyvNamepsaceTests,
keyvNamespaceTests,
keyvIteratorTests
});

Expand Down
2 changes: 1 addition & 1 deletion packages/keyv/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@keyvhq/keyv",
"version": "0.2.2",
"version": "0.2.3",
"description": "Simple key-value storage with support for multiple backends",
"main": "src/index.js",
"scripts": {
Expand Down
4 changes: 2 additions & 2 deletions packages/keyv/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Keyv extends EventEmitter {
this.store.on('error', error => this.emit('error', error));
}

this.store.namespace = this.options.namespace;
this.store.namespace = this.options.namespace ? this.options.namespace + ':' : '';

const generateIterator = iterator => async function * () {
for await (const [key, raw] of (typeof iterator === 'function' ? iterator() : iterator)) {
Expand Down Expand Up @@ -54,7 +54,7 @@ class Keyv extends EventEmitter {
}

_getKeyPrefix(key) {
return `${this.options.namespace}:${key}`;
return this.options.namespace ? `${this.options.namespace}:${key}` : key;
}

_getKeyUnprefix(key) {
Expand Down
21 changes: 21 additions & 0 deletions packages/keyv/test/keyv.js
Original file line number Diff line number Diff line change
Expand Up @@ -124,5 +124,26 @@ test.serial('Keyv supports async serializer/deserializer', async t => {
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');
});

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');
});

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);

0 comments on commit 2774f88

Please sign in to comment.