Skip to content

Commit

Permalink
redis client register async support added
Browse files Browse the repository at this point in the history
  • Loading branch information
wjamilaion committed Oct 25, 2023
1 parent eb3b5be commit 8a44a00
Show file tree
Hide file tree
Showing 7 changed files with 153 additions and 17 deletions.
46 changes: 43 additions & 3 deletions __test__/redis-client/redis-client.module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
RedisClientService,
} from '../../src/redis-client';
import RedisMock from 'ioredis-mock';
import { Module } from '@nestjs/common';

const config = {
REDIS_CONNECTION: {
Expand All @@ -17,16 +18,55 @@ describe('RedisClientModule', () => {
imports: [
RedisConnectorModule.register(
{
...config.REDIS_CONNECTION,
ttl: 0,
config: {
...config.REDIS_CONNECTION,
ttl: 0,
},
_Redis: RedisMock
},
RedisMock,
),
],
}).compile();

expect(module).toBeDefined();
expect(module.get(RedisClientService)).toBeInstanceOf(RedisClientService);
module.close();
});
it('should compile the module using async', async () => {
const module = await Test.createTestingModule({
imports: [
RedisConnectorModule.registerAsync({
imports:[ConfigModule],
useFactory: (configService: ConfigService) => {
return {
config: {
...configService.createRedisOptions(),
},
_Redis: RedisMock
}
},
inject: [ConfigService]
}),
],
}).compile();

expect(module).toBeDefined();
expect(module.get(RedisClientService)).toBeInstanceOf(RedisClientService);
module.close();
});
});

// to test async options params
class ConfigService{
createRedisOptions(){
return {
url: ''
}
}
}

@Module({
providers: [ConfigService],
exports: [ConfigService]
})
class ConfigModule {}
8 changes: 5 additions & 3 deletions __test__/redis-client/redis-client.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,12 @@ describe('RedisClientService', () => {
imports: [
RedisConnectorModule.register(
{
...config.REDIS_CONNECTION,
ttl: 0,
config: {
...config.REDIS_CONNECTION,
ttl: 0,
},
_Redis: RedisMock
},
RedisMock,
),
],
}).compile();
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

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

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nestjs-redis-connector",
"version": "1.0.2",
"version": "1.0.3",
"description": "redis connector for NestJs based services",
"main": "dist/index.js",
"types": "dist/index.d.ts",
Expand Down
1 change: 1 addition & 0 deletions src/redis-client/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './redis-client.module';
export * from './redis-client.service';
export * from './redis-store';
export * from './redis-client.interface';
26 changes: 26 additions & 0 deletions src/redis-client/redis-client.interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Redis, RedisOptions } from 'ioredis';
import type { Config } from 'cache-manager';
import RedisMock from 'ioredis-mock';
import { RedisClusterConfig } from '.';
import { ModuleMetadata, Type } from '@nestjs/common';

export type RedisConnectorConfig = (RedisOptions | { clusterConfig: RedisClusterConfig }) &
Config & { url: string };

export interface RedisConnectorOptions {
config: RedisConnectorConfig;
_Redis?: typeof Redis | typeof RedisMock;
}

export interface RedisOptionsFactory {
createRedisConnectorOptions(): Promise<RedisConnectorOptions> | RedisConnectorOptions;
}
export interface RedisOptionsAsync extends Pick<ModuleMetadata, 'imports'> {
isGlobal?: boolean;
useExisting?: Type<RedisOptionsFactory>;
useClass?: Type<RedisOptionsFactory>;
useFactory?: (...args: any[]) => Promise<RedisConnectorOptions> | RedisConnectorOptions;
inject?: any[];
}

export const REDIS_CONNECTOR_MODULE_OPTIONS='REDIS_CONNECTOR_MODULE_OPTIONS'
83 changes: 75 additions & 8 deletions src/redis-client/redis-client.module.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
import { DynamicModule, Module } from '@nestjs/common';
import { DynamicModule, Module, Provider, Type } from '@nestjs/common';
import { RedisClientService } from './redis-client.service';
import { CacheModule } from '@nestjs/cache-manager';
import { RedisClusterConfig, redisStore } from '.';
import { Redis, RedisOptions } from 'ioredis';
import type { Config } from 'cache-manager';
import RedisMock from 'ioredis-mock';
import { redisStore } from '.';
import { REDIS_CONNECTOR_MODULE_OPTIONS, RedisConnectorOptions, RedisOptionsAsync, RedisOptionsFactory } from './redis-client.interface';

@Module({})
export class RedisConnectorModule {
static register(
config: (RedisOptions | { clusterConfig: RedisClusterConfig }) &
Config & { url: string },
_Redis?: typeof Redis | typeof RedisMock,
options: RedisConnectorOptions
): DynamicModule {
const {
config,
_Redis
} = options;
return {
imports: [
CacheModule.registerAsync({
Expand All @@ -33,4 +33,71 @@ export class RedisConnectorModule {
exports: [RedisClientService],
};
}
static registerAsync(options: RedisOptionsAsync): DynamicModule {
return {
global: options.isGlobal,
module: RedisConnectorModule,
imports:[...options.imports??[],
CacheModule.registerAsync({
isGlobal: options.isGlobal,
imports: [...options.imports??[]],
useFactory: async (options: RedisConnectorOptions) => {
const {
config,
_Redis
} = options;
return {
store: await redisStore(config.url, {
...config,
ttl: 0,
})(_Redis),
};
},
inject: [REDIS_CONNECTOR_MODULE_OPTIONS],
extraProviders: [...this.createAsyncProviders(options)]
}),
],
providers: [...this.createAsyncProviders(options), RedisClientService],
exports: [RedisClientService],
};
}

private static createAsyncProviders(
options: RedisOptionsAsync,
): Provider[] {
if (options.useExisting || options.useFactory) {
return [this.createAsyncOptionsProvider(options)];
}
const useClass = options.useClass as Type<RedisOptionsFactory>;
return [
this.createAsyncOptionsProvider(options),
{
provide: useClass,
useClass,
},
];
}

private static createAsyncOptionsProvider(
options: RedisOptionsAsync,
): Provider {
if (options.useFactory) {
return {
provide: REDIS_CONNECTOR_MODULE_OPTIONS,
useFactory: options.useFactory,
inject: options.inject || [],
};
}
// `as Type<TypeOrmOptionsFactory>` is a workaround for microsoft/TypeScript#31603
const inject = [
(options.useClass ||
options.useExisting) as Type<RedisOptionsFactory>,
];
return {
provide: REDIS_CONNECTOR_MODULE_OPTIONS,
useFactory: async (optionsFactory: RedisOptionsFactory) =>
await optionsFactory.createRedisConnectorOptions(),
inject,
};
}
}

0 comments on commit 8a44a00

Please sign in to comment.