diff --git a/CHANGELOG.md b/CHANGELOG.md index 6209b30..8fba060 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1 +1,19 @@ -RELEASE 1.0.0 \ No newline at end of file +## RELEASE 1.1.0 +### Feature +* Add full support for useClass and useExisting +* Add more docs +### Bug Fixes +* Fix minor bugs + +## RELEASE 1.0.5 +### Feature +* Update package.json +* Add more docs +### Bug Fixes +* Fix minor bugs + +## RELEASE 1.0.1 +### Feature +* Initial support for About currency conversion module for nestjs +### Bug Fixes +* Fix minor bugs \ No newline at end of file diff --git a/example/src/app.module.ts b/example/src/app.module.ts index 1b44fc9..c38b4b8 100644 --- a/example/src/app.module.ts +++ b/example/src/app.module.ts @@ -12,7 +12,6 @@ const rates = { @Module({ imports: [ - ConfigModule.forRoot(), // CashifyModule.forRoot({base: 'EUR', rates}), CashifyModule.forRootAsync({ imports: [ConfigModule], @@ -20,7 +19,12 @@ const rates = { base: configService.get('BASE'), rates }), inject: [ConfigService] - }) + }), + // CashifyModule.forRootAsync({ + // useClass: CashifyConfigService, + // import: [ConfigModule], + // extraProviders: [ConfigService], + // }) ], controllers: [AppController], providers: [AppService], diff --git a/example/src/cashify-config.service.ts b/example/src/cashify-config.service.ts new file mode 100644 index 0000000..7f09437 --- /dev/null +++ b/example/src/cashify-config.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from "@nestjs/common"; +import { ConfigService } from "@nestjs/config"; +import { CashifyOptionsFactory } from 'nestjs-cashify'; + +@Injectable() +export class CashifyConfigService implements CashifyOptionsFactory { + constructor(private configService: ConfigService) {} + + createCashifyOptions() { + const rates = { + GBP: 0.92, + EUR: 1.00, + USD: 1.12 + }; + return { + base: this.configService.get('BASE'), + rates + }; + } +} \ No newline at end of file diff --git a/package.json b/package.json index e3d97dc..bcccfa1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "nestjs-cashify", - "version": "1.0.5", + "version": "1.1.0", "description": "Currency conversion module for nest", "author": "Vahid Najafi ", "license": "MIT", @@ -22,7 +22,14 @@ "test:e2e": "jest --config ./test/jest-e2e.json" }, "keywords": [ - "nestjs" + "nestjs", + "nodejs", + "cashify", + "nestjs-cashify", + "currency-exchange", + "conversion", + "money", + "exchange-rates" ], "publishConfig": { "access": "public" diff --git a/src/cashify.module.ts b/src/cashify.module.ts index 1d6b3a4..a0e0e46 100644 --- a/src/cashify.module.ts +++ b/src/cashify.module.ts @@ -1,10 +1,23 @@ -import { DynamicModule, Module } from '@nestjs/common'; +import { DynamicModule, Module, Provider } from '@nestjs/common'; import { Cashify } from 'cashify'; import { CASHIFY, CashifyService, CASHIFY_OPTIONS } from './'; +import { CashifyOptionsFactory } from './interfaces/cashify-module.interface'; @Module({}) export class CashifyModule { + + /** + * @param options a simple configuration object + * @returns DynamicModule object + */ public static forRoot(options): DynamicModule { + + /** + * To have access to the Cashify's instance by CASHIFY token injection + * The reason we export it too, is that we can have direct access in consumer module, + * so if there is a new method added in future for core module by it's author, + * consumer module can have access to it + */ const CashifyProvider = { provide: CASHIFY, useValue: new Cashify(options), @@ -18,13 +31,19 @@ export class CashifyModule { ] } } + + /** + * @param optionsAsync this is not a simple object of main options + * this is an async configuration with useFactory passed from consumer module + * @returns DynamicModule object + */ public static forRootAsync(optionsAsync): DynamicModule { - const CashifyOptionProvider = { - provide: CASHIFY_OPTIONS, - useFactory: optionsAsync.useFactory, - inject: optionsAsync.inject || [] - }; - const CashifyProvider = { + + /** + * This is our main provider that is accessible within the service + * The same one in forRoot method (but resolve the options in an async way) + */ + const CashifyProvider = { provide: CASHIFY, useFactory: (options) => new Cashify(options), inject: [CASHIFY_OPTIONS], @@ -35,10 +54,53 @@ export class CashifyModule { imports: optionsAsync.imports, exports: [CashifyService, CashifyProvider], providers: [ + ...this.createAsyncProviders(optionsAsync), CashifyProvider, - CashifyOptionProvider, - CashifyService - ] + CashifyService, + ...(optionsAsync.extraProviders || []), + ], } } + + private static createAsyncProviders(options): Provider[] { + if (options.useExisting || options.useFactory) { + return [this.createAsyncOptionsProvider(options)]; + } + return [ + this.createAsyncOptionsProvider(options), + { + provide: options.useClass, + useClass: options.useClass, + }, + ]; + } + + private static createAsyncOptionsProvider(optionsAsync): Provider { + + /** + * This is going to be a factory provider and import in the list of providers + * This provider make the options value available in CashifyProvider. Since it's a provider, + * it can be injected in CashifyProvider + */ + if (optionsAsync.useFactory) { + return { + provide: CASHIFY_OPTIONS, + useFactory: optionsAsync.useFactory, + inject: optionsAsync.inject || [] + }; + } + + /** + * In consumer module, if we use useClass, the give class may have some dependencies, + * like ConfigService (and it's module). But they are not available in this module's context. + * So, we have an 'imports' object and extraProviders in forRootAsync method. + * Then we can dynamically add them from consumer module. See example in example folder. + */ + return { + provide: CASHIFY_OPTIONS, + useFactory: async (optionsFactory: CashifyOptionsFactory) => + optionsFactory.createCashifyOptions(), + inject: [optionsAsync.useExisting || optionsAsync.useClass], + }; + } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 4c382b4..22f40f6 100644 --- a/src/index.ts +++ b/src/index.ts @@ -2,4 +2,5 @@ export * from './cashify.const'; export * from './cashify.module'; export * from './cashify.service'; +export * from './interfaces'; diff --git a/src/interfaces/cashify-module.interface.ts b/src/interfaces/cashify-module.interface.ts new file mode 100644 index 0000000..fe117ed --- /dev/null +++ b/src/interfaces/cashify-module.interface.ts @@ -0,0 +1,11 @@ +/** + * Interface describing a `CashifyOptionsFactory`. Providers supplying configuration + * options for the Cashify module must implement this interface. + * + * @see [Async configuration](https://docs.nestjs.com/techniques/caching#async-configuration) + * + * @publicApi + */ + export interface CashifyOptionsFactory { + createCashifyOptions(); + } \ No newline at end of file diff --git a/src/interfaces/index.ts b/src/interfaces/index.ts new file mode 100644 index 0000000..a656222 --- /dev/null +++ b/src/interfaces/index.ts @@ -0,0 +1 @@ +export * from './cashify-module.interface';