diff --git a/README.md b/README.md index 95dd124..09c2bff 100644 --- a/README.md +++ b/README.md @@ -56,6 +56,68 @@ fastify.register(fastifyRedis, { client: redis }) // ... ``` +## Registering multiple Redis client instances + +By using the `namespace` option you can register multiple Redis client instances. + +```js +const fastify = require('fastify') +const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) + +fastify + .register(require('fastify-redis'), { + host: '127.0.0.1', + port: 6380, + namespace: 'hello' + }) + .register(require('fastify-redis'), { + client: redis, + namespace: 'world' + }) + +// Here we will use the `hello` named instance +fastify.get('/hello', (req, reply) => { + const { redis } = fastify + + redis.hello.get(req.query.key, (err, val) => { + reply.send(err || val) + }) +}) + +fastify.post('/hello', (req, reply) => { + const { redis } = fastify + + redis['hello'].set(req.body.key, req.body.value, (err) => { + reply.send(err || { status: 'ok' }) + }) +}) + +// Here we will use the `world` named instance +fastify.get('/world', (req, reply) => { + const { redis } = fastify + + redis['world'].get(req.query.key, (err, val) => { + reply.send(err || val) + }) +}) + +fastify.post('/world', (req, reply) => { + const { redis } = fastify + + redis.world.set(req.body.key, req.body.value, (err) => { + reply.send(err || { status: 'ok' }) + }) +}) + +fastify.listen(3000, function (err) { + if (err) { + fastify.log.error(err) + process.exit(1) + } +}) + +``` + ## Acknowledgements This project is kindly sponsored by: diff --git a/index.js b/index.js index 247c3c1..60fe3f5 100644 --- a/index.js +++ b/index.js @@ -4,18 +4,52 @@ const fp = require('fastify-plugin') const Redis = require('ioredis') function fastifyRedis (fastify, options, next) { - var client = options.client || null + const namespace = options.namespace + delete options.namespace - if (!client) { - try { - client = new Redis(options) - } catch (err) { - return next(err) + let client = options.client || null + + if (namespace) { + if (!fastify.redis) { + fastify.decorate('redis', {}) } - fastify.addHook('onClose', close) - } - fastify.decorate('redis', client) + if (fastify.redis[namespace]) { + return next(new Error(`Redis '${namespace}' instance namespace has already been registered`)) + } + + const closeNamedInstance = (fastify, done) => { + fastify.redis[namespace].quit(done) + } + + if (!client) { + try { + client = new Redis(options) + } catch (err) { + return next(err) + } + + fastify.addHook('onClose', closeNamedInstance) + } + + fastify.redis[namespace] = client + } else { + if (fastify.redis) { + next(new Error('fastify-redis has already been registered')) + } else { + if (!client) { + try { + client = new Redis(options) + } catch (err) { + return next(err) + } + + fastify.addHook('onClose', close) + } + + fastify.decorate('redis', client) + } + } next() } diff --git a/test.js b/test.js index 6af1a70..4fc758d 100644 --- a/test.js +++ b/test.js @@ -5,14 +5,14 @@ const test = t.test const Fastify = require('fastify') const fastifyRedis = require('./index') -t.beforeEach(done => { +t.beforeEach((done) => { const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) - fastify.ready(err => { + fastify.ready((err) => { t.error(err) fastify.redis.flushall(() => { @@ -22,14 +22,14 @@ t.beforeEach(done => { }) }) -test('fastify.redis should exist', t => { +test('fastify.redis should exist', (t) => { t.plan(2) const fastify = Fastify() fastify.register(fastifyRedis, { host: '127.0.0.1' }) - fastify.ready(err => { + fastify.ready((err) => { t.error(err) t.ok(fastify.redis) @@ -37,7 +37,7 @@ test('fastify.redis should exist', t => { }) }) -test('fastify.redis should be the redis client', t => { +test('fastify.redis should be the redis client', (t) => { t.plan(4) const fastify = Fastify() @@ -45,10 +45,10 @@ test('fastify.redis should be the redis client', t => { host: '127.0.0.1' }) - fastify.ready(err => { + fastify.ready((err) => { t.error(err) - fastify.redis.set('key', 'value', err => { + fastify.redis.set('key', 'value', (err) => { t.error(err) fastify.redis.get('key', (err, val) => { t.error(err) @@ -60,7 +60,49 @@ test('fastify.redis should be the redis client', t => { }) }) -test('promises support', t => { +test('fastify.redis.test namespace should exist', (t) => { + t.plan(3) + + const fastify = Fastify() + fastify.register(fastifyRedis, { + host: '127.0.0.1', + namespace: 'test' + }) + + fastify.ready((err) => { + t.error(err) + t.ok(fastify.redis) + t.ok(fastify.redis.test) + + fastify.close() + }) +}) + +test('fastify.redis.test should be the redis client', (t) => { + t.plan(4) + const fastify = Fastify() + + fastify.register(fastifyRedis, { + host: '127.0.0.1', + namespace: 'test' + }) + + fastify.ready((err) => { + t.error(err) + + fastify.redis.test.set('key_namespace', 'value_namespace', (err) => { + t.error(err) + fastify.redis.test.get('key_namespace', (err, val) => { + t.error(err) + t.equal(val, 'value_namespace') + + fastify.close() + }) + }) + }) +}) + +test('promises support', (t) => { t.plan(2) const fastify = Fastify() @@ -68,33 +110,34 @@ test('promises support', t => { host: '127.0.0.1' }) - fastify.ready(err => { + fastify.ready((err) => { t.error(err) - fastify.redis.set('key', 'value') + fastify.redis + .set('key', 'value') .then(() => { return fastify.redis.get('key') }) - .then(val => { + .then((val) => { t.equal(val, 'value') fastify.close() }) - .catch(err => t.fail(err)) + .catch((err) => t.fail(err)) }) }) -test('custom client', t => { +test('custom client', (t) => { t.plan(7) const fastify = Fastify() const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) fastify.register(fastifyRedis, { client: redis }) - fastify.ready(err => { + fastify.ready((err) => { t.error(err) t.is(fastify.redis, redis) - fastify.redis.set('key', 'value', err => { + fastify.redis.set('key', 'value', (err) => { t.error(err) fastify.redis.get('key', (err, val) => { t.error(err) @@ -110,3 +153,107 @@ test('custom client', t => { }) }) }) + +test('custom client inside a namespace', (t) => { + t.plan(7) + const fastify = Fastify() + const redis = require('redis').createClient({ host: 'localhost', port: 6379 }) + + fastify.register(fastifyRedis, { + namespace: 'test', + client: redis + }) + + fastify.ready((err) => { + t.error(err) + t.is(fastify.redis.test, redis) + + fastify.redis.test.set('key', 'value', (err) => { + t.error(err) + fastify.redis.test.get('key', (err, val) => { + t.error(err) + t.equal(val, 'value') + + fastify.close(function (err) { + t.error(err) + fastify.redis.test.quit(function (err) { + t.error(err) + }) + }) + }) + }) + }) +}) + +test('fastify.redis.test should throw with duplicate connection namespaces', (t) => { + t.plan(1) + + const namespace = 'test' + + const fastify = Fastify() + t.teardown(() => fastify.close()) + + fastify + .register(fastifyRedis, { + host: '127.0.0.1', + namespace + }) + .register(fastifyRedis, { + host: '127.0.0.1', + namespace + }) + + fastify.ready((err) => { + t.is(err.message, `Redis '${namespace}' instance namespace has already been registered`) + }) +}) + +test('Should throw when trying to register multiple instances without giving a namespace', (t) => { + t.plan(1) + + const fastify = Fastify() + t.teardown(() => fastify.close()) + + fastify + .register(fastifyRedis, { + host: '127.0.0.1' + }) + .register(fastifyRedis, { + host: '127.0.0.1' + }) + + fastify.ready((err) => { + t.is(err.message, 'fastify-redis has already been registered') + }) +}) + +test('Should not throw within different contexts', (t) => { + t.plan(1) + + const fastify = Fastify() + t.teardown(() => fastify.close()) + + fastify.register(function (instance, options, next) { + instance.register(fastifyRedis, { + host: '127.0.0.1' + }) + next() + }) + + fastify.register(function (instance, options, next) { + instance + .register(fastifyRedis, { + host: '127.0.0.1', + namespace: 'test1' + }) + .register(fastifyRedis, { + host: '127.0.0.1', + namespace: 'test2' + }) + next() + }) + + fastify.ready((error) => { + t.is(error, null) + }) +})