RedbackA high-level Redis library | |
| lib/advanced_structures/BloomFilter.js |
Module dependencies.
|
var Structure = require('../Structure'),
crc32 = require('../Utils').crc32;
|
A Simple BloomFilter. Bloomfilter is a probabilistic data structure used to
determine if an element is present in a set. There may be false positives,
but there cannot be false negatives.
Usage
redback.createBloomFilter(key [, size, hashes]);
Options
size - Size of the bloom filter , default is 100 bits.
hashes - Number of hashes to perform. default is 2.
Reference
http://redis.io/commands#string
http://en.wikipedia.org/wiki/Bloom_filter
http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html
Redis Structure
(namespace:)key = string(bits)
|
var BloomFilter = exports.BloomFilter = Structure.new();
|
Adds an element to the bloom filter.
|
BloomFilter.prototype.add = function(item, callback) {
var multi = this.client.multi(), crc;
for (var hash_index = 0; hash_index < this.num_hashes; hash_index++) {
crc = crc32(item, hash_index) % (this.size+1);
multi.setbit(this.key, crc, 1);
}
multi.exec(callback || function () {});
return this;
}
|
Checks if the element exists in the bloom filter.
This can return false positives( i.e An element does not exist but it returns true)
But this can never return false negatives. (i.e an element )
|
BloomFilter.prototype.exists = function(item, callback) {
var multi = this.client.multi(), crc;
callback = callback || function () {};
for (var hash_index = 0; hash_index < this.num_hashes; hash_index++) {
crc = crc32(item, hash_index) % (this.size+1);
multi.getbit(this.key, crc);
}
multi.exec(function(err, results) {
callback(err, results.indexOf(0) === -1);
});
return this;
}
|
Resets the Bloom filter.
|
BloomFilter.prototype.reset = function (callback) {
this.client.set(this.key, 0, callback || function () {});
return this;
}
|
| lib/advanced_structures/CappedList.js |
Module dependencies.
|
var List = require('../base_structures/List').List;
|
A Redis list with a fixed length. Each command that adds a value to the
list is followed by an LTRIM command.
Usage
redback.createCappedList(key [, max_length]);
Reference
http://redis.io/topics/data-types#lists
http://redis.io/commands/ltrim
Redis Structure
(namespace:)key = list(values)
|
var CappedList = exports.CappedList = List.prototype.extend();
|
Insert an element before the specified pivot.
|
CappedList.prototype.insertBefore = function (pivot, value, callback) {
callback = callback || function () {};
var multi = this.client.multi()
multi.linsert(this.key, 'BEFORE', pivot, value);
multi.ltrim(this.key, -1 * this.len, -1);
multi.exec(callback);
return this;
}
|
Insert an element after the specified pivot.
|
CappedList.prototype.insertAfter = function (pivot, value, callback) {
callback = callback || function () {};
var multi = this.client.multi()
multi.linsert(this.key, 'AFTER', pivot, value);
multi.ltrim(this.key, -1 * this.len, -1);
multi.exec(callback);
return this;
}
|
Add one or more elements to the start of the list.
|
CappedList.prototype.unshift = CappedList.prototype.lpush = function (values, callback) {
callback = callback || function () {};
var multi = this.client.multi();
if (Array.isArray(values)) {
var key = this.key;
values.reverse().forEach(function (value) {
multi.lpush(key, value);
});
} else {
multi.lpush(this.key, values);
}
multi.ltrim(this.key, -1 * this.len, -1);
multi.exec(callback);
return this;
}
|
Add one or more elements to the end of the list.
|
CappedList.prototype.push = CappedList.prototype.add = function (values, callback) {
callback = callback || function () {};
var multi = this.client.multi();
if (Array.isArray(values)) {
var key = this.key;
values.forEach(function (value) {
multi.rpush(key, value);
});
} else {
multi.rpush(this.key, values);
}
multi.ltrim(this.key, -1 * this.len, -1);
multi.exec(callback);
return this;
}
|
| lib/advanced_structures/DensitySet.js |
Module dependencies.
|
var SortedSet = require('../base_structures/SortedSet').SortedSet;
|
The DensitySet is similar to a SortedSet but the ability to explicitly
set an element's score has been removed. Instead, adding/removing
an element will increment/decrement its score, e.g.
DensitySet.add(['foo','foo','foo'], ..) //'foo' has a score of 3
Usage
redback.createDensitySet(key);
Reference
http://redis.io/topics/data-types#sorted-sets
Redis Structure
(namespace:)key = zset(count => element)
|
var DensitySet = exports.DensitySet = SortedSet.prototype.extend();
|
Add one or more elements to the set.
|
DensitySet.prototype.add = function (element, callback) {
callback = callback || function () {};
if (Array.isArray(element)) {
return this.addAll(element, callback);
}
this.client.zincrby(this.key, 1, element, callback);
return this;
}
|
Remove one or more elements from the set.
|
DensitySet.prototype.remove = function (element, callback) {
callback = callback || function () {};
if (Array.isArray(element)) {
return this.removeAll(element, callback);
}
var self = this;
this.client.zincrby(this.key, -1, element, function (err, removed) {
if (err) return callback(err, null);
self.client.zremrangebyscore(self.key, '-inf', 0, callback);
});
return this;
}
|
| lib/advanced_structures/KeyPair.js |
Module dependencies.
|
var Structure = require('../Structure');
|
The KeyPair is a structure where unique values are assigned an
ID (like a table with a primary auto-incrementing key and
a single unique column). Internally, the KeyPair uses two Redis
hashes to provide O(1) lookup by both ID and value.
Usage
redback.createKeyPair(key);
Reference
http://redis.io/topics/data-types#hashes
Redis Structure
(namespace:)key = hash(id => value)
(namespace:)key:ids = hash(value => id)
|
var KeyPair = exports.KeyPair = Structure.new();
|
Add a unique value to the KeyPair and return its id. If the value already
exists, the existing id is returned.
|
KeyPair.prototype.add = function (value, callback) {
if (Array.isArray(value)) {
return this.addAll(value, callback);
}
var self = this, hashed_value = this.hashValue(value);
this.client.hget(this.idkey, value, function (err, id) {
if (err) return callback(err, null);
if (null !== id) {
callback(null, id);
} else {
self.autoincrement(function (err, id) {
if (err) return callback(err, null);
var multi = self.client.multi();
multi.hsetnx(self.idkey, hashed_value, id);
multi.hsetnx(self.key, id, value);
multi.exec(function(err, response) {
if (err) return callback(err, null);
self.client.hget(self.idkey, hashed_value, function (err, real_id) {
if (err) return callback(err, null);
if (real_id == id) {
return callback(null, real_id);
} else {
self.client.hdel(self.key, id, function (err) {
if (err) {
callback(err, null);
} else {
callback(null, real_id);
}
});
}
});
});
});
}
});
return this;
}
|
Add multiple unique values to the KeyPair and return and
object containing {value: id, ...}.
param: Array values param: Function callback return: this api: public
|
KeyPair.prototype.addAll = function (values, callback) {
var self = this,
remaining = values.length,
ids = {},
failed = false;
values.forEach(function (value) {
self.add(value, function (err, id) {
if (failed) {
return;
} else if (err) {
failed = true;
return callback(err, null);
} else {
ids[value] = id;
if (!--remaining) callback(null, ids);
}
});
});
}
|
Lookup a unique value and get the associated id.
param: string value param: Function callback return: this api: public
|
KeyPair.prototype.get = function (value, callback) {
if (typeof value === 'function') {
callback = value;
this.client.hgetall(this.key, callback);
} else if (Array.isArray(value)) {
for (var i = 0, l = value.length; i < l; i++) {
value[i] = this.hashValue(value[i]);
}
this.client.hmget(this.idkey, value, callback)
} else {
this.client.hget(this.idkey, this.hashValue(value), callback);
}
return this;
}
|
Get the value associated with the id.
param: int | Array id(s) param: Function callback return: this api: public
|
KeyPair.prototype.getById = function (id, callback) {
if (Array.isArray(id))
this.client.hmget(this.key, id, callback);
else
this.client.hget(this.key, id, callback);
return this;
}
|
Get an array of ids.
param: Function callback return: this api: public
|
KeyPair.prototype.ids = function (callback) {
this.client.hkeys(this.key, callback);
return this;
}
|
Get an array of values.
param: string value param: Function callback return: this api: public
|
KeyPair.prototype.values = function (callback) {
this.client.hvals(this.key, callback);
return this;
}
|
Check whether a unique value already exists and has an associated id.
param: string value param: Function callback return: this api: public
|
KeyPair.prototype.exists = function (value, callback) {
this.client.hexists(this.idkey, this.hashValue(value), callback);
return this;
}
|
Checks whether an id exists.
param: string value param: Function callback return: this api: public
|
KeyPair.prototype.idExists = function (id, callback) {
this.client.hexists(this.key, id, callback);
return this;
}
|
Deletes a unique value and its associated id.
|
KeyPair.prototype.delete = function (value, callback) {
callback = callback || function () {};
var self = this, value = this.hashValue(value);
this.client.hget(this.idkey, value, function (err, id) {
if (err || value == null) return callback(err);
self._delete(id, value, callback);
});
return this;
}
|
Deletes an id and its associated unique value.
|
KeyPair.prototype.deleteById = function (id, callback) {
callback = callback || function () {};
var self = this;
this.client.hget(this.key, id, function (err, value) {
if (err || value == null) return callback(err);
self._delete(id, self.hashValue(value), callback);
});
return this;
}
|
Get the number of unique values.
param: Function callback return: this api: public
|
KeyPair.prototype.length = function (callback) {
this.client.hlen(this.key, callback);
return this;
}
|
Override this method if you need to hash the unique value
in the second internal hash (i.e. if values are large).
|
KeyPair.prototype.hashValue = function (value) {
return value;
}
|
| lib/advanced_structures/Lock.js |
Module dependencies.
|
var crypto = require('crypto');
var Structure = require('../Structure');
|
A distributed lock.
|
var Lock = exports.Lock = Structure.new();
|
Acquire a temporary lock on some key.
param: string key The unique key of the lock param: number ttl The amount of time (in seconds) before the lock expires param: Function callback Invoked when the process completes param: Error callback.err An error that occurred, if any param: string callback.token The token that was acquired if successful. If the lock was not acquired then this will be undefined api: public
|
Lock.prototype.acquire = function(key, ttl, callback) {
var client = this.client;
_createToken(function(err, token) {
if (err) {
return callback(err);
}
client.setnx(key, token, function(err, wasSet) {
if (err) {
return callback(err);
} else if (!wasSet) {
_ensureTtl(client, key, ttl);
return callback();
}
client.expire(key, ttl, function(err) {
if (err) {
return callback(err);
}
return callback(null, token);
});
});
});
};
|
Release a lock that was acquired with the provided key and token.
param: string key The key for the lock to release param: string token The token that was generated for the lock acquisition param: Function callback Invoked when the function completes param: Error callback.err An error that occurred, if any param: boolean callback.hadLock Determines whether or not we owned the lock at the time that we released it api: public
|
Lock.prototype.release = function(key, token, callback) {
var client = this.client;
client.get(key, function(err, lockedToken) {
if (err) {
return callback(err);
} else if (lockedToken !== token) {
return callback(null, false);
}
client.del(key, function(err) {
if (err) {
return callback(err);
}
return callback(null, true);
});
});
};
|
| lib/advanced_structures/Queue.js |
Module dependencies.
|
var Structure = require('../Structure'),
List = require('../base_structures/List').List;
|
A simple FIFO/LIFO queue.
Usage
redback.createQueue(key [, is_fifo]);
Reference
http://redis.io/topics/data-types#lists
http://en.wikipedia.org/wiki/Queue(datastructure)
Redis Structure
(namespace:)key = list(values)
|
var Queue = exports.Queue = Structure.new();
|
Add one or more elements to the queue.
|
Queue.prototype.enqueue = Queue.prototype.add = function (values, callback) {
this.list.unshift(values, callback);
return this;
}
|
Remove the next element from the queue.
|
Queue.prototype.dequeue = Queue.prototype.next = function (wait, callback) {
this.list[this.fifo ? 'pop' : 'shift'](wait, callback);
return this;
}
|
| lib/advanced_structures/RateLimit.js |
Module dependencies.
|
var Structure = require('../Structure');
|
See https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da
Count the number of times a subject performs an action over an interval
in the immediate past - this can be used to rate limit the subject if
the count goes over a certain threshold. For example, you could track
how many times an IP (the subject) has viewed a page (the action) over
a certain time frame and limit them accordingly.
Usage
redback.createRateLimit(action [, options]);
Options
bucket_interval - default is 5 seconds
bucket_span - default is 10 minutes
subject_expiry - default is 20 minutes
Reference
https://gist.github.com/chriso/54dd46b03155fcf555adccea822193da
http://redis.io/topics/data-types#hash
Redis Structure
(namespace:)action:<subject1> = hash(bucket => count)
(namespace:)action:<subject2> = hash(bucket => count)
(namespace:)action:<subjectN> = hash(bucket => count)
|
var RateLimit = exports.RateLimit = Structure.new();
|
Increment the count for the specified subject.
|
RateLimit.prototype.add = function (subject, callback) {
if (Array.isArray(subject)) {
return this.addAll(subject, callback);
}
var bucket = this.getBucket(), multi = this.client.multi();
subject = this.key + ':' + subject;
multi.hincrby(subject, bucket, 1)
multi.hdel(subject, (bucket + 1) % this.bucket_count)
.hdel(subject, (bucket + 2) % this.bucket_count)
multi.expire(subject, this.subject_expiry);
multi.exec(function (err) {
if (!callback) return;
if (err) return callback(err);
callback(null);
});
return this;
}
|
Count the number of times the subject has performed an action
in the last interval seconds.
param: string subject param: int interval param: Function callback return: this api: public
|
RateLimit.prototype.count = function (subject, interval, callback) {
var bucket = this.getBucket(),
multi = this.client.multi(),
count = Math.floor(interval / this.bucket_interval);
subject = this.key + ':' + subject;
multi.hget(subject, bucket);
while (count--) {
multi.hget(subject, (--bucket + this.bucket_count) % this.bucket_count);
}
multi.exec(function (err, counts) {
if (err) return callback(err, null);
for (var count = 0, i = 0, l = counts.length; i < l; i++) {
if (counts[i]) {
count += parseInt(counts[i], 10);
}
}
callback(null, count);
});
return this;
}
|
An alias for ratelimit.add(subject).count(subject, interval);
param: string subject param: int interval param: Function callback return: this api: public
|
RateLimit.prototype.addCount = function (subject, interval, callback) {
var bucket = this.getBucket(),
multi = this.client.multi(),
count = Math.floor(interval / this.bucket_interval);
subject = this.key + ':' + subject;
multi.hincrby(subject, bucket, 1)
multi.hdel(subject, (bucket + 1) % this.bucket_count)
.hdel(subject, (bucket + 2) % this.bucket_count)
multi.expire(subject, this.subject_expiry);
multi.hget(subject, bucket);
while (count--) {
multi.hget(subject, (--bucket + this.bucket_count) % this.bucket_count);
}
multi.exec(function (err, counts) {
if (err) return callback(err, null);
for (var count = 0, i = 4, l = counts.length; i < l; i++) {
if (counts[i]) {
count += parseInt(counts[i], 10);
}
}
callback(null, count);
});
return this;
}
|
| lib/advanced_structures/SocialGraph.js |
Module dependencies.
|
var Structure = require('../Structure');
|
Build a social graph similar to Twitter's. User ID can be a string or
integer, as long as they're unique.
Usage
redback.createSocialGraph(id [, prefix]);
Reference
http://redis.io/topics/data-types#sets
Redis Structure
(namespace:)(prefix:)id:following = set(ids)
(namespace:)(prefix:)id:followers = set(ids)
|
var SocialGraph = exports.SocialGraph = Structure.new();
|
Follow one or more users.
|
SocialGraph.prototype.follow = function (users, callback) {
var self = this,
users = this.getKeys(arguments, 'id'),
multi = this.client.multi();
if (typeof users[users.length-1] === 'function') {
callback = users.pop();
} else {
callback = function () {};
}
users.forEach(function (user) {
multi.sadd(self.key_prefix + user + ':followers', self.id);
multi.sadd(self.following, user);
});
multi.exec(callback);
return this;
}
|
Unfollow one or more users.
|
SocialGraph.prototype.unfollow = function (users, callback) {
var self = this,
users = this.getKeys(arguments, 'id'),
multi = this.client.multi();
if (typeof users[users.length-1] === 'function') {
callback = users.pop();
} else {
callback = function () {};
}
users.forEach(function (user) {
multi.srem(self.key_prefix + user + ':followers', self.id);
multi.srem(self.following, user);
});
multi.exec(callback);
return this;
}
|
Gets the users whom the current users follows as an array.
param: Function callback return: this api: public
|
SocialGraph.prototype.getFollowing = function (callback) {
this.client.smembers(this.following, callback);
return this;
}
|
Gets an array of users who follow the current user.
param: Function callback return: this api: public
|
SocialGraph.prototype.getFollowers = function (callback) {
this.client.smembers(this.followers, callback);
return this;
}
|
Count how many users the current user follows.
param: Function callback return: this api: public
|
SocialGraph.prototype.countFollowing = function (callback) {
this.client.scard(this.following, callback);
return this;
}
|
Count how many users follow the current user.
param: Function callback return: this api: public
|
SocialGraph.prototype.countFollowers = function (callback) {
this.client.scard(this.followers, callback);
return this;
}
|
Checks whether the current user follows the specified user.
|
SocialGraph.prototype.isFollowing = function (user, callback) {
user = this.getKey(user, 'id');
this.client.sismember(this.following, user, callback);
return this;
}
|
Checks whether the specified user follows the current user.
|
SocialGraph.prototype.hasFollower = function (user, callback) {
user = this.getKey(user, 'id');
this.client.sismember(this.followers, user, callback);
return this;
}
|
Gets an array of common followers for one or more users.
|
SocialGraph.prototype.getCommonFollowers = function (users, callback) {
var users = this.getSocialKeys(arguments, 'followers');
users.unshift(this.followers);
this.client.sinter.apply(this.client, users);
return this;
}
|
Gets an array of users who are followed by all of the specified user(s).
|
SocialGraph.prototype.getCommonFollowing = function (users, callback) {
var users = this.getSocialKeys(arguments, 'following');
users.unshift(this.following);
this.client.sinter.apply(this.client, users);
return this;
}
|
Gets an array of users who follow the current user but do not follow any
of the other specified users.
|
SocialGraph.prototype.getDifferentFollowers = function (users, callback) {
var users = this.getSocialKeys(arguments, 'followers');
users.unshift(this.followers);
this.client.sdiff.apply(this.client, users);
return this;
}
|
Gets an array of users who are followed by the current user but not any of
the other specified users.
|
SocialGraph.prototype.getDifferentFollowing = function (users, callback) {
var users = this.getSocialKeys(arguments, 'following');
users.unshift(this.following);
this.client.sdiff.apply(this.client, users);
return this;
}
|
| lib/base_structures/Bitfield.js |
Module dependencies.
|
var Structure = require('../Structure');
|
Wrap the Redis bit commands.
Usage
redback.createBitfield(key);
Reference
http://redis.io/commands#string
Redis Structure
(namespace:)key = string
|
var Bitfield = exports.Bitfield = Structure.new();
|
Get a single bit
|
Bitfield.prototype.get = function (bit, callback) {
callback = callback || function () {};
this.client.getbit(this.key, bit, callback);
return this;
}
|
Set a single bit. The callback receives the previous value.
|
Bitfield.prototype.set = function (bit, value, callback) {
callback = callback || function () {};
this.client.setbit(this.key, bit, value ? 1 : 0, callback);
return this;
}
|
| lib/base_structures/Hash.js |
Module dependencies.
|
var Structure = require('../Structure');
|
A wrapper for the Redis hash type.
Usage
redback.createHash(key);
Reference
http://redis.io/topics/data-types#hashes
Redis Structure
(namespace:)key = hash(key => value)
|
var Hash = exports.Hash = Structure.new();
|
Get an array of hash keys.
param: Function callback return: this api: public
|
Hash.prototype.keys = function (callback) {
this.client.hkeys(this.key, callback);
return this;
}
|
Get an array of hash values.
param: Function callback return: this api: public
|
Hash.prototype.values = function (callback) {
this.client.hvals(this.key, callback);
return this;
}
|
Get the number of hash keys.
param: Function callback return: this api: public
|
Hash.prototype.length = function (callback) {
this.client.hlen(this.key, callback);
return this;
}
|
Delete a hash key.
|
Hash.prototype.delete = Hash.prototype.del = function (hash_key, callback) {
callback = callback || function () {};
this.client.hdel(this.key, hash_key, callback);
return this;
}
|
Checks whether a hash key exists.
param: string hash_key param: Function callback return: this api: public
|
Hash.prototype.exists = function (hash_key, callback) {
this.client.hexists(this.key, hash_key, callback);
return this;
}
|
Sets one or more key/value pairs.
To set one key/value pair:
hash.set('foo', 'bar', callback);
To set multiple:
hash.set({key1:'value1', key2:'value2}, callback);
param: string | Object hash_key param: string value (optional) param: Function callback (optional) return: this api: public
|
Hash.prototype.set = function (hash_key, value, callback) {
if (typeof hash_key === 'object') {
callback = value || function () {};
this.client.hmset(this.key, hash_key, callback);
} else {
callback = callback || function () {};
this.client.hset(this.key, hash_key, value, callback);
}
return this;
}
|
Sets a key/value pair if the key doesn't already exist.
param: string hash_key param: string value param: Function callback return: this api: public
|
Hash.prototype.add = function (hash_key, value, callback) {
callback = callback || function () {};
this.client.hsetnx(this.key, hash_key, value, callback);
return this;
}
|
Gets one or more key/value pairs.
To get all key/value pairs in the hash:
hash.get('foo', callback);
To get certain key/value pairs:
hash.get(['foo','bar'], callback);
hash.get('foo', callback);
|
Hash.prototype.get = function (hash_key, callback) {
if (typeof hash_key === 'function') {
callback = hash_key;
this.client.hgetall(this.key, callback);
} else if (Array.isArray(hash_key)) {
this.client.hmget(this.key, hash_key, callback)
} else {
this.client.hget(this.key, hash_key, callback);
}
return this;
}
|
Increment the specified hash value.
|
Hash.prototype.increment =
Hash.prototype.incrBy = function (hash_key, amount, callback) {
callback = callback || function () {};
if (typeof amount === 'function') {
callback = amount;
amount = 1;
}
this.client.hincrby(this.key, hash_key, amount, callback);
return this;
}
|
Decrement the specified hash value.
|
Hash.prototype.decrement =
Hash.prototype.decrBy = function (hash_key, amount, callback) {
callback = callback || function () {};
if (typeof amount === 'function') {
callback = amount;
amount = 1;
}
this.client.hincrby(this.key, hash_key, -1 * amount, callback);
return this;
}
|
| lib/base_structures/List.js |
Module dependencies.
|
var Structure = require('../Structure');
|
A wrapper for the Redis list type.
Usage
redback.createList(key);
Reference
http://redis.io/topics/data-types#lists
Redis Structure
(namespace:)key = list(values)
|
var List = exports.List = Structure.new();
|
Get the list as an array.
param: Function callback return: this api: public
|
List.prototype.values = function (callback) {
this.client.lrange(this.key, 0, -1, callback);
return this;
}
|
Get a range of list elements.
|
List.prototype.range = function (start, end, callback) {
if (typeof end === 'function') {
callback = end;
end = -1;
}
this.client.lrange(this.key, start, end, callback);
return this;
}
|
Get one or more elements starting at the specified index.
|
List.prototype.get = function (index, count, callback) {
if (typeof count === 'function') {
callback = count;
this.client.lindex(this.key, index, callback);
} else {
this.client.lrange(this.key, index, index + count - 1, callback);
}
return this;
}
|
Cap the length of the list.
|
List.prototype.cap = function (length, keep_earliest, callback) {
callback = callback || function () {};
var start = 0, end = -1;
if (typeof keep_earliest === 'function') {
start = -1 * length;
callback = keep_earliest;
} else {
end = length - 1;
}
this.client.ltrim(this.key, start, end, callback);
return this;
}
|
Remove one or more list elements matching the value.
|
List.prototype.remove = function (value, count, callback) {
callback = callback || function () {};
if (typeof count === 'function') {
callback = count;
count = 1;
}
this.client.lrem(this.key, count, value, callback);
return this;
}
|
Trim a list to the specified bounds.
|
List.prototype.trim = function (start, end, callback) {
callback = callback || function () {};
this.client.ltrim(this.key, start, end, callback);
return this;
}
|
Insert an element before the specified pivot.
|
List.prototype.insertBefore = function (pivot, value, callback) {
callback = callback || function () {};
this.client.linsert(this.key, 'BEFORE', pivot, value, callback);
return this;
}
|
Insert an element after the specified pivot.
|
List.prototype.insertAfter = function (pivot, value, callback) {
callback = callback || function () {};
this.client.linsert(this.key, 'AFTER', pivot, value, callback);
return this;
}
|
Set the element at the specified index.
|
List.prototype.set = function (index, value, callback) {
callback = callback || function () {};
this.client.lset(this.key, index, value, callback);
return this;
}
|
Get the number of elements in the list.
param: Function callback return: this api: public
|
List.prototype.length = function (callback) {
this.client.llen(this.key, callback);
return this;
}
|
Get and remove the last element in the list. The first param can be used
to block the process and wait until list elements are available. If the list
is empty in both examples below, the first example will return null , while
the second will wait for up to 3 seconds. If a list element becomes available
during the 3 seconds it will be returned, otherwise null will be returned.
Example
list.shift(callback);
Blocking Example
list.shift(3, callback)
|
List.prototype.shift = function (wait, callback) {
if (typeof wait === 'function') {
callback = wait;
this.client.lpop(this.key, callback);
} else {
this.client.blpop(this.key, wait, callback);
}
return this;
}
|
Get and remove the last element in the list. The first param can be used
to block the process and wait until list elements are available. If the list
is empty in both examples below, the first example will return null , while
the second will wait for up to 3 seconds. If a list element becomes available
during the 3 seconds it will be returned, otherwise null will be returned.
Example
list.pop(callback);
Blocking Example
list.pop(3, callback)
|
List.prototype.pop = function (wait, callback) {
if (typeof wait === 'function') {
callback = wait;
this.client.rpop(this.key, callback);
} else {
this.client.brpop(this.key, wait, callback);
}
return this;
}
|
Add one or more elements to the start of the list.
|
List.prototype.unshift = List.prototype.lpush = function (values, callback) {
callback = callback || function () {};
if (Array.isArray(values)) {
var multi = this.client.multi(), key = this.key;
values.reverse().forEach(function (value) {
multi.lpush(key, value);
});
multi.exec(callback);
} else {
this.client.lpush(this.key, values, callback);
}
return this;
}
|
Add one or more elements to the end of the list.
|
List.prototype.push = List.prototype.add = function (values, callback) {
callback = callback || function () {};
if (Array.isArray(values)) {
var multi = this.client.multi(), key = this.key;
values.forEach(function (value) {
multi.rpush(key, value);
});
multi.exec(callback);
} else {
this.client.rpush(this.key, values, callback);
}
return this;
}
|
Remove the last element of the list and add it to the start
of another list.
param: String | List list param: bool wait (optional) - seconds to block while waiting param: Function callback (optional) return: this api: public
|
List.prototype.popShift = function (list, wait, callback) {
callback = callback || function () {};
list = this.getKey(list);
if (typeof wait === 'function') {
callback = wait;
this.client.rpoplpush(this.key, list, callback);
} else {
this.client.brpoplpush(this.key, list, wait, callback);
}
return this;
}
|
| lib/base_structures/Set.js |
Module dependencies.
|
var Structure = require('../Structure');
|
A wrapper for the Redis set type.
Usage
redback.createSet(key);
Reference
http://redis.io/topics/data-types#sets
Redis Structure
(namespace:)key = set(elements)
|
var Set = exports.Set = Structure.new();
|
Add one or more elements to the set.
|
Set.prototype.add = function (element, callback) {
callback = callback || function () {};
if (Array.isArray(element)) {
return this.addAll(element, callback);
}
this.client.sadd(this.key, element, callback);
return this;
}
|
Remove one or more elements from the set.
|
Set.prototype.remove = function (element, callback) {
callback = callback || function () {};
if (Array.isArray(element)) {
return this.removeAll(element, callback);
}
this.client.srem(this.key, element, callback);
return this;
}
|
Get an array of elements in the set.
param: Function callback return: this api: public
|
Set.prototype.elements = Set.prototype.members = function (callback) {
this.client.smembers(this.key, callback);
return this;
}
|
Move an element to another set.
|
Set.prototype.move = function (dest, element, callback) {
callback = callback || function () {};
this.client.smove(this.key, this.getKey(dest), element, callback);
return this;
}
|
Check whether an element exists in the set.
param: string element param: Function callback return: this api: public
|
Set.prototype.exists = Set.prototype.contains = function (element, callback) {
this.client.sismember(this.key, element, callback);
return this;
}
|
Get the length (cardinality) of the set.
param: Function callback return: this api: public
|
Set.prototype.length = Set.prototype.cardinality = function (callback) {
this.client.scard(this.key, callback);
return this;
}
|
Get a random element from the set and optionally remove it.
|
Set.prototype.random = function (remove, callback) {
if (typeof remove === 'function') {
callback = remove;
this.client.srandmember(this.key, callback);
} else {
this.client.spop(this.key, callback);
}
return this;
}
|
Get the intersection of one or more sets.
|
Set.prototype.inter = function (sets, callback) {
sets = this.getKeys(arguments);
sets.unshift(this.key);
this.client.sinter.apply(this.client, sets);
return this;
}
|
Get the intersection of one or more sets and store it another
set (dest).
|
Set.prototype.interStore = function (dest, sets, callback) {
sets = this.getKeys(arguments);
dest = sets.shift();
sets.unshift(dest, this.key);
this.client.sinterstore.apply(this.client, sets);
return this;
}
|
Get the union of one or more sets.
|
Set.prototype.union = function (sets, callback) {
sets = this.getKeys(arguments);
sets.unshift(this.key);
this.client.sunion.apply(this.client, sets);
return this;
}
|
Get the union of one or more sets and store it another
set (dest).
|
Set.prototype.unionStore = function (dest, sets, callback) {
sets = this.getKeys(arguments);
dest = sets.shift();
sets.unshift(dest, this.key);
this.client.sunionstore.apply(this.client, sets);
return this;
}
|
Get the difference of one or more sets.
|
Set.prototype.diff = function (sets, callback) {
sets = this.getKeys(arguments);
sets.unshift(this.key);
this.client.sdiff.apply(this.client, sets);
return this;
}
|
Get the difference of one or more sets and store it another
set (dest).
|
Set.prototype.diffStore = function (dest, sets, callback) {
sets = this.getKeys(arguments);
dest = sets.shift();
sets.unshift(dest, this.key);
this.client.sdiffstore.apply(this.client, sets);
return this;
}
|
| lib/base_structures/SortedSet.js |
Module dependencies.
|
var Structure = require('../Structure');
|
A wrapper for the Redis sorted set (zset) type. Each element has a
score which is used to rank and order all elements in the set. Elements
are ranked from lowest score to highest (the lowest score has
a rank of 0)
Usage
redback.createSortedSet(key);
Reference
http://redis.io/topics/data-types#sorted-sets
Redis Structure
(namespace:)key = zset(score => element)
|
var SortedSet = exports.SortedSet = Structure.new();
|
Add one or more elements to the set.
To add a single element and score:
set.add(12, 'foo', callback);
To add multiple elements/scores:
set.add({foo:12, bar:3}, callback);
param: int score (optional) param: string | Object element(s) param: Function callback (optional) return: this api: public
|
SortedSet.prototype.add = function (score, element, callback) {
callback = callback || function () {};
if (typeof score === 'object') {
callback = element;
element = score;
return this.addAll(element, callback);
}
this.client.zadd(this.key, score, element, callback);
return this;
}
|
Remove one or more elements from the set.
|
SortedSet.prototype.remove = function (element, callback) {
callback = callback || function () {};
if (Array.isArray(element)) {
return this.removeAll(element, callback);
}
this.client.zrem(this.key, element, callback);
return this;
}
|
Get the number of elements in the set.
param: Function callback return: this api: public
|
SortedSet.prototype.length = function (callback) {
this.client.zcard(this.key, callback);
return this;
}
|
Check whether an element exists in the set.
param: string element param: Function callback return: this api: public
|
SortedSet.prototype.exists =
SortedSet.prototype.contains = function (element, callback) {
this.client.zscore(this.key, element, function (err, score) {
callback(err, score != null);
});
return this;
}
|
Get the rank of the specified element.
param: string element param: Function callback return: this api: public
|
SortedSet.prototype.rank = function (element, callback) {
this.client.zrank(this.key, element, callback)
return this;
}
|
Get the score of the specified element.
param: string element param: Function callback return: this api: public
|
SortedSet.prototype.score = function (element, callback) {
this.client.zscore(this.key, element, callback)
return this;
}
|
Increment the specified element's score.
|
SortedSet.prototype.increment =
SortedSet.prototype.incrBy = function (element, amount, callback) {
callback = callback || function () {};
if (typeof amount === 'function') {
callback = amount;
amount = 1;
}
this.client.zincrby(this.key, amount, element, callback);
return this;
}
|
Decrement the specified element's score.
|
SortedSet.prototype.decrement =
SortedSet.prototype.decrBy = function (element, amount, callback) {
callback = callback || function () {};
if (typeof amount === 'function') {
callback = amount;
amount = 1;
}
this.client.zincrby(this.key, -1 * amount, element, callback);
return this;
}
|
Get all elements in the set as an object {element: score, ...} .
If without_scores is true then just an array of elements is returned.
|
SortedSet.prototype.get = function (without_scores, callback) {
if (typeof without_scores === 'function') {
callback = without_scores;
this.client.zrange(this.key, 0, -1, 'WITHSCORES', this.parseScores(callback));
} else {
this.client.zrange(this.key, 0, -1, callback);
}
return this;
}
|
Get elements with scores between the specified range. Elements are returned
as an object {element: score, ..} and ordered from highest score to lowest.
Note that the start and end range is inclusive and can be an integer or
the constants redback.INF to represent infinity, or redback.NINF to
represent negative infinity. start must be <= end .
param: int start param: int end param: int count (optional) - the maximum number of elements to return param: int offset (optional) - if using count, start at this offset param: Function callback return: this api: public
|
SortedSet.prototype.getScores = function (start, end, count, offset, callback) {
if (null === start) start = '-inf';
if (null === end) end = '+inf';
if (typeof count === 'function') {
callback = count;
this.client.zrangebyscore(this.key, start, end,
'WITHSCORES', this.parseScores(callback));
return this;
} else if (typeof offset === 'function') {
callback = offset;
offset = 0;
}
this.client.zrangebyscore(this.key, start, end, 'WITHSCORES',
'LIMIT', offset, count, this.parseScores(callback));
return this;
}
|
The same as getScores() but elements are ordered from lowest score to
highest.
Note that end must be <= start .
param: int start param: int end param: int count (optional) - the maximum number of elements to return param: int offset (optional) - if using count, start at this offset param: Function callback return: this api: public
|
SortedSet.prototype.getScoresReverse = function (start, end, count, offset, callback) {
if (null === start) start = '+inf';
if (null === end) end = '-inf';
if (typeof count === 'function') {
callback = count;
this.client.zrevrangebyscore(this.key, start, end,
'WITHSCORES', this.parseScores(callback));
return this;
} else if (typeof offset === 'function') {
callback = offset;
offset = 0;
}
this.client.zrevrangebyscore(this.key, start, end, 'WITHSCORES',
'LIMIT', offset, count, this.parseScores(callback));
return this;
}
|
Remove elements with scores between the specified range (inclusive).
|
SortedSet.prototype.removeScores = function (start, end, callback) {
callback = callback || function () {};
if (null === start) start = '-inf';
if (null === end) end = '+inf';
this.client.zremrangebyscore(this.key, start, end, callback);
return this;
}
|
Count the number of elements with scores between the specified
range (inclusive).
param: int start param: int end param: Function callback return: this api: public
|
SortedSet.prototype.countScores = function (start, end, callback) {
if (null === start) start = '-inf';
if (null === end) end = '+inf';
this.client.zcount(this.key, start, end, callback);
return this;
}
|
Get elements with ranks between the specified range (inclusive).
To get the first 3 elements in the set (with the highest scores):
set.getRanks(0, 2, callback);
To get the last 3 elements in the set (lowest scores):
set.getRanks(-3, -1, callback);
param: int start param: int end param: Function callback return: this api: public
|
SortedSet.prototype.getRanks = function (start, end, callback) {
if (null === start) start = 0;
if (null === end) end = -1;
this.client.zrange(this.key, start, end,
'WITHSCORES', this.parseScores(callback));
return this;
}
|
The same as getRanks() but elements are ordered from lowest score
to the highest.
Note that start and end have been deliberately switched for consistency.
getScoresReverse(arg1, arg2, ..) expects arg1 >= arg2 and so does this
method.
param: int end param: int start param: Function callback return: this api: public
|
SortedSet.prototype.getRanksReverse = function (end, start, callback) {
if (null === start) start = -1;
if (null === end) end = 0;
this.client.zrevrange(this.key, start, end,
'WITHSCORES', this.parseScores(callback));
return this;
}
|
Remove elements with ranks between the specified range (inclusive).
|
SortedSet.prototype.removeRanks = function (start, end, callback) {
callback = callback || function () {};
if (null === start) start = -1;
if (null === end) end = 0;
this.client.zremrangebyrank(this.key, start, end, callback);
return this;
}
|
Get count elements with the highest scores.
param: int count param: Function callback return: this api: public
|
SortedSet.prototype.highestScores = function (count, callback) {
this.getRanks(-1 * count, -1, callback);
return this;
}
|
Get count elements with the lowest scores.
param: int count param: Function callback return: this api: public
|
SortedSet.prototype.lowestScores = function (count, callback) {
this.getRanks(0, count - 1, callback);
return this;
}
|
Get the intersection of one or more sets. For more information on weights,
aggregate functions, etc. see: http://redis.io/commands/zinterstore
param: int dest param: string | Set | Array set(s) param: int | Array weights (optional) param: string aggregate (optional) - either SUM, MIN or MAX param: Function callback return: this api: public
|
SortedSet.prototype.inter = function (dest, sets, weights, aggregate, callback) {
var args = [], self = this;
args.push(this.getKey(dest));
if (typeof weights === 'function') {
callback = weights;
weights = aggregate = false;
} else if (typeof aggregate === 'function') {
callback = aggregate;
aggregate = false;
}
if (Array.isArray(sets)) {
args.push(sets.length);
sets.forEach(function (set) {
args.push(self.getKey(set));
});
} else {
args.push(1, this.getKey(sets));
}
if (weights) {
args.push('WEIGHTS');
if (Array.isArray(weights)) {
weights.forEach(function (weight) {
args.push(weight);
});
} else {
args.push(weights);
}
}
if (aggregate) {
args.push('AGGREGATE', aggregate);
}
args.push(callback);
this.client.zinterstore.apply(this.client, args);
return this;
}
|
Get the union of one or more sets. For more information on weights,
aggregate functions, etc. see: http://redis.io/commands/zunionstore
param: int dest param: string | Set | Array set(s) param: int | Array weights (optional) param: string aggregate (optional) - either SUM, MIN or MAX param: Function callback return: this api: public
|
SortedSet.prototype.union = function (dest, sets, weights, aggregate, callback) {
var args = [], self = this;
args.push(this.getKey(dest));
if (typeof weights === 'function') {
callback = weights;
weights = aggregate = false;
} else if (typeof aggregate === 'function') {
callback = aggregate;
aggregate = false;
}
if (Array.isArray(sets)) {
args.push(sets.length);
sets.forEach(function (set) {
args.push(self.getKey(set));
});
} else {
args.push(1, this.getKey(sets));
}
if (weights) {
args.push('WEIGHTS');
if (Array.isArray(weights)) {
weights.forEach(function (weight) {
args.push(weight);
});
} else {
args.push(weights);
}
}
if (aggregate) {
args.push('AGGREGATE', aggregate);
}
args.push(callback);
this.client.zunionstore.apply(this.client, args);
return this;
}
|