1
0
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:
Ruben Bridgewater
2016-03-31 19:14:30 +02:00
parent 861749f4d6
commit 3fd865bbb3
3 changed files with 228 additions and 60 deletions

View File

@@ -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
View 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;
};

View File

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