New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@type-cacheable/redis-adapter

Package Overview
Dependencies
Maintainers
1
Versions
41
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@type-cacheable/redis-adapter - npm Package Compare versions

Comparing version 5.2.0 to 6.0.0

2

dist/index.d.ts

@@ -35,2 +35,2 @@ import { RedisClient, Callback } from 'redis';

}
export declare const useAdapter: (client: RedisClient) => void;
export declare const useAdapter: (client: RedisClient, asFallback?: boolean | undefined) => void;

@@ -17,223 +17,204 @@ "use strict";

const SCALAR_KEY = '';
// When values are returned from redis, numbers can be converted to strings, so we need to store them
// in a way that we can differentiate them from numbers that were intentionally stored as strings
const NUMBER_IDENTIFIER = 'n';
const BOOL_IDENTIFIER = 'b';
let RedisAdapter = /** @class */ (() => {
class RedisAdapter {
constructor(redisClient) {
class RedisAdapter {
constructor(redisClient) {
this.clientReady = false;
this.isPingingClient = false;
this.redisClient = redisClient;
this.clientReady = this.redisClient.ping();
this.redisClient.on('ready', () => {
this.clientReady = true;
});
this.redisClient.on('error', () => {
this.clientReady = false;
this.isPingingClient = false;
this.redisClient = redisClient;
this.clientReady = this.redisClient.ping();
this.redisClient.on('ready', () => {
});
this.checkIfReady();
}
/**
* checkIfReady will return the last received ready status of the client.
* If the client isn't ready, it will ping the redis client to check if it's ready
* yet. This isn't a perfect solution, because we're not waiting for the response (so as to
* not add latency to the underlying method calls). I believe it's a reasonable trade-off to
* have a potential cache miss rather than add latency to all decorated method calls.
*/
checkIfReady() {
if (!this.clientReady && !this.isPingingClient) {
this.isPingingClient = true;
this.redisClient.ping(() => {
this.clientReady = true;
this.isPingingClient = false;
});
this.redisClient.on('error', () => {
this.clientReady = false;
});
this.checkIfReady();
}
/**
* checkIfReady will return the last received ready status of the client.
* If the client isn't ready, it will ping the redis client to check if it's ready
* yet. This isn't a perfect solution, because we're not waiting for the response (so as to
* not add latency to the underlying method calls). I believe it's a reasonable trade-off to
* have a potential cache miss rather than add latency to all decorated method calls.
*/
checkIfReady() {
if (!this.clientReady && !this.isPingingClient) {
this.isPingingClient = true;
this.redisClient.ping(() => {
this.clientReady = true;
this.isPingingClient = false;
return this.clientReady;
}
// Redis doesn't have a standard TTL, it's at a per-key basis
getClientTTL() {
return 0;
}
get(cacheKey) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
if (cacheKey.includes(':')) {
this.redisClient.hgetall(cacheKey, RedisAdapter.responseCallback(resolve, reject));
}
else {
this.redisClient.get(cacheKey, RedisAdapter.responseCallback(resolve, reject));
}
}).then((result) => {
const usableResult = core_1.parseIfRequired(result);
if (usableResult &&
typeof usableResult === 'object' &&
Object.keys(usableResult).every((key) => Number.isInteger(Number(key)))) {
return Object.values(usableResult);
}
return usableResult;
});
}
return this.clientReady;
}
// Redis doesn't have a standard TTL, it's at a per-key basis
getClientTTL() {
return 0;
}
get(cacheKey) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
if (cacheKey.includes(':')) {
this.redisClient.hgetall(cacheKey, RedisAdapter.responseCallback(resolve, reject));
throw new Error('Redis client is not accepting connections.');
});
}
/**
* set - Sets a key equal to a value in a Redis cache
*
* @param cacheKey The key to store the value under
* @param value The value to store
* @param ttl Time to Live (how long, in seconds, the value should be cached)
*
* @returns {Promise}
*/
set(cacheKey, value, ttl) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
if (cacheKey.includes(':')) {
if (typeof value === 'object') {
const args = RedisAdapter.buildSetArgumentsFromObject(value);
this.redisClient.hmset(cacheKey, args, (err, result) => {
if (!err) {
// hmset doesn't add expiration by default, so we have to implement that here if ttl is given
if (ttl) {
this.redisClient.expire(cacheKey, ttl, RedisAdapter.responseCallback(resolve, reject));
return;
}
}
RedisAdapter.responseCallback(resolve, reject)(err, result);
});
}
else {
this.redisClient.get(cacheKey, RedisAdapter.responseCallback(resolve, reject));
this.redisClient.hmset(cacheKey, RedisAdapter.buildSetArgumentsFromObject({ [SCALAR_KEY]: JSON.stringify(value) }), (err, result) => {
if (!err) {
// hset doesn't add expiration by default, so we have to implement that here if ttl is given
if (ttl) {
this.redisClient.expire(cacheKey, ttl, RedisAdapter.responseCallback(resolve, reject));
return;
}
}
RedisAdapter.responseCallback(resolve, reject)(err, result);
});
}
}).then((result) => {
const usableResult = core_1.parseIfRequired(result);
if (usableResult &&
typeof usableResult === 'object' &&
Object.keys(usableResult).every((key) => Number.isInteger(Number(key)))) {
return Object.keys(usableResult).map((key) => core_1.parseIfRequired(usableResult[key]));
}
else {
const usableValue = JSON.stringify(value);
if (ttl) {
this.redisClient.set(cacheKey, usableValue, 'EX', ttl, RedisAdapter.responseCallback(resolve, reject));
}
return usableResult;
});
}
throw new Error('Redis client is not accepting connections.');
});
}
/**
* set - Sets a key equal to a value in a Redis cache
*
* @param cacheKey The key to store the value under
* @param value The value to store
* @param ttl Time to Live (how long, in seconds, the value should be cached)
*
* @returns {Promise}
*/
set(cacheKey, value, ttl) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
if (cacheKey.includes(':')) {
if (typeof value === 'object') {
const args = RedisAdapter.buildSetArgumentsFromObject(value);
this.redisClient.hmset(cacheKey, args, (err, result) => {
if (!err) {
// hmset doesn't add expiration by default, so we have to implement that here if ttl is given
if (ttl) {
this.redisClient.expire(cacheKey, ttl, RedisAdapter.responseCallback(resolve, reject));
return;
}
}
RedisAdapter.responseCallback(resolve, reject)(err, result);
});
}
else {
this.redisClient.hmset(cacheKey, RedisAdapter.buildSetArgumentsFromObject({ [SCALAR_KEY]: value }), (err, result) => {
if (!err) {
// hset doesn't add expiration by default, so we have to implement that here if ttl is given
if (ttl) {
this.redisClient.expire(cacheKey, ttl, RedisAdapter.responseCallback(resolve, reject));
return;
}
}
RedisAdapter.responseCallback(resolve, reject)(err, result);
});
}
}
else {
const usableValue = typeof value === 'string' ? value : JSON.stringify(value);
if (ttl) {
this.redisClient.set(cacheKey, usableValue, 'EX', ttl, RedisAdapter.responseCallback(resolve, reject));
}
else {
this.redisClient.set(cacheKey, usableValue, RedisAdapter.responseCallback(resolve, reject));
}
this.redisClient.set(cacheKey, usableValue, RedisAdapter.responseCallback(resolve, reject));
}
});
}
throw new Error('Redis client is not accepting connections.');
});
}
del(keyOrKeys) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
this.redisClient.del(keyOrKeys, RedisAdapter.responseCallback(resolve, reject));
});
}
throw new Error('Redis client is not accepting connections.');
});
}
keys(pattern) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
this.redisClient.scan('0', 'MATCH', `*${pattern}*`, 'COUNT', '1000', RedisAdapter.responseScanCommandCallback(resolve, reject));
});
}
throw new Error('Redis client is not accepting connections.');
});
}
}
});
}
throw new Error('Redis client is not accepting connections.');
});
}
RedisAdapter.buildSetArgumentsFromObject = (objectValue) => Object.keys(objectValue).reduce((accum, objectKey) => {
let value = objectValue[objectKey];
switch (typeof value) {
case 'object': {
value = JSON.stringify(value);
break;
del(keyOrKeys) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
if (isReady) {
return new Promise((resolve, reject) => {
this.redisClient.del(keyOrKeys, RedisAdapter.responseCallback(resolve, reject));
});
}
case 'number': {
value = `${value}${NUMBER_IDENTIFIER}`;
break;
}
case 'boolean': {
value = `${value}${BOOL_IDENTIFIER}`;
break;
}
default:
break;
}
accum.push(objectKey, value);
return accum;
}, []);
RedisAdapter.transformRedisResponse = (response) => {
if (response && typeof response === 'object') {
return Object.entries(response).reduce((accum, curr) => {
const [key, value] = curr;
switch (typeof value) {
case 'string': {
if (value.endsWith(NUMBER_IDENTIFIER) &&
parseFloat(value).toString() === value.substr(0, value.length - 1)) {
accum[key] = parseFloat(value);
break;
}
else if (value.endsWith(BOOL_IDENTIFIER) &&
(value === 'false' + BOOL_IDENTIFIER || value === 'true' + BOOL_IDENTIFIER)) {
accum[key] = value === 'true' + BOOL_IDENTIFIER;
break;
}
throw new Error('Redis client is not accepting connections.');
});
}
keys(pattern) {
return __awaiter(this, void 0, void 0, function* () {
const isReady = this.checkIfReady();
let keys = [];
let cursor = '0';
if (isReady) {
while (cursor) {
const result = (yield new Promise((resolve, reject) => {
this.redisClient.scan(cursor, 'MATCH', pattern, 'COUNT', '1000', RedisAdapter.responseScanCommandCallback(resolve, reject));
}));
if (result) {
// array exists at index 1 from SCAN command, cursor is at 0
cursor = cursor !== result[0] ? result[0] : null;
keys = [...keys, ...result[1]];
}
default: {
accum[key] = value;
break;
else {
cursor = null;
}
}
return accum;
}, {});
}
return keys;
}
throw new Error('Redis client is not accepting connections.');
});
}
}
exports.RedisAdapter = RedisAdapter;
RedisAdapter.buildSetArgumentsFromObject = (objectValue) => Object.keys(objectValue).reduce((accum, objectKey) => {
accum.push(objectKey, JSON.stringify(objectValue[objectKey]));
return accum;
}, []);
RedisAdapter.transformRedisResponse = (response) => {
if (response && typeof response === 'object') {
return Object.entries(response).reduce((accum, curr) => {
const [key, value] = curr;
accum[key] = JSON.parse(value);
return accum;
}, {});
}
try {
return JSON.parse(response);
}
catch (_a) {
return response;
};
RedisAdapter.responseCallback = (resolve, reject) => (err, response) => {
if (err) {
reject(err);
}
else {
if (response &&
typeof response === 'object' &&
Object.keys(response).length === 1 &&
response[SCALAR_KEY]) {
resolve(RedisAdapter.transformRedisResponse(response)[SCALAR_KEY]);
return;
}
resolve(RedisAdapter.transformRedisResponse(response));
}
};
RedisAdapter.responseScanCommandCallback = (resolve, reject) => (err, response) => {
if (err) {
reject(err);
}
else {
// array exists at index '1' from SCAN command
resolve(response['1']);
}
};
RedisAdapter.responseCallback = (resolve, reject) => (err, response) => {
if (err) {
reject(err);
}
else {
if (response &&
typeof response === 'object' &&
Object.keys(response).length === 1 &&
response[SCALAR_KEY]) {
resolve(RedisAdapter.transformRedisResponse(response)[SCALAR_KEY]);
return;
}
};
return RedisAdapter;
})();
exports.RedisAdapter = RedisAdapter;
exports.useAdapter = (client) => {
resolve(RedisAdapter.transformRedisResponse(response));
}
};
RedisAdapter.responseScanCommandCallback = (resolve, reject) => (err, response) => {
if (err) {
reject(err);
}
else {
resolve(response);
return;
}
};
exports.useAdapter = (client, asFallback) => {
const redisAdapter = new RedisAdapter(client);
core_1.default.setClient(redisAdapter);
if (asFallback) {
core_1.default.setFallbackClient(redisAdapter);
}
else {
core_1.default.setClient(redisAdapter);
}
};
{
"name": "@type-cacheable/redis-adapter",
"version": "5.2.0",
"version": "6.0.0",
"description": "Adapter for using redis with type-cacheable",

@@ -49,3 +49,3 @@ "main": "dist/index.js",

"devDependencies": {
"@types/jest": "^25.1.0",
"@types/jest": "^26.0.0",
"@types/redis": "^2.8.13",

@@ -61,5 +61,5 @@ "jest": "^25.1.0",

"dependencies": {
"@type-cacheable/core": "^5.2.0"
"@type-cacheable/core": "^6.0.0"
},
"gitHead": "a5f3495fb4f0c2c05c2bd81900ba69ae9cbd657e"
"gitHead": "cff04b6483ff5c538fc798f11fd33ca15c665a31"
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc