Skip to content

Commit

Permalink
feat: new cache manager component (#3492)
Browse files Browse the repository at this point in the history
* fix(deps): update dependency ws to v8.16.0 (#3524)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* fix(deps): update dependency axios to v1.6.3 (#3523)

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>

* chore: add cache code

* feat: add cache-manager and cache-manager-redis

* fix: store options

* chore: upgrade cache-manager

* chore: sync cache-manager

* fix: typings

* fix: test

---------

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
  • Loading branch information
czy88840616 and renovate[bot] authored Dec 30, 2023
1 parent c1ed3a2 commit af82070
Show file tree
Hide file tree
Showing 49 changed files with 1,488 additions and 5 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"description": "midway cache manager",
"main": "dist/index.js",
"typings": "index.d.ts",
"private": true,
"scripts": {
"build": "tsc",
"test": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand",
Expand Down Expand Up @@ -32,7 +33,6 @@
"@midwayjs/mock": "^3.13.9"
},
"dependencies": {
"@types/cache-manager": "3.4.3",
"cache-manager": "3.6.3"
}
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
12 changes: 12 additions & 0 deletions packages/cache-manager-redis/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# midway cache manager redis store

[![Package Quality](http://npm.packagequality.com/shield/midway-core.svg)](http://packagequality.com/#?package=midway-core)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/midwayjs/midway/pulls)

this is a sub package for midway.

Document: [https://midwayjs.org](https://midwayjs.org)

## License

[MIT]((http://github.com/midwayjs/midway/blob/master/LICENSE))
8 changes: 8 additions & 0 deletions packages/cache-manager-redis/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testPathIgnorePatterns: ['<rootDir>/test/fixtures'],
coveragePathIgnorePatterns: ['<rootDir>/test/', '<rootDir>/dist/'],
setupFilesAfterEnv: ['./jest.setup.js'],
coverageProvider: 'v8',
};
2 changes: 2 additions & 0 deletions packages/cache-manager-redis/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
process.env.MIDWAY_TS_MODE = 'true';
jest.setTimeout(30000);
40 changes: 40 additions & 0 deletions packages/cache-manager-redis/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "@midwayjs/cache-manager-redis",
"version": "3.13.5",
"description": "midway redis store for cache manager",
"main": "dist/index.js",
"typings": "dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand",
"cov": "node --require=ts-node/register ../../node_modules/.bin/jest --runInBand --coverage --forceExit"
},
"author": "",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "[email protected]:midwayjs/midway.git"
},
"keywords": [
"midway",
"cache",
"store",
"redis"
],
"engines": {
"node": ">=12"
},
"devDependencies": {
"@midwayjs/core": "^3.13.5",
"@midwayjs/cache-manager": "^3.13.5",
"@midwayjs/mock": "^3.13.5",
"cache-manager": "5.3.1"
},
"dependencies": {
"@midwayjs/redis": "^3.13.5"
}
}
12 changes: 12 additions & 0 deletions packages/cache-manager-redis/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { IMidwayContainer } from '@midwayjs/core';
import { RedisServiceFactory } from '@midwayjs/redis';
import { Config } from 'cache-manager';
import { createRedisStore } from './store';

export function createStore(instanceName: string) {
return async (options: Config, container: IMidwayContainer) => {
const redisServiceFactory = await container.getAsync(RedisServiceFactory);
const redisInstance = redisServiceFactory.get(instanceName);
return createRedisStore(redisInstance, options);
};
}
76 changes: 76 additions & 0 deletions packages/cache-manager-redis/src/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import type { Config, Store } from 'cache-manager';
import { Redis } from '@midwayjs/redis';
import { MidwayCommonError } from '@midwayjs/core';

const getVal = (value: unknown) => JSON.stringify(value) || '"undefined"';
export interface RedisStore extends Store {
readonly isCacheable: (value: unknown) => boolean;
}

export function createRedisStore(redisCache: Redis, options?: Config) {
const isCacheable =
options?.isCacheable || (value => value !== undefined && value !== null);

const keys = (pattern: string) => redisCache.keys(pattern);

return {
async get<T>(key: string) {
const val = await redisCache.get(key);
if (val === undefined || val === null) return undefined;
else return JSON.parse(val) as T;
},
async set(key, value, ttl) {
if (!isCacheable(value))
throw new MidwayCommonError(`"${value}" is not a cacheable value`);
const t = ttl === undefined ? options?.ttl : ttl;
if (t !== undefined && t !== 0)
await redisCache.set(key, getVal(value), 'PX', t);
else await redisCache.set(key, getVal(value));
},
async mset(args, ttl) {
const t = ttl === undefined ? options?.ttl : ttl;
if (t !== undefined && t !== 0) {
const multi = redisCache.multi();
for (const [key, value] of args) {
if (!isCacheable(value))
throw new MidwayCommonError(
`"${getVal(value)}" is not a cacheable value`
);
multi.set(key, getVal(value), 'PX', t);
}
await multi.exec();
} else
await redisCache.mset(
args.flatMap(([key, value]) => {
if (!isCacheable(value))
throw new Error(`"${getVal(value)}" is not a cacheable value`);
return [key, getVal(value)] as [string, string];
})
);
},
mget: (...args) =>
redisCache
.mget(args)
.then(x =>
x.map(x =>
x === null || x === undefined
? undefined
: (JSON.parse(x) as unknown)
)
),
async mdel(...args) {
await redisCache.del(args);
},
async del(key) {
await redisCache.del(key);
},
ttl: async key => redisCache.pttl(key),
keys: (pattern = '*') => keys(pattern),
reset: () => {
throw new MidwayCommonError(
'flushdb() is too dangerous, if necessary, please use redisServiceFactory.get(client) to get the instance and call it manually.'
);
},
isCacheable,
} as RedisStore;
}
91 changes: 91 additions & 0 deletions packages/cache-manager-redis/test/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import * as cacheManager from '@midwayjs/cache-manager';
import * as redis from '@midwayjs/redis';
import { createLightApp, close } from '@midwayjs/mock';
import { createStore } from '../src';
import { CachingFactory } from '@midwayjs/cache-manager';

describe('cache-manager-redis', () => {
it('should test single caching', async () => {
const app = await createLightApp('', {
imports: [
cacheManager,
redis,
],
globalConfig: {
cacheManager: {
client: {
store: createStore('default'),
options: {
ttl: 10,
}
}
},
redis: {
client: {
port: 6379,
host: '127.0.0.1',
}
}
},
});

const cachingFactory = await app.getApplicationContext().getAsync(CachingFactory);
const caching = cachingFactory.getCaching('default');
await caching.set('foo', 'bar', 1000);
const result = await caching.get('foo');
expect(result).toEqual('bar');


try {
await caching.reset();
} catch (e) {
expect(e.message).toMatch('flushdb() is too dangerous');
}

await close(app);
});

it('should test multi caching', async () => {
const app = await createLightApp('', {
imports: [
redis,
cacheManager,
],
globalConfig: {
cacheManager: {
client: {
store: [
{
store: createStore('default'),
options: {
ttl: 10,
}
}
]
}
},
redis: {
client: {
port: 6379,
host: '127.0.0.1',
}
}
}
});


const cachingFactory = await app.getApplicationContext().getAsync(CachingFactory);
const caching = cachingFactory.getMultiCaching('default');
await caching.mset([['foo', 'bar']], 5);

const result = await caching.mget('foo');
expect(result).toEqual(['bar']);

// mdel
await caching.mdel('foo');
const result2 = await caching.mget('foo');
expect(result2).toEqual([undefined]);

await close(app);
});
});
11 changes: 11 additions & 0 deletions packages/cache-manager-redis/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"extends": "../../tsconfig.json",
"compileOnSave": true,
"compilerOptions": {
"rootDir": "src",
"outDir": "dist"
},
"include": [
"./src/**/*.ts"
]
}
4 changes: 4 additions & 0 deletions packages/cache-manager-redis/typedoc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"extends": ["../../typedoc.base.json"],
"entryPoints": ["src/index.ts"]
}
Loading

0 comments on commit af82070

Please sign in to comment.