@hotmeshio/hotmesh
Version:
Permanent-Memory Workflows & AI Agents
191 lines (190 loc) • 7.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.IORedisStoreService = void 0;
const key_1 = require("../../../../modules/key");
const enums_1 = require("../../../../modules/enums");
const _base_1 = require("./_base");
class IORedisStoreService extends _base_1.RedisStoreBase {
constructor(storeClient) {
super(storeClient);
this.commands = {
get: 'get',
set: 'set',
setnx: 'setnx',
del: 'del',
expire: 'expire',
hset: 'hset',
hscan: 'hscan',
hsetnx: 'hsetnx',
hincrby: 'hincrby',
hdel: 'hdel',
hget: 'hget',
hmget: 'hmget',
hgetall: 'hgetall',
hincrbyfloat: 'hincrbyfloat',
zrank: 'zrank',
zrange: 'zrange',
zrangebyscore_withscores: 'zrangebyscore',
zrangebyscore: 'zrangebyscore',
zrem: 'zrem',
zadd: 'zadd',
lmove: 'lmove',
lpop: 'lpop',
lrange: 'lrange',
rename: 'rename',
rpush: 'rpush',
scan: 'scan',
xack: 'xack',
xdel: 'xdel',
};
}
/**
* When in cluster mode, the transact wrapper only
* sends commands to the same node/shard if they share a key.
* All other commands are sent simultaneouslyusing Promise.all
* and are then collated. this is effectiely a wrapper for
* `multi` but is closer to `pipeline` in terms of usage when
* promises are used.
*/
transact() {
const my = this;
if (enums_1.HMSH_IS_CLUSTER) {
const commands = [];
const addCommand = (command, args) => {
commands.push({ command, args });
return multiInstance;
};
const multiInstance = {
sendCommand(command) {
return my.storeClient.sendCommand(command);
},
async exec() {
if (commands.length === 0)
return [];
const sameKey = commands.every((cmd) => {
return cmd.args[0] === commands[0].args[0];
});
if (sameKey) {
const multi = my.storeClient.multi();
commands.forEach((cmd) => multi[cmd.command](...cmd.args));
const results = await multi.exec();
return results.map((item) => item);
}
else {
return Promise.all(commands.map((cmd) => my.storeClient[cmd.command](...cmd.args)));
}
},
xadd(key, id, fields, message) {
return addCommand('xadd', [key, id, fields, message]);
},
xack(key, group, id) {
return addCommand('xack', [key, group, id]);
},
xdel(key, id) {
return addCommand('xdel', [key, id]);
},
xlen(key) {
return addCommand('xlen', [key]);
},
xpending(key, group, start, end, count, consumer) {
return addCommand('xpending', [
key,
group,
start,
end,
count,
consumer,
]);
},
xclaim(key, group, consumer, minIdleTime, id, ...args) {
return addCommand('xclaim', [
key,
group,
consumer,
minIdleTime,
id,
...args,
]);
},
del(key) {
return addCommand('del', [key]);
},
expire: function (key, seconds) {
return addCommand('expire', [key, seconds]);
},
hdel(key, itemId) {
return addCommand('hdel', [key, itemId]);
},
hget(key, itemId) {
return addCommand('hget', [key, itemId]);
},
hgetall(key) {
return addCommand('hgetall', [key]);
},
hincrbyfloat(key, itemId, value) {
return addCommand('hincrbyfloat', [key, itemId, value]);
},
hmget(key, itemIds) {
return addCommand('hmget', [key, itemIds]);
},
hset(key, values) {
return addCommand('hset', [key, values]);
},
lrange(key, start, end) {
return addCommand('lrange', [key, start, end]);
},
rpush(key, value) {
return addCommand('rpush', [key, value]);
},
zadd(...args) {
return addCommand('zadd', args);
},
xgroup(command, key, groupName, id, mkStream) {
return addCommand('xgroup', [command, key, groupName, id, mkStream]);
},
};
return multiInstance;
}
return this.storeClient.multi();
}
async exec(...args) {
try {
const response = await this.storeClient.call.apply(this.storeClient, args);
if (typeof response === 'string') {
return response;
}
else if (Array.isArray(response)) {
if (Array.isArray(response[0])) {
return response;
}
return response;
}
return response;
}
catch (error) {
// Connection closed during test cleanup - log and return empty response
if (error?.message?.includes('Connection is closed')) {
return [];
}
// Re-throw unexpected errors
throw error;
}
}
async setnxex(key, value, expireSeconds) {
const status = await this.storeClient[this.commands.set](key, value, 'NX', 'EX', expireSeconds.toString());
return this.isSuccessful(status);
}
hGetAllResult(result) {
//ioredis response signature is [null, {}] or [null, null]
return result[1];
}
async addTaskQueues(keys) {
const multi = this.storeClient.multi();
const zsetKey = this.mintKey(key_1.KeyType.WORK_ITEMS, { appId: this.appId });
for (const key of keys) {
multi.zadd(zsetKey, 'NX', Date.now(), key);
}
await multi.exec();
}
}
exports.IORedisStoreService = IORedisStoreService;