Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

`use-cache-helper` provides helper functions to easily manage and scale your redis and database caching strategies.

## Install

```
npm i use-cache-helper
```

## Initialize

```ts
Expand Down
25 changes: 19 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@eslint/js": "^9.1.1",
"@types/node": "^20.12.7",
"cross-env": "^7.0.3",
"dotenv": "^16.4.5",
"eslint": "^8.57.0",
"eslint-config-prettier": "^9.1.0",
"globals": "^15.1.0",
Expand All @@ -35,7 +36,7 @@
"typescript-eslint": "^7.8.0"
},
"dependencies": {
"@upstash/redis": "^1.30.1",
"@upstash/redis": "^1.31.5",
"ioredis": "^5.4.1"
},
"repository": {
Expand Down
30 changes: 15 additions & 15 deletions src/features.ts → src/features/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { checkRedis } from './helpers';
import { UseCacheError } from './errors';
import { store } from './store';
import { checkRedis } from '../helpers';
import { UseCacheError } from '../errors';
import { store } from '../store';
import {
IAppInitParams,
IGetOrRefreshDataInPaginatedListParams,
Expand All @@ -11,7 +11,7 @@ import {
IRemoveItemFromPaginatedListParams,
ISetParams,
IUpdateItemScoreFromPaginatedList,
} from './types';
} from '../types';

/**
* Get latest cache data or force refresh before returning the value
Expand Down Expand Up @@ -145,7 +145,7 @@ export const getOrRefreshDataInPaginatedList = async <T>(
await updateItemScoreFromPaginatedList({
id,
score,
key: listKey,
listKey,
});
}

Expand All @@ -158,7 +158,7 @@ export const getOrRefreshDataInPaginatedList = async <T>(
* @param {Object} params
* @param {string} params.key - Data cache key
* @param {string | number | Object} params.value - Your data for the cache key
* @param {number} expiry - (optional) Expiry in seconds. No expiry set by default.
* @param {number} params.expiry - (optional) Expiry in seconds. No expiry set by default.
* @returns {string} 'OK' | 'Error'
*/
export const set = async <T>(params: ISetParams<T>): Promise<string | 'OK'> => {
Expand Down Expand Up @@ -229,7 +229,7 @@ export const init = (params: IAppInitParams): void => {
* Get paginated list by page.
* Always in ascending order.
* @param {Object} params
* @param {string} params.key - Your list's cache key
* @param {string} params.listKey - Your list's cache key
* @param {number} params.page - Target page
* @param {number} params.sizePerPage - Total items in a single page
* @param {boolean} params.ascendingOrder - (optional) Fetch list in ascending order. High to low by default.
Expand All @@ -238,7 +238,7 @@ export const init = (params: IAppInitParams): void => {
export const getPaginatedListByPage = async (
params: IGetPaginatedListByPageParams
): Promise<string[]> => {
const { page, sizePerPage, key, ascendingOrder = false } = params;
const { page, sizePerPage, listKey: key, ascendingOrder = false } = params;
const start = (page - 1) * sizePerPage;
const end = start + (sizePerPage - 1);
const items: { id: string; score: number }[] = [];
Expand Down Expand Up @@ -351,7 +351,7 @@ export const insertRecordsToPaginatedList = async <T>(params: {
await insertToPaginatedList({
score,
id,
key: listKey,
listKey,
});

if (cachePayload) {
Expand All @@ -377,15 +377,15 @@ export const insertRecordsToPaginatedList = async <T>(params: {
* Insert an item to the list using the item ID.
* Use non-zero & non-negative scores.
* @param {Object} params
* @param {string} params.key - Your list's cache key
* @param {string} params.listKey - Your list's cache key
* @param {string} params.id - Data id
* @param {number} params.score - (optional) Score order of the item in the paginated list, determining its placement.
* @returns {string}
*/
export const insertToPaginatedList = async (
params: IInsertPaginatedListItemParams
): Promise<string | 'OK'> => {
const { score, key, id } = params;
const { score, listKey: key, id } = params;
const total = await getPaginatedListTotalItems(key); // get count
const maxPaginatedItems = store.maxPaginatedItems;
const redis = store.redis;
Expand Down Expand Up @@ -423,14 +423,14 @@ export const insertToPaginatedList = async (
/**
* Remove item from the list.
* @param {Object} params
* @param {string} params.key - Your list's cache key
* @param {string} params.listKey - Your list's cache key
* @param {string} params.id - Item ID
* @returns {string} 'OK' | 'Error'
*/
export const removeItemFromPaginatedList = async (
params: IRemoveItemFromPaginatedListParams
): Promise<string | 'OK'> => {
const { id, key } = params;
const { id, listKey: key } = params;

if (!id) {
throw new UseCacheError('removeItemFromPaginatedList(): Invalid id.');
Expand Down Expand Up @@ -459,15 +459,15 @@ export const removeItemFromPaginatedList = async (
/**
* Update the score of an item in the paginated list to move it up or down in the order.
* @param {Object} params
* @param {string} params.key - Your list's cache key
* @param {string} params.listKey - Your list's cache key
* @param {string} params.id - Item ID*
* @param {number} params.score - Score order of the item in the paginated list, determining its placement.
* @returns
*/
export const updateItemScoreFromPaginatedList = async (
params: IUpdateItemScoreFromPaginatedList
): Promise<string | 'OK'> => {
const { score, id, key } = params;
const { score, id, listKey: key } = params;

if (!id) {
throw new UseCacheError('updateItemScoreFromPaginatedList(): Invalid id.');
Expand Down
62 changes: 62 additions & 0 deletions src/features/paginated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import { store } from 'store';
import { checkRedis } from '../helpers';

/**
* Check if Redis stack schema for paginated list already exists.
* @returns {boolean} true or false
*/
export const validateSchemaAlreadyExists = async (
listKey: string
): Promise<boolean> => {
checkRedis();

try {
const redis = store.redis;

if (redis) {
await redis.call('FT.INFO', `${listKey || ''}_idx`);
} else {
console.log(
'UseCacheError: validateSchemaAlreadyExists() is not supported for @upstash/redis instance'
);

return false;
}

return true;
} catch (err) {
return false;
}
};

/**
* Define schema for your paginated list.
* This allows you to call searchPaginatedListByProperty() and query your paginated data.
* @param {string} listKey Your list's cache key
* @param {Object} properties
*/
export const createSchemaForSearchableList = (
listKey: string,
properties: Record<string, 'string' | 'number'>
) => {
if (properties && typeof properties === 'object') {
const keys = Object.keys(properties);

for (let i = 0; i < keys.length; i++) {
const property = properties[keys[i]];

if (property === 'string' || property === 'number') {
// @todo add schema
}
}
}
};

export const searchPaginatedListByProperty = (
listKey: string,
properties: Record<string, string>
) => {
if (listKey && properties && typeof properties === 'object') {
// @todo search by property
}
};
8 changes: 4 additions & 4 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,25 @@ export interface IAppStoreRef {
}

export interface IGetPaginatedListByPageParams {
key: string;
listKey: string;
page: number;
sizePerPage: number;
ascendingOrder?: boolean;
}

export interface IInsertPaginatedListItemParams {
key: string;
listKey: string;
id: string;
score?: number;
}

export interface IRemoveItemFromPaginatedListParams {
key: string;
listKey: string;
id: string;
}

export interface IUpdateItemScoreFromPaginatedList {
key: string;
listKey: string;
id: string;
score: number;
}
31 changes: 24 additions & 7 deletions tests/index.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,36 @@
import { getOrRefresh } from '../src/features';
import 'dotenv/config';
import { init, getOrRefresh } from '../src/features';
import { Redis } from '@upstash/redis';

interface IUserProfile {
id: string;
name: string;
}

export const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL || '',
token: process.env.UPSTASH_REDIS_REST_TOKEN || '',
});

export const start = async () => {
interface IUserProfile {
id: string;
name: string;
}
await testGetOrRefresh();
};

const testGetOrRefresh = async () => {
const id = 'test-user-id';
const res = await getOrRefresh<IUserProfile>({
key: 'userProfile' + id,
async cacheRefreshHandler(): Promise<IUserProfile> {
return {} as IUserProfile;
return {
id,
name: 'TestUserProfile',
} as IUserProfile;
},
});

if (res?.id) {
//
console.log('getOrRefresh', res);
}
};

init({ upstashRedis: redis, maxPaginatedItems: 100 });