You've already forked node-redis
mirror of
https://github.com/redis/node-redis.git
synced 2025-08-06 02:15:48 +03:00
Move the exposed and documented api into a separate file
This commit is contained in:
57
index.js
57
index.js
@@ -180,6 +180,14 @@ util.inherits(RedisClient, EventEmitter);
|
||||
|
||||
RedisClient.connection_id = 0;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
All functions in here are internal besides the RedisClient constructor
|
||||
and the exported functions. Don't rely on them as they will be private
|
||||
functions in node_redis v.3
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
// Attention: the function name "create_stream" should not be changed, as other libraries need this to mock the stream (e.g. fakeredis)
|
||||
RedisClient.prototype.create_stream = function () {
|
||||
var self = this;
|
||||
@@ -269,17 +277,6 @@ RedisClient.prototype.handle_reply = function (reply, command) {
|
||||
RedisClient.prototype.cork = noop;
|
||||
RedisClient.prototype.uncork = noop;
|
||||
|
||||
RedisClient.prototype.duplicate = function (options) {
|
||||
var existing_options = utils.clone(this.options);
|
||||
options = utils.clone(options);
|
||||
for (var elem in options) { // jshint ignore: line
|
||||
existing_options[elem] = options[elem];
|
||||
}
|
||||
var client = new RedisClient(existing_options);
|
||||
client.selected_db = this.selected_db;
|
||||
return client;
|
||||
};
|
||||
|
||||
RedisClient.prototype.initialize_retry_vars = function () {
|
||||
this.retry_timer = null;
|
||||
this.retry_totaltime = 0;
|
||||
@@ -288,18 +285,6 @@ RedisClient.prototype.initialize_retry_vars = function () {
|
||||
this.attempts = 1;
|
||||
};
|
||||
|
||||
RedisClient.prototype.unref = function () {
|
||||
if (this.connected) {
|
||||
debug("Unref'ing the socket connection");
|
||||
this.stream.unref();
|
||||
} else {
|
||||
debug('Not connected yet, will unref later');
|
||||
this.once('connect', function () {
|
||||
this.unref();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
RedisClient.prototype.warn = function (msg) {
|
||||
var self = this;
|
||||
// Warn on the next tick. Otherwise no event listener can be added
|
||||
@@ -918,29 +903,6 @@ RedisClient.prototype.write = function (data) {
|
||||
return;
|
||||
};
|
||||
|
||||
RedisClient.prototype.end = function (flush) {
|
||||
// Flush queue if wanted
|
||||
if (flush) {
|
||||
this.flush_and_error(new Error("The command can't be processed. The connection has already been closed."));
|
||||
} else if (arguments.length === 0) {
|
||||
this.warn(
|
||||
'Using .end() without the flush parameter is deprecated and throws from v.3.0.0 on.\n' +
|
||||
'Please check the doku (https://github.com/NodeRedis/node_redis) and explictly use flush.'
|
||||
);
|
||||
}
|
||||
// Clear retry_timer
|
||||
if (this.retry_timer) {
|
||||
clearTimeout(this.retry_timer);
|
||||
this.retry_timer = null;
|
||||
}
|
||||
this.stream.removeAllListeners();
|
||||
this.stream.on('error', noop);
|
||||
this.connected = false;
|
||||
this.ready = false;
|
||||
this.closing = true;
|
||||
return this.stream.destroySoon();
|
||||
};
|
||||
|
||||
exports.createClient = function () {
|
||||
return new RedisClient(unifyOptions.apply(null, arguments));
|
||||
};
|
||||
@@ -948,6 +910,7 @@ exports.RedisClient = RedisClient;
|
||||
exports.print = utils.print;
|
||||
exports.Multi = require('./lib/multi');
|
||||
|
||||
// Add all redis commands to the client
|
||||
// Add all redis commands / node_redis api to the client
|
||||
require('./lib/individualCommands');
|
||||
require('./lib/extendedApi');
|
||||
require('./lib/commands');
|
||||
|
91
lib/extendedApi.js
Normal file
91
lib/extendedApi.js
Normal file
@@ -0,0 +1,91 @@
|
||||
'use strict';
|
||||
|
||||
var utils = require('./utils');
|
||||
var debug = require('./debug');
|
||||
var RedisClient = require('../').RedisClient;
|
||||
var noop = function () {};
|
||||
|
||||
/**********************************************
|
||||
All documented and exposed API belongs in here
|
||||
**********************************************/
|
||||
|
||||
// Redirect calls to the appropriate function and use to send arbitrary / not supported commands
|
||||
RedisClient.prototype.send_command = function (command, args, callback) {
|
||||
// Throw to fail early instead of relying in order in this case
|
||||
if (typeof command !== 'string') {
|
||||
throw new Error('Wrong input type "' + (command !== null && command !== undefined ? command.constructor.name : command) + '" for command name');
|
||||
}
|
||||
if (!Array.isArray(args)) {
|
||||
if (args === undefined || args === null) {
|
||||
args = [];
|
||||
} else if (typeof args === 'function' && callback === undefined) {
|
||||
callback = args;
|
||||
args = [];
|
||||
} else {
|
||||
throw new Error('Wrong input type "' + args.constructor.name + '" for args');
|
||||
}
|
||||
}
|
||||
if (typeof callback !== 'function' && callback !== undefined) {
|
||||
throw new Error('Wrong input type "' + (callback !== null ? callback.constructor.name : 'null') + '" for callback function');
|
||||
}
|
||||
|
||||
// Using the raw multi command is only possible with this function
|
||||
// If the command is not yet added to the client, the internal function should be called right away
|
||||
// Otherwise we need to redirect the calls to make sure the interal functions don't get skipped
|
||||
// The internal functions could actually be used for any non hooked function
|
||||
// but this might change from time to time and at the moment there's no good way to distinguishe them
|
||||
// from each other, so let's just do it do it this way for the time being
|
||||
if (command === 'multi' || typeof this[command] !== 'function') {
|
||||
return this.internal_send_command(command, args, callback);
|
||||
}
|
||||
if (typeof callback === 'function') {
|
||||
args = args.concat([callback]);
|
||||
}
|
||||
return this[command].apply(this, args);
|
||||
};
|
||||
|
||||
RedisClient.prototype.end = function (flush) {
|
||||
// Flush queue if wanted
|
||||
if (flush) {
|
||||
this.flush_and_error(new Error("The command can't be processed. The connection has already been closed."));
|
||||
} else if (arguments.length === 0) {
|
||||
this.warn(
|
||||
'Using .end() without the flush parameter is deprecated and throws from v.3.0.0 on.\n' +
|
||||
'Please check the doku (https://github.com/NodeRedis/node_redis) and explictly use flush.'
|
||||
);
|
||||
}
|
||||
// Clear retry_timer
|
||||
if (this.retry_timer) {
|
||||
clearTimeout(this.retry_timer);
|
||||
this.retry_timer = null;
|
||||
}
|
||||
this.stream.removeAllListeners();
|
||||
this.stream.on('error', noop);
|
||||
this.connected = false;
|
||||
this.ready = false;
|
||||
this.closing = true;
|
||||
return this.stream.destroySoon();
|
||||
};
|
||||
|
||||
RedisClient.prototype.unref = function () {
|
||||
if (this.connected) {
|
||||
debug("Unref'ing the socket connection");
|
||||
this.stream.unref();
|
||||
} else {
|
||||
debug('Not connected yet, will unref later');
|
||||
this.once('connect', function () {
|
||||
this.unref();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
RedisClient.prototype.duplicate = function (options) {
|
||||
var existing_options = utils.clone(this.options);
|
||||
options = utils.clone(options);
|
||||
for (var elem in options) { // jshint ignore: line
|
||||
existing_options[elem] = options[elem];
|
||||
}
|
||||
var client = new RedisClient(existing_options);
|
||||
client.selected_db = this.selected_db;
|
||||
return client;
|
||||
};
|
@@ -109,33 +109,147 @@ describe('The node_redis client', function () {
|
||||
|
||||
describe('send_command', function () {
|
||||
|
||||
it('omitting args should be fine in some cases', function (done) {
|
||||
it('omitting args should be fine', function (done) {
|
||||
client.server_info = {};
|
||||
client.send_command('info');
|
||||
client.send_command('ping', function (err, res) {
|
||||
assert.strictEqual(res, 'PONG');
|
||||
// Check if the previous info command used the internal individual info command
|
||||
assert.notDeepEqual(client.server_info, {});
|
||||
client.server_info = {};
|
||||
});
|
||||
client.send_command('info', null, undefined);
|
||||
client.send_command('ping', null, function (err, res) {
|
||||
assert.strictEqual(res, 'PONG');
|
||||
// Check if the previous info command used the internal individual info command
|
||||
assert.notDeepEqual(client.server_info, {});
|
||||
client.server_info = {};
|
||||
});
|
||||
client.send_command('info', undefined, undefined);
|
||||
client.send_command('ping', function (err, res) {
|
||||
assert.strictEqual(res, 'PONG');
|
||||
// Check if the previous info command used the internal individual info command
|
||||
assert.notDeepEqual(client.server_info, {});
|
||||
client.server_info = {};
|
||||
});
|
||||
client.send_command('info', undefined, function (err, res) {
|
||||
assert(/redis_version/.test(res));
|
||||
// The individual info command should also be called by using send_command
|
||||
// console.log(info, client.server_info);
|
||||
assert.notDeepEqual(client.server_info, {});
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('using another type as cb should just work as if there were no callback parameter', function (done) {
|
||||
it('using multi with send_command should work as individual command instead of using the internal multi', function (done) {
|
||||
// This is necessary to keep backwards compatibility and it is the only way to handle multis as you want in node_redis
|
||||
client.send_command('multi');
|
||||
client.send_command('set', ['foo', 'bar'], helper.isString('QUEUED'));
|
||||
client.get('foo');
|
||||
client.exec(function (err, res) { // exec is not manipulated if not fired by the individual multi command
|
||||
// As the multi command is handled individually by the user he also has to handle the return value
|
||||
assert.strictEqual(res[0].toString(), 'OK');
|
||||
assert.strictEqual(res[1].toString(), 'bar');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('multi should be handled special', function (done) {
|
||||
client.send_command('multi', undefined, helper.isString('OK'));
|
||||
var args = ['test', 'bla'];
|
||||
client.send_command('set', args, helper.isString('QUEUED'));
|
||||
assert.deepEqual(args, ['test', 'bla']); // Check args manipulation
|
||||
client.get('test', helper.isString('QUEUED'));
|
||||
client.exec(function (err, res) {
|
||||
// As the multi command is handled individually by the user he also has to handle the return value
|
||||
assert.strictEqual(res[0].toString(), 'OK');
|
||||
assert.strictEqual(res[1].toString(), 'bla');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('using another type as cb should throw', function () {
|
||||
try {
|
||||
client.send_command('set', ['test', 'bla'], [true]);
|
||||
client.get('test', function (err, res) {
|
||||
assert.equal(res, 'bla');
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "Array" for callback function');
|
||||
}
|
||||
try {
|
||||
client.send_command('set', ['test', 'bla'], null);
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "null" for callback function');
|
||||
}
|
||||
});
|
||||
|
||||
it('command argument has to be of type string', function () {
|
||||
try {
|
||||
client.send_command(true, ['test', 'bla'], function () {});
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "Boolean" for command name');
|
||||
}
|
||||
try {
|
||||
client.send_command(undefined, ['test', 'bla'], function () {});
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "undefined" for command name');
|
||||
}
|
||||
try {
|
||||
client.send_command(null, ['test', 'bla'], function () {});
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "null" for command name');
|
||||
}
|
||||
});
|
||||
|
||||
it('args may only be of type Array or undefined', function () {
|
||||
try {
|
||||
client.send_command('info', 123);
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "Number" for args');
|
||||
}
|
||||
});
|
||||
|
||||
it('passing a callback as args and as callback should throw', function () {
|
||||
try {
|
||||
client.send_command('info', function a () {}, function b () {});
|
||||
throw new Error('failed');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'Wrong input type "Function" for args');
|
||||
}
|
||||
});
|
||||
|
||||
it('multi should be handled special', function (done) {
|
||||
client.send_command('multi', undefined, helper.isString('OK'));
|
||||
var args = ['test', 'bla'];
|
||||
client.send_command('set', args, helper.isString('QUEUED'));
|
||||
assert.deepEqual(args, ['test', 'bla']); // Check args manipulation
|
||||
client.get('test', helper.isString('QUEUED'));
|
||||
client.exec(function (err, res) {
|
||||
// As the multi command is handled individually by the user he also has to handle the return value
|
||||
assert.strictEqual(res[0].toString(), 'OK');
|
||||
assert.strictEqual(res[1].toString(), 'bla');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('misusing the function should eventually throw (no command)', function (done) {
|
||||
client.send_command(true, 'info', function (err, res) {
|
||||
assert(/ERR Protocol error/.test(err.message));
|
||||
assert.equal(err.command, undefined);
|
||||
assert.equal(err.code, 'ERR');
|
||||
it('the args array may contain a arbitrary number of arguments', function (done) {
|
||||
client.send_command('mset', ['foo', 1, 'bar', 2, 'baz', 3], helper.isString('OK'));
|
||||
client.mget(['foo', 'bar', 'baz'], function (err, res) {
|
||||
// As the multi command is handled individually by the user he also has to handle the return value
|
||||
assert.strictEqual(res[0].toString(), '1');
|
||||
assert.strictEqual(res[1].toString(), '2');
|
||||
assert.strictEqual(res[2].toString(), '3');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('misusing the function should eventually throw (wrong args)', function (done) {
|
||||
client.send_command('info', false, function (err, res) {
|
||||
assert.equal(err.message, 'ERR Protocol error: invalid multibulk length');
|
||||
it('send_command with callback as args', function (done) {
|
||||
client.send_command('abcdef', function (err, res) {
|
||||
assert.strictEqual(err.message, "ERR unknown command 'abcdef'");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
Reference in New Issue
Block a user