forked from makeomatic/redis-filtered-sort
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
101 lines (85 loc) · 2.59 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const fs = require('fs');
const path = require('path');
const camelCase = require('lodash/camelCase');
const snakeCase = require('lodash/snakeCase');
const lua = fs.readFileSync(path.join(__dirname, 'sorted-filtered-list.lua'));
const fsortBust = fs.readFileSync(path.join(__dirname, 'filtered-list-bust.lua'));
const aggregateScript = fs.readFileSync(path.join(__dirname, 'groupped-list.lua'));
// cached vars
const regexp = /[\^\$\(\)\%\.\[\]\*\+\-\?]/g;
const keys = Object.keys;
const stringify = JSON.stringify;
const BLACK_LIST_PROPS = ['eq', 'ne'];
exports.FSORT_TEMP_KEYSET = 'fsort_temp_keys';
const luaWrapper = (script) => `
---
local function getIndexTempKeys(index)
return index .. "::${exports.FSORT_TEMP_KEYSET}";
end
---
${script.toString('utf-8')}
`;
/**
* Attached .sortedFilteredList function to ioredis instance
* @param {ioredis} redis
*/
const fsortScript = luaWrapper(lua);
const fsortBustScript = luaWrapper(fsortBust);
exports.attach = function attachToRedis(redis, _name, useSnakeCase = false) {
const name = _name || 'sortedFilteredList';
const bustName = (useSnakeCase ? snakeCase : camelCase)(`${name}Bust`);
const aggregateName = (useSnakeCase ? snakeCase : camelCase)(`${name}Aggregate`);
redis.defineCommand(name, { numberOfKeys: 2, lua: fsortScript });
redis.defineCommand(bustName, { numberOfKeys: 1, lua: fsortBustScript });
redis.defineCommand(aggregateName, { numberOfKeys: 2, lua: aggregateScript });
};
/**
* Performs escape on a filter clause
* ^ $ ( ) % . [ ] * + - ? are prefixed with %
*
* @param {String} filter
* @return {String}
*/
function escape(filter) {
return filter.replace(regexp, '%$&');
};
exports.escape = escape;
/**
* Walks over object and escapes string, does not touch #multi.fields
* @param {Object} obj
* @return {Object}
*/
function iterateOverObject(obj) {
const props = keys(obj);
const output = {};
props.forEach(function iterateOverProps(prop) {
const val = obj[prop];
const type = typeof val;
if (type === 'string' && BLACK_LIST_PROPS.indexOf(prop) === -1) {
output[prop] = escape(val);
} else if (type === 'object') {
if (prop !== '#multi') {
output[prop] = iterateOverObject(val);
} else {
output[prop] = val;
val.match = escape(val.match);
}
} else {
output[prop] = val;
}
});
return output;
}
/**
* Goes over filter and escapes each string
* @param {Object} obj
* @return {String}
*/
exports.filter = function filter(obj) {
return stringify(iterateOverObject(obj));
};
/**
* Exports raw script
* @type {Buffer}
*/
exports.script = lua;