From 1fc5e5d0d3d71cdad94abd9c0f2bedb71cf8fabc Mon Sep 17 00:00:00 2001 From: yariplus Date: Sun, 16 Oct 2016 14:48:29 -0400 Subject: [PATCH 1/8] getSortedSetRevRangeByLex --- src/database/redis/sorted.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index e02366c08f..e1fcb0cc8e 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -299,9 +299,25 @@ module.exports = function (redisClient, module) { if (max !== '+') { max = '(' + max; } - redisClient.zrangebylex([key, min, max, 'LIMIT', start, count], callback); + + sortedSetRangeByLex('zrangebylex', key, min, max, start, count, callback) + }; + + module.getSortedSetRevRangeByLex = function (key, max, min, start, count, callback) { + if (min !== '-') { + min = '[' + min; + } + if (max !== '+') { + max = '(' + max; + } + + sortedSetRangeByLex('zrevrangebylex', key, max, min, start, count, callback) }; + function sortedSetRangeByLex(method, key, min, max, start, count, callback) { + redisClient[method]([key, min, max, 'LIMIT', start, count], callback); + } + module.sortedSetIntersectCard = function (keys, callback) { if (!Array.isArray(keys) || !keys.length) { return callback(null, 0); From ef20757f3e6b8a08a2b218346b4a2bf5c47b80e6 Mon Sep 17 00:00:00 2001 From: yariplus Date: Sun, 16 Oct 2016 18:45:54 -0400 Subject: [PATCH 2/8] zremrangebylex, zlexcount --- src/database/redis/sorted.js | 50 ++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 17 deletions(-) diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index e1fcb0cc8e..8cf807d3a4 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -293,29 +293,45 @@ module.exports = function (redisClient, module) { }; module.getSortedSetRangeByLex = function (key, min, max, start, count, callback) { - if (min !== '-') { - min = '[' + min; - } - if (max !== '+') { - max = '(' + max; - } - - sortedSetRangeByLex('zrangebylex', key, min, max, start, count, callback) + sortedSetLex('zrangebylex', false, key, min, max, start, count, callback) }; module.getSortedSetRevRangeByLex = function (key, max, min, start, count, callback) { - if (min !== '-') { - min = '[' + min; - } - if (max !== '+') { - max = '(' + max; - } + sortedSetLex('zrevrangebylex', true, key, max, min, start, count, callback) + }; + + module.sortedSetRemoveRangeByLex = function (key, min, max) { + sortedSetLex('zremrangebylex', false, key, min, max, callback) + }; - sortedSetRangeByLex('zrevrangebylex', key, max, min, start, count, callback) + module.sortedSetLexCount = function (key, min, max) { + sortedSetLex('zlexcount', false, key, min, max, callback) }; - function sortedSetRangeByLex(method, key, min, max, start, count, callback) { - redisClient[method]([key, min, max, 'LIMIT', start, count], callback); + function sortedSetLex(method, reverse, key, min, max, start, count, callback) { + if (!callback) callback === start; + + if (reverse) { + if (min !== '+') { + min = '(' + min; + } + if (max !== '-') { + max = '[' + max; + } + } else { + if (min !== '-') { + min = '[' + min; + } + if (max !== '+') { + max = '(' + max; + } + } + + if (count) { + redisClient[method]([key, min, max, 'LIMIT', start, count], callback); + } else { + redisClient[method]([key, min, max], callback); + } } module.sortedSetIntersectCard = function (keys, callback) { From 437d2744ccf21e092311b920f20cdb9a7261ca24 Mon Sep 17 00:00:00 2001 From: yariplus Date: Sun, 16 Oct 2016 20:37:48 -0400 Subject: [PATCH 3/8] addl lex commands for mongo --- src/database/mongo/sorted.js | 38 ++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 1a36f6eeb0..fa772666b3 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -579,7 +579,22 @@ module.exports = function (db, module) { }; module.getSortedSetRangeByLex = function (key, min, max, start, count, callback) { - var query = {_key: key}; + sortedSetLex(key, min, max, 1, start, count, callback); + }; + + module.getSortedSetRevRangeByLex = function (key, min, max, start, count, callback) { + sortedSetLex(key, min, max, -1, start, count, callback); + }; + + module.sortedSetLexCount = function (key, min, max, callback) { + sortedSetLex(key, min, max, 1, 0, 0, function (err, data) { + callback(err, data ? data.length : null); + }); + }; + + function sortedSetLex(method, sort, key, min, max, start, count, callback) { + var query = {_key: key, value: {}}; + if (min !== '-') { query.value = {$gte: min}; } @@ -587,8 +602,9 @@ module.exports = function (db, module) { query.value = query.value || {}; query.value.$lte = max; } + db.collection('objects').find(query, {_id: 0, value: 1}) - .sort({value: 1}) + .sort({value: sort}) .skip(start) .limit(count === -1 ? 0 : count) .toArray(function (err, data) { @@ -600,6 +616,24 @@ module.exports = function (db, module) { }); callback(err, data); }); + } + + module.sortedSetRemoveRangeByLex = function (key, min, max, callback) { + callback = callback || helpers.noop; + + var query = {_key: key}; + + if (min !== '-') { + query.value = {$gte: min}; + } + if (max !== '+') { + query.value = query.value || {}; + query.value.$lte = max; + } + + db.collection('objects').remove(query, function (err) { + callback(err); + }); }; module.processSortedSet = function (setKey, process, batch, callback) { From 1bb44e2429e1ac17259d8172aab7fa75bf6a930f Mon Sep 17 00:00:00 2001 From: yariplus Date: Sun, 16 Oct 2016 21:29:45 -0400 Subject: [PATCH 4/8] Allow lex min and max to be inclusive or exclusive. --- src/database/mongo/sorted.js | 24 ++++++++++++++++++++---- src/database/redis/sorted.js | 26 ++++++++++++++------------ 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index fa772666b3..d9183521c6 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -596,11 +596,19 @@ module.exports = function (db, module) { var query = {_key: key, value: {}}; if (min !== '-') { - query.value = {$gte: min}; + if (min.match('(')) { + query.value = {$gt: parseInt(min, 10)}; + } else { + query.value = {$gte: parseInt(min, 10)}; + } } if (max !== '+') { query.value = query.value || {}; - query.value.$lte = max; + if (max.match('(')) { + query.value = {$lt: parseInt(max, 10)}; + } else { + query.value = {$lte: parseInt(max, 10)}; + } } db.collection('objects').find(query, {_id: 0, value: 1}) @@ -624,11 +632,19 @@ module.exports = function (db, module) { var query = {_key: key}; if (min !== '-') { - query.value = {$gte: min}; + if (min.match('(')) { + query.value = {$gt: parseInt(min, 10)}; + } else { + query.value = {$gte: parseInt(min, 10)}; + } } if (max !== '+') { query.value = query.value || {}; - query.value.$lte = max; + if (max.match('(')) { + query.value = {$lt: parseInt(max, 10)}; + } else { + query.value = {$lte: parseInt(max, 10)}; + } } db.collection('objects').remove(query, function (err) { diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 8cf807d3a4..f8be7b3754 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -311,20 +311,22 @@ module.exports = function (redisClient, module) { function sortedSetLex(method, reverse, key, min, max, start, count, callback) { if (!callback) callback === start; + var minmin, maxmax; if (reverse) { - if (min !== '+') { - min = '(' + min; - } - if (max !== '-') { - max = '[' + max; - } + minmin = '+'; + maxmax = '-'; } else { - if (min !== '-') { - min = '[' + min; - } - if (max !== '+') { - max = '(' + max; - } + minmin = '-'; + maxmax = '+'; + } + + if (min !== minmin) { + min = '' + min; + if (!min.match(/[\[\(]/)) min = '[' + min; + } + if (max !== maxmax) { + max = '' + max; + if (!max.match(/[\[\(]/)) max = '[' + max; } if (count) { From be3b35dea34cf39b533e5c8338509838ea518675 Mon Sep 17 00:00:00 2001 From: yariplus Date: Sun, 16 Oct 2016 21:53:02 -0400 Subject: [PATCH 5/8] fix callbacks and regex --- src/database/mongo/sorted.js | 32 ++++++++++++++++++++------------ src/database/redis/sorted.js | 21 ++++++++++----------- 2 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index d9183521c6..8fc21cb50a 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -596,18 +596,22 @@ module.exports = function (db, module) { var query = {_key: key, value: {}}; if (min !== '-') { - if (min.match('(')) { - query.value = {$gt: parseInt(min, 10)}; + if (min.match(/^\(/)) { + query.value = {$gt: min.slice(1)}; + } else if (min.match(/^\[/)) { + query.value = {$gte: min.slice(1)}; } else { - query.value = {$gte: parseInt(min, 10)}; + query.value = {$gte: min}; } } if (max !== '+') { query.value = query.value || {}; - if (max.match('(')) { - query.value = {$lt: parseInt(max, 10)}; + if (max.match(/^\(/)) { + query.value.$lt = max.slice(1); + } else if (max.match(/^\[/)) { + query.value.$lte = max.slice(1); } else { - query.value = {$lte: parseInt(max, 10)}; + query.value.$lte = max; } } @@ -632,18 +636,22 @@ module.exports = function (db, module) { var query = {_key: key}; if (min !== '-') { - if (min.match('(')) { - query.value = {$gt: parseInt(min, 10)}; + if (min.match(/^\(/)) { + query.value = {$gt: min.slice(1)}; + } else if (min.match(/^\[/)) { + query.value = {$gte: min.slice(1)}; } else { - query.value = {$gte: parseInt(min, 10)}; + query.value = {$gte: min}; } } if (max !== '+') { query.value = query.value || {}; - if (max.match('(')) { - query.value = {$lt: parseInt(max, 10)}; + if (max.match(/^\(/)) { + query.value.$lt = max.slice(1); + } else if (max.match(/^\[/)) { + query.value.$lte = max.slice(1); } else { - query.value = {$lte: parseInt(max, 10)}; + query.value.$lte = max; } } diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index f8be7b3754..0077ab13ec 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -293,23 +293,24 @@ module.exports = function (redisClient, module) { }; module.getSortedSetRangeByLex = function (key, min, max, start, count, callback) { - sortedSetLex('zrangebylex', false, key, min, max, start, count, callback) + sortedSetLex('zrangebylex', false, key, min, max, start, count, callback); }; module.getSortedSetRevRangeByLex = function (key, max, min, start, count, callback) { - sortedSetLex('zrevrangebylex', true, key, max, min, start, count, callback) + sortedSetLex('zrevrangebylex', true, key, max, min, start, count, callback); }; - module.sortedSetRemoveRangeByLex = function (key, min, max) { - sortedSetLex('zremrangebylex', false, key, min, max, callback) + module.sortedSetRemoveRangeByLex = function (key, min, max, callback) { + callback = callback || helpers.noop; + sortedSetLex('zremrangebylex', false, key, min, max, callback); }; - module.sortedSetLexCount = function (key, min, max) { - sortedSetLex('zlexcount', false, key, min, max, callback) + module.sortedSetLexCount = function (key, min, max, callback) { + sortedSetLex('zlexcount', false, key, min, max, callback); }; function sortedSetLex(method, reverse, key, min, max, start, count, callback) { - if (!callback) callback === start; + callback = callback || start; var minmin, maxmax; if (reverse) { @@ -321,12 +322,10 @@ module.exports = function (redisClient, module) { } if (min !== minmin) { - min = '' + min; - if (!min.match(/[\[\(]/)) min = '[' + min; + if (!min.match(/^[\[\(]/)) min = '[' + min; } if (max !== maxmax) { - max = '' + max; - if (!max.match(/[\[\(]/)) max = '[' + max; + if (!max.match(/^[\[\(]/)) max = '[' + max; } if (count) { From e8823eab3323211d13eb1f02886dad923387bb71 Mon Sep 17 00:00:00 2001 From: yariplus Date: Mon, 17 Oct 2016 14:22:50 -0400 Subject: [PATCH 6/8] add db lexical tests --- test/database/sorted.js | 174 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) diff --git a/test/database/sorted.js b/test/database/sorted.js index 29ed4cf95e..af1870ae83 100644 --- a/test/database/sorted.js +++ b/test/database/sorted.js @@ -17,6 +17,9 @@ describe('Sorted Set methods', function () { }, function (next) { db.sortedSetAdd('sortedSetTest3', [2, 4], ['value2', 'value4'], next); + }, + function (next) { + db.sortedSetAdd('sortedSetLex', [0, 0, 0, 0], ['a', 'b', 'c', 'd'], done); } ], done); }); @@ -694,6 +697,177 @@ describe('Sorted Set methods', function () { }); }); + describe('getSortedSetRangeByLex', function () { + it('should return an array of all values', function (done) { + db.getSortedSetRangeByLex('sortedSetLex', '-', '+', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['a', 'b', 'c', 'd']); + done(); + }); + }); + + it('should return an array with an inclusive range by default', function (done) { + db.getSortedSetRangeByLex('sortedSetLex', 'a', 'd', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['a', 'b', 'c', 'd']); + done(); + }); + }); + + it('should return an array with an inclusive range', function (done) { + db.getSortedSetRangeByLex('sortedSetLex', '[a', '[d', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['a', 'b', 'c', 'd']); + done(); + }); + }); + + it('should return an array with an exclusive range', function (done) { + db.getSortedSetRangeByLex('sortedSetLex', '(a', '(d', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['b', 'c']); + done(); + }); + }); + + it('should return an array limited to the first two values', function (done) { + db.getSortedSetRangeByLex('sortedSetLex', '-', '+', 0, 2, function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['a', 'b']); + done(); + }); + }); + }); + + describe('getSortedSetRevRangeByLex', function () { + it('should return an array of all values reversed', function (done) { + db.getSortedSetRevRangeByLex('sortedSetLex', '+', '-', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['d', 'c', 'b', 'a']); + done(); + }); + }); + + it('should return an array with an inclusive range by default reversed', function (done) { + db.getSortedSetRevRangeByLex('sortedSetLex', 'd', 'a', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['d', 'c', 'b', 'a']); + done(); + }); + }); + + it('should return an array with an inclusive range reversed', function (done) { + db.getSortedSetRevRangeByLex('sortedSetLex', '[d', '[a', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['d', 'c', 'b', 'a']); + done(); + }); + }); + + it('should return an array with an exclusive range reversed', function (done) { + db.getSortedSetRevRangeByLex('sortedSetLex', '(d', '(a', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['c', 'b']); + done(); + }); + }); + + it('should return an array limited to the first two values reversed', function (done) { + db.getSortedSetRevRangeByLex('sortedSetLex', '+', '-', 0, 2, function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['d', 'c']); + done(); + }); + }); + }); + + describe('sortedSetLexCount', function () { + it('should return the count of all values', function (done) { + db.sortedSetLexCount('sortedSetLex', '-', '+', function (err, data) { + assert.ifError(err); + assert.strictEqual(data, 4); + done(); + }); + }); + + it('should return the count with an inclusive range by default', function (done) { + db.sortedSetLexCount('sortedSetLex', 'a', 'd', function (err, data) { + assert.ifError(err); + assert.strictEqual(data, 4); + done(); + }); + }); + + it('should return the count with an inclusive range', function (done) { + db.sortedSetLexCount('sortedSetLex', '[a', '[d', function (err, data) { + assert.ifError(err); + assert.strictEqual(data, 4); + done(); + }); + }); + + it('should return the count with an exclusive range', function (done) { + db.sortedSetLexCount('sortedSetLex', '(a', '(d', function (err, data) { + assert.ifError(err); + assert.strictEqual(data, 2); + done(); + }); + }); + }); + + describe('sortedSetRemoveRangeByLex', function () { + before(function (done) { + db.sortedSetAdd('sortedSetLex2', [0, 0, 0, 0, 0, 0, 0], ['a', 'b', 'c', 'd', 'e', 'f', 'g'], done); + }); + + it('should remove an inclusive range by default', function (done) { + db.sortedSetRemoveRangeByLex('sortedSetLex2', 'a', 'b', function (err) { + assert.ifError(err); + assert.equal(arguments.length, 1); + db.getSortedSetRangeByLex('sortedSetLex2', '-', '+', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['c', 'd', 'e', 'f', 'g']); + done(); + }); + }); + }); + + it('should remove an inclusive range', function (done) { + db.sortedSetRemoveRangeByLex('sortedSetLex2', '[c', '[d', function (err) { + assert.ifError(err); + assert.equal(arguments.length, 1); + db.getSortedSetRangeByLex('sortedSetLex2', '-', '+', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['e', 'f', 'g']); + done(); + }); + }); + }); + + it('should remove an exclusive range', function (done) { + db.sortedSetRemoveRangeByLex('sortedSetLex2', '(e', '(g', function (err) { + assert.ifError(err); + assert.equal(arguments.length, 1); + db.getSortedSetRangeByLex('sortedSetLex2', '-', '+', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, ['e', 'g']); + done(); + }); + }); + }); + + it('should remove all values', function (done) { + db.sortedSetRemoveRangeByLex('sortedSetLex2', '-', '+', function (err) { + assert.ifError(err); + assert.equal(arguments.length, 1); + db.getSortedSetRangeByLex('sortedSetLex2', '-', '+', function (err, data) { + assert.ifError(err); + assert.deepEqual(data, []); + done(); + }); + }); + }); + }); after(function (done) { db.flushdb(done); From 472dd007d8ff638a76cd1677e4520b66b255ca15 Mon Sep 17 00:00:00 2001 From: yariplus Date: Mon, 17 Oct 2016 14:38:11 -0400 Subject: [PATCH 7/8] fix mongo lex callback --- src/database/mongo/sorted.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 8fc21cb50a..1ac6fb6f85 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -592,7 +592,13 @@ module.exports = function (db, module) { }); }; - function sortedSetLex(method, sort, key, min, max, start, count, callback) { + function sortedSetLex(key, min, max, sort, start, count, callback) { + if (!callback) { + callback = start; + start = 0; + count = 0; + } + var query = {_key: key, value: {}}; if (min !== '-') { @@ -697,7 +703,6 @@ module.exports = function (db, module) { ); }; - module.sortedSetIntersectCard = function (keys, callback) { if (!Array.isArray(keys) || !keys.length) { return callback(null, 0); From af2122bdb9ad50d5b7e09fbfbadde92446fd7972 Mon Sep 17 00:00:00 2001 From: yariplus Date: Mon, 17 Oct 2016 16:35:33 -0400 Subject: [PATCH 8/8] fix lex tests maybe --- src/database/mongo/sorted.js | 4 ++-- src/database/redis/sorted.js | 4 +++- test/database/sorted.js | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/database/mongo/sorted.js b/src/database/mongo/sorted.js index 1ac6fb6f85..c1c25eaa75 100644 --- a/src/database/mongo/sorted.js +++ b/src/database/mongo/sorted.js @@ -582,7 +582,7 @@ module.exports = function (db, module) { sortedSetLex(key, min, max, 1, start, count, callback); }; - module.getSortedSetRevRangeByLex = function (key, min, max, start, count, callback) { + module.getSortedSetRevRangeByLex = function (key, max, min, start, count, callback) { sortedSetLex(key, min, max, -1, start, count, callback); }; @@ -599,7 +599,7 @@ module.exports = function (db, module) { count = 0; } - var query = {_key: key, value: {}}; + var query = {_key: key}; if (min !== '-') { if (min.match(/^\(/)) { diff --git a/src/database/redis/sorted.js b/src/database/redis/sorted.js index 0077ab13ec..68d2695d1d 100644 --- a/src/database/redis/sorted.js +++ b/src/database/redis/sorted.js @@ -302,7 +302,9 @@ module.exports = function (redisClient, module) { module.sortedSetRemoveRangeByLex = function (key, min, max, callback) { callback = callback || helpers.noop; - sortedSetLex('zremrangebylex', false, key, min, max, callback); + sortedSetLex('zremrangebylex', false, key, min, max, function (err) { + callback(err); + }); }; module.sortedSetLexCount = function (key, min, max, callback) { diff --git a/test/database/sorted.js b/test/database/sorted.js index af1870ae83..bd944a3825 100644 --- a/test/database/sorted.js +++ b/test/database/sorted.js @@ -19,7 +19,7 @@ describe('Sorted Set methods', function () { db.sortedSetAdd('sortedSetTest3', [2, 4], ['value2', 'value4'], next); }, function (next) { - db.sortedSetAdd('sortedSetLex', [0, 0, 0, 0], ['a', 'b', 'c', 'd'], done); + db.sortedSetAdd('sortedSetLex', [0, 0, 0, 0], ['a', 'b', 'c', 'd'], next); } ], done); });