Skip to content

Commit 5eaa089

Browse files
authored
Merge pull request #33 from dial-once/feature/options-by-url
Add support for using url instead of options for redis.
2 parents 116247d + 64aec70 commit 5eaa089

File tree

4 files changed

+115
-4
lines changed

4 files changed

+115
-4
lines changed

README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,20 @@ multiCache.wrap(key2, function (cb) {
124124
});
125125
```
126126

127+
### Using a URL instead of options (if url is correct it overrides options host, port, db, auth_pass and ttl)
128+
Urls should be in this format `redis://[:password@]host[:port][/db-number][?ttl=value]`
129+
```js
130+
var cacheManager = require('cache-manager');
131+
var redisStore = require('cache-manager-redis');
132+
133+
var redisCache = cacheManager.caching({
134+
store: redisStore,
135+
url: 'redis://:XXXX@localhost:6379/0?ttl=600'
136+
});
137+
138+
// proceed with redisCache
139+
```
140+
127141
Tests
128142
-----
129143

index.js

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
var RedisPool = require('sol-redis-pool');
44
var EventEmitter = require('events').EventEmitter;
5+
var redisUrl = require('redis-url');
56

67
/**
78
* The cache manager Redis Store module
@@ -20,11 +21,11 @@ function redisStore(args) {
2021

2122
// cache-manager should always pass in args
2223
/* istanbul ignore next */
23-
var redisOptions = args || {};
24+
var redisOptions = getFromUrl(args) || args || {};
2425
var poolSettings = redisOptions;
2526

26-
redisOptions.host = args.host || '127.0.0.1';
27-
redisOptions.port = args.port || 6379;
27+
redisOptions.host = redisOptions.host || '127.0.0.1';
28+
redisOptions.port = redisOptions.port || 6379;
2829

2930
var pool = new RedisPool(redisOptions, poolSettings);
3031

@@ -74,7 +75,7 @@ function redisStore(args) {
7475

7576
try {
7677
// allow undefined only if allowed by isCacheableValue
77-
if(! ( (result === undefined || result === "undefined") && typeof args.isCacheableValue === 'function' && args.isCacheableValue(result))) {
78+
if(! ( (result === undefined || result === 'undefined') && typeof args.isCacheableValue === 'function' && args.isCacheableValue(result))) {
7879
result = JSON.parse(result);
7980
}
8081
} catch (e) {
@@ -88,6 +89,63 @@ function redisStore(args) {
8889
};
8990
}
9091

92+
/**
93+
* Extracts options from an args.url
94+
* @param {Object} args
95+
* @param {String} args.url a string in format of redis://[:password@]host[:port][/db-number][?option=value]
96+
* @returns {Object} the input object args if it is falsy, does not contain url or url is not string, otherwise a new object with own properties of args
97+
* but with host, port, db, ttl and auth_pass properties overridden by those provided in args.url.
98+
*/
99+
function getFromUrl(args) {
100+
if (!args || typeof args.url !== 'string') {
101+
return args;
102+
}
103+
104+
try {
105+
var options = redisUrl.parse(args.url);
106+
// make a clone so we don't change input args
107+
return applyOptionsToArgs(args, options);
108+
} catch (e) {
109+
//url is unparsable so returning original
110+
return args;
111+
}
112+
113+
}
114+
115+
/**
116+
* Clones args'es own properties to a new object and sets isCacheableValue on the new object
117+
* @param {Object} args
118+
* @returns {Object} a clone of the args object
119+
*/
120+
function cloneArgs(args) {
121+
var newArgs = {};
122+
for(var key in args){
123+
if (key && args.hasOwnProperty(key)) {
124+
newArgs[key] = args[key];
125+
}
126+
}
127+
newArgs.isCacheableValue = args.isCacheableValue && args.isCacheableValue.bind(newArgs);
128+
return newArgs;
129+
}
130+
131+
/**
132+
* Apply some options like hostname , port, db, ttl auth_pass from options to newArgs host, port, db, auth_pass and ttl and return clone of args
133+
* @param {Object} args
134+
* @param {Object} options
135+
* @returns {Object} clone of args param with properties set to those of options
136+
*/
137+
function applyOptionsToArgs(args, options) {
138+
var newArgs = cloneArgs(args);
139+
newArgs.host = options.hostname;
140+
newArgs.port = parseInt(options.port, 10);
141+
newArgs.db = parseInt(options.database, 10);
142+
newArgs.auth_pass = options.password;
143+
if(options.query && options.query.ttl){
144+
newArgs.ttl = parseInt(options.query.ttl, 10);
145+
}
146+
return newArgs;
147+
}
148+
91149
/**
92150
* Get a value for a given key.
93151
* @method get

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
"license": "MIT",
2424
"dependencies": {
2525
"cache-manager": "^1.2.2",
26+
"redis-url": "^1.2.1",
2627
"sol-redis-pool": "^0.2.1"
2728
},
2829
"devDependencies": {

spec/lib/redis-store-spec.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,44 @@ describe('redisErrorEvent', function () {
346346
});
347347
});
348348

349+
describe('uses url to override redis options', function () {
350+
var redisCacheByUrl;
351+
352+
beforeAll(function () {
353+
redisCacheByUrl = require('cache-manager').caching({
354+
store: redisStore,
355+
// redis://[:password@]host[:port][/db-number][?option=value]
356+
url: 'redis://:' + config.redis.auth_pass +'@' + config.redis.host + ':' + config.redis.port + '/' + config.redis.db +'?ttl=' + config.redis.ttl,
357+
// some fakes to see that url overrides them
358+
host: 'test-host',
359+
port: -78,
360+
db: -7,
361+
auth_pass: 'test_pass',
362+
ttl: -6
363+
});
364+
});
365+
366+
it('should ignore other options if set in url', function() {
367+
expect(redisCacheByUrl.store._pool._redis_host).toBe(config.redis.host);
368+
expect(redisCacheByUrl.store._pool._redis_port).toBe(config.redis.port);
369+
expect(redisCacheByUrl.store._pool._redis_default_db).toBe(config.redis.db);
370+
expect(redisCacheByUrl.store._pool._redis_options.auth_pass).toBe(config.redis.auth_pass);
371+
});
372+
373+
it('should get and set values without error', function (done) {
374+
var key = 'byUrlKey';
375+
var value = 'test';
376+
redisCacheByUrl.set(key, value, function (err) {
377+
expect(err).toBe(null);
378+
redisCacheByUrl.get(key, function(getErr, val){
379+
expect(getErr).toBe(null);
380+
expect(val).toEqual(value);
381+
done();
382+
});
383+
});
384+
});
385+
});
386+
349387
describe('overridable isCacheableValue function', function () {
350388
var redisCache2;
351389

0 commit comments

Comments
 (0)