@silverwind/ioredis-mock
Version:
This library emulates ioredis by performing all operations in-memory.
140 lines (108 loc) • 4.78 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.customCommand = void 0;
exports.defineArgv = defineArgv;
exports.defineCommand = defineCommand;
exports.defineKeys = defineKeys;
exports.defineRedisObject = void 0;
var _fengari = _interopRequireDefault(require("fengari"));
var _fengariInterop = _interopRequireDefault(require("fengari-interop"));
var _command = _interopRequireDefault(require("../command"));
var _lua = require("../lua");
var commands = _interopRequireWildcard(require("."));
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const {
lua,
to_luastring: toLuaString
} = _fengari.default;
/**
* exported to test
*
* @param {*} vm - object with the lua state (L) and some utils
* ->
* @param fn - a function returning 0 for non-error and != 0 for error
*/
const defineRedisObject = vm => fn => {
vm.defineGlobalFunction(fn, 'call'); // define redis object with call method
// convert nil to false base on https://redis.io/commands/eval#conversion-between-lua-and-redis-data-types
vm.luaExecString(`
local redis = {}
function repair(val)
if val == nil then
return false
end
return val
end
redis.call = function(...)
return repair(call(false, ...))
end
redis.pcall = function(...)
return repair(call(true, ...))
end
return redis
`); // loads the redis object from the stack into the global table under key 'redis'
lua.lua_setglobal(vm.L, toLuaString('redis'));
};
exports.defineRedisObject = defineRedisObject;
const callToRedisCommand = vm => function callToRedisCommand2() {
const rawArgs = vm.extractArgs();
const returnError = rawArgs[0];
let result;
try {
const args = rawArgs.slice(1);
const name = args[0].toLowerCase();
const redisCmd = commands[name].bind(this);
result = redisCmd(...args.slice(1));
} catch (err) {
if (!returnError) {
throw err;
}
_fengariInterop.default.push(vm.L, ['error', err.toString()]);
return 1;
}
if (!!result || result === 0) {
if (Array.isArray(result)) {
// fix for one-based indices
result.unshift(null); // https://github.com/fengari-lua/fengari-interop/blob/1626687fb15452cdd82ee522955dd1f144ea7a68/src/js.js#L845
result[Symbol.for('__len')] = function () {
const arr = this;
return arr.length - 1;
};
}
_fengariInterop.default.push(vm.L, result);
return 1;
}
return 0;
}; // exported to test
function defineKeys(vm, numberOfKeys, commandArgs) {
const keys = commandArgs.slice(0, numberOfKeys);
vm.defineGlobalArray(keys, 'KEYS');
} // exported to test
function defineArgv(vm, numberOfKeys, commandArgs) {
const args = commandArgs.slice(numberOfKeys);
vm.defineGlobalArray(args, 'ARGV');
} // exported to test
const customCommand = (numberOfKeys, luaCode) => function customCommand2(...luaScriptArgs) {
const vm = (0, _lua.init)();
defineRedisObject(vm)(callToRedisCommand(vm).bind(this));
defineKeys.bind(this)(vm, numberOfKeys, luaScriptArgs);
defineArgv.bind(this)(vm, numberOfKeys, luaScriptArgs);
const topBeforeExecute = lua.lua_gettop(vm.L);
vm.luaExecString(luaCode);
const retVal = vm.popReturnValue(topBeforeExecute);
(0, _lua.dispose)(vm);
return retVal;
};
exports.customCommand = customCommand;
function defineCommand(command, {
numberOfKeys,
lua: luaCode
}) {
const cmd = (0, _command.default)(customCommand(numberOfKeys, luaCode).bind(this), command, this);
this[command] = cmd; // for multi/pipeline
this.customCommands[command] = cmd;
}