Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'feature/expire'

  • Loading branch information...
commit cd384a9f293bc60ad2715e83cd440e6acb61714d 2 parents 27f1231 + 4f31456
@tj authored
View
40 lib/commands/hash.js
@@ -9,15 +9,15 @@
* Module dependencies.
*/
-var utils = require('../utils');
+var utils = require('../utils')
+ , string = utils.string;
/**
* HLEN <key>
*/
exports.hlen = function(client, key){
- var key = utils.string(key)
- , obj = this.db.data[key];
+ var obj = this.lookup(string(key));
if (!obj) {
client.int(0);
@@ -33,8 +33,7 @@ exports.hlen = function(client, key){
*/
exports.hvals = function(client, key){
- var key = utils.string(key)
- , obj = this.db.data[key];
+ var obj = this.lookup(string(key));
if (!obj) {
client.emptyList();
@@ -52,8 +51,7 @@ exports.hvals = function(client, key){
*/
exports.hkeys = function(client, key){
- var key = utils.string(key)
- , obj = this.db.data[key];
+ var obj = this.lookup(string(key));
if (!obj) {
client.emptyList();
@@ -69,9 +67,9 @@ exports.hkeys = function(client, key){
*/
(exports.hset = function(client, key, field, val){
- var key = utils.string(key)
- , field = utils.string(field)
- , obj = this.db.data[key];
+ var key = string(key)
+ , field = string(field)
+ , obj = this.lookup(key);
if (obj && 'hash' != obj.type) return client.typeError();
obj = obj || (this.db.data[key] = { type: 'hash', val: {} });
@@ -86,8 +84,8 @@ exports.hkeys = function(client, key){
(exports.hmset = function(client, data){
var len = data.length
- , key = utils.string(data[0])
- , obj = this.db.data[key]
+ , key = string(data[0])
+ , obj = this.lookup(key)
, field
, val;
@@ -95,7 +93,7 @@ exports.hkeys = function(client, key){
obj = obj || (this.db.data[key] = { type: 'hash', val: {} });
for (var i = 1; i < len; ++i) {
- field = utils.string(data[i++]);
+ field = string(data[i++]);
val = data[i];
obj.val[field] = val;
}
@@ -111,9 +109,9 @@ exports.hmset.skip = 1;
*/
exports.hget = function(client, key, field){
- var key = utils.string(key)
- , field = utils.string(field)
- , obj = this.db.data[key]
+ var key = string(key)
+ , field = string(field)
+ , obj = this.lookup(key)
, val;
if (!obj) {
@@ -134,8 +132,8 @@ exports.hget = function(client, key, field){
*/
exports.hgetall = function(client, key){
- var key = utils.string(key)
- , obj = this.db.data[key]
+ var key = string(key)
+ , obj = this.lookup(key)
, list = [];
if (!obj) {
@@ -155,9 +153,9 @@ exports.hgetall = function(client, key){
*/
exports.hexists = function(client, key, field){
- var key = utils.string(key)
- , field = utils.string(field)
- , obj = this.db.data[key]
+ var key = string(key)
+ , field = string(field)
+ , obj = this.lookup(key);
if (obj) {
if ('hash' == obj.type) {
View
68 lib/commands/keys.js
@@ -13,12 +13,70 @@ var utils = require('../utils')
, string = utils.string;
/**
+ * EXPIRE <key> <seconds>
+ */
+
+exports.expire = function(client, key, seconds){
+ var obj = this.lookup(string(key));
+
+ if (obj) {
+ obj.expires = Date.now() + (string(seconds) * 1000);
+ client.bool(true);
+ } else {
+ client.bool(false);
+ }
+};
+
+/**
+ * EXPIREAT <key> <seconds>
+ */
+
+exports.expireat = function(client, key, seconds){
+ var obj = this.lookup(string(key));
+
+ if (obj) {
+ obj.expires = +string(seconds) * 1000;
+ client.bool(true);
+ } else {
+ client.bool(false);
+ }
+};
+
+/**
+ * PERSIST <key>
+ */
+
+exports.persist = function(client, key){
+ var obj = this.lookup(string(key));
+
+ if (obj && 'number' == typeof obj.expires) {
+ delete obj.expires;
+ client.bool(true);
+ } else {
+ client.bool(false);
+ }
+};
+
+/**
+ * TTL <key>
+ */
+
+exports.ttl = function(client, key){
+ var obj = this.lookup(string(key));
+
+ if (obj && 'number' == typeof obj.expires) {
+ client.int(obj.expires - Date.now());
+ } else {
+ client.nil();
+ }
+};
+
+/**
* TYPE <key>
*/
exports.type = function(client, key){
- var key = string(key)
- , obj = this.db.data[key];
+ var obj = this.lookup(string(key));
if (obj) {
client.write(obj.type);
@@ -32,7 +90,7 @@ exports.type = function(client, key){
*/
exports.exists = function(client, key){
- client.bool(this.db.data[string(key)]);
+ client.bool(this.lookup(string(key)));
};
/**
@@ -59,7 +117,7 @@ exports.randomkey = function(client){
// TODO: varg
// TODO: del count ?
key = string(key);
- if (this.db.data[key]) {
+ if (this.lookup(key)) {
delete this.db.data[key];
client.bool(true);
} else {
@@ -76,7 +134,7 @@ exports.randomkey = function(client){
// Fail if attempting to rename a non-existant key
from = string(from);
- if (null == data[from]) return client.error('no such key');
+ if (!this.lookup(from)) return client.error('no such key');
// Fail on same keys
to = string(to);
View
105 lib/commands/string.js
@@ -17,8 +17,7 @@ var utils = require('../utils')
*/
exports.get = function(client, key){
- var key = string(key)
- , obj = this.db.data[key];
+ var obj = this.lookup(string(key));
if (!obj) {
client.nil();
@@ -35,16 +34,14 @@ exports.get = function(client, key){
exports.getset = function(client, key, val){
var key = string(key)
- , prev = this.data[key]
- , prevType = this.keyType(key);
+ , obj = this.lookup(key);
- this.data[key] = val;
- this.keyType(key, 'string');
+ this.db.data[key] = { type: 'string', val: val };
- if (null == prev) {
+ if (!obj) {
client.nil();
- } else if ('string' == prevType) {
- client.send(prev);
+ } else if ('string' == obj.type) {
+ client.send(obj.val);
} else {
client.typeError();
}
@@ -66,9 +63,8 @@ exports.getset = function(client, key, val){
(exports.setnx = function(client, key, val){
key = string(key);
- if (null != this.data[key]) return client.bool(false);
- this.data[key] = val;
- this.keyType(key, 'string');
+ if (this.lookup(key)) return client.bool(false);
+ this.db.data[key] = { type: 'string', val: val };
client.bool(true);
}).mutates = true;
@@ -78,7 +74,7 @@ exports.getset = function(client, key, val){
(exports.incr = function(client, key){
var key = string(key)
- , obj = this.db.data[key];
+ , obj = this.lookup(key);
if (!obj) {
this.db.data[key] = { type: 'string', val: 1 };
@@ -98,7 +94,7 @@ exports.getset = function(client, key, val){
(exports.incrby = function(client, key, num){
var key = string(key)
- , obj = this.db.data[key]
+ , obj = this.lookup(key)
, num = +string(num);
if (isNaN(num)) return client.rangeError();
@@ -121,7 +117,7 @@ exports.getset = function(client, key, val){
(exports.decrby = function(client, key, num){
var key = string(key)
- , obj = this.db.data[key]
+ , obj = this.lookup(key)
, num = +string(num);
if (isNaN(num)) return client.rangeError();
@@ -144,7 +140,7 @@ exports.getset = function(client, key, val){
(exports.decr = function(client, key){
var key = string(key)
- , obj = this.db.data[key];
+ , obj = this.lookup(key);
if (!obj) {
this.db.data[key] = { type: 'string', val: -1 };
@@ -164,7 +160,7 @@ exports.getset = function(client, key, val){
exports.strlen = function(client, key){
var key = string(key)
- , val = this.data[key];
+ , val = this.lookup(key);
if (val) {
client.int(val.length);
@@ -181,22 +177,23 @@ exports.strlen = function(client, key){
(exports.append = function(client, key, str){
var key = string(key)
- , val = null != this.data[key]
- ? this.data[key]
- : new Buffer(0);
+ , obj = this.lookup(key);
- if ('string' != this.keyType(key)) return client.typeError();
+ if (obj && 'string' != obj.type) return client.typeError();
- if (Buffer.isBuffer(val)) {
- var offset = val.length
+ if (obj) {
+ if (!Buffer.isBuffer(obj.val)) obj.val = new Buffer(obj.val.toString());
+ var offset = obj.val.length
, len = offset + str.length
, buf = new Buffer(len);
- val.copy(buf);
+ obj.val.copy(buf);
str.copy(buf, offset);
- this.data[key] = buf;
+ obj.val = buf;
+ this.db.data[key] = obj;
client.int(len);
} else {
- client.typeError();
+ this.db.data[key] = { type: 'string', val: str };
+ client.int(str.length);
}
}).mutates = true;
@@ -205,16 +202,15 @@ exports.strlen = function(client, key){
*/
(exports.setrange = function(client, key, offset, str){
- var key = string(key)
- , val = this.data[key]
+ var obj = this.lookup(string(key))
, offset = +string(offset);
- if (null == val) {
+ if (!obj) {
// TODO: finish
- } else if ('string' == this.keyType(key)) {
- str.copy(val, offset);
- client.int(val.length);
+ } else if ('string' == obj.type) {
+ str.copy(obj.val, offset);
+ client.int(obj.val.length);
} else {
client.typeError();
}
@@ -225,12 +221,15 @@ exports.strlen = function(client, key){
*/
exports.getrange = function(client, key, from, to){
- var key = string(key)
- , val = this.data[key]
- , len = val.length
+ var obj = this.lookup(string(key))
, from = +string(from)
, to = +string(to);
+ if (!obj) return client.nil();
+ if ('string' != obj.type) return client.typeError();
+
+ var len = obj.val.length;
+
if (isNaN(from)) return client.typeError();
if (isNaN(to)) return client.typeError();
@@ -246,13 +245,7 @@ exports.getrange = function(client, key, from, to){
if (to < 0) to = 0;
if (from < 0) from = 0;
- if (null == val) {
- client.nil();
- } else if ('string' == this.keyType(key)) {
- client.send(val.slice(from, to + 1));
- } else {
- client.typeError();
- }
+ client.send(obj.val.slice(from, to + 1));
};
/**
@@ -278,15 +271,15 @@ exports.substr = exports.getrange;
*/
exports.mset = function(client, strs){
- var key
- , val
- , len = strs.length;
+ var len = strs.length
+ , key
+ , val;
+
for (var i = 0; i < len; ++i) {
key = string(strs[i++]);
- val = strs[i];
- this.data[key] = val;
- this.keyType(key, 'string');
+ this.db.data[key] = { type: 'string', val: strs[i] };
}
+
client.ok();
};
@@ -298,25 +291,21 @@ exports.mset.mutates = true;
*/
exports.msetnx = function(client, strs){
- var key
- , val
- , len = strs.length
- , keys = [];
+ var len = strs.length
+ , keys = []
+ , key
+ , val;
// Ensure none exist
for (var i = 0; i < len; ++i) {
keys[i] = key = string(strs[i++]);
- if (null != this.data[key]) {
- return client.bool(false);
- }
+ if (this.lookup(key)) return client.bool(false);
}
// Perform sets
for (var i = 0; i < len; i += 2) {
key = keys[i];
- val = strs[i];
- this.data[key] = val;
- this.keyType(key, 'string');
+ this.db.data[key] = { type: 'string', val: strs[i] }
}
client.bool(true);
View
5 lib/connection.js
@@ -78,7 +78,10 @@ Connection.prototype.list = function(arr){
*/
Connection.prototype.send = function(data){
- var stream = this.stream;
+ var stream = this.stream
+ , data = 'number' == typeof data
+ ? data.toString()
+ : data;
stream.write('$' + data.length + '\r\n');
stream.write(data);
stream.write('\r\n');
View
17 lib/database.js
@@ -73,6 +73,23 @@ Database.prototype.selectDB = function(index){
};
/**
+ * Lookup `key`, when volatile compare timestamps to
+ * expire the key.
+ *
+ * @param {String} key
+ * @return {Object}
+ */
+
+Database.prototype.lookup = function(key){
+ var obj = this.db.data[key];
+ if (obj && 'number' == typeof obj.expires && Date.now() > obj.expires) {
+ delete this.db.data[key];
+ return;
+ }
+ return obj;
+};
+
+/**
* Create a connection to the server.
*
* @return {net.Stream}
Please sign in to comment.
Something went wrong with that request. Please try again.