Skip to content
This repository has been archived by the owner on Feb 7, 2021. It is now read-only.

Commit

Permalink
feat: implementing forFeature (#64)
Browse files Browse the repository at this point in the history
Add support for module imports using forFeature method in addition to forRoot. This adds the ability for multiple instances of InMemoryDBService to be registered each with differing configurations.

Closes #59
  • Loading branch information
wesleygrimes authored Aug 29, 2019
1 parent 0a68aa5 commit aae9146
Show file tree
Hide file tree
Showing 18 changed files with 283 additions and 48 deletions.
51 changes: 50 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ To get started, let's first update our `app.module.ts` to include the necessary

> While we are importing to the AppModule in this example, InMemoryDBModule could be imported in Feature modules just as well.
#### Registering a forRoot InMemoryDBService

```typescript
// app.module.ts

Expand All @@ -48,7 +50,7 @@ import { InMemoryDBModule } from '@nestjs-addons/in-memory-db';

@Module({
...
imports: [InMemoryDBModule.forRoot()],
imports: [InMemoryDBModule.forRoot({})],
...
})
export class AppModule {}
Expand Down Expand Up @@ -102,6 +104,53 @@ export class UserController {
}
```

## Feature Modules - Registering Multiple Instances using `forFeature`

Registering multiple instances for specific feature modules is super simple. Each feature module is guaranteed isolated to that feature. In order to get up and running you need to do the following:

#### Registering a forFeature InMemoryDBService

For each feature module(s), do the following:

```typescript
// feature-one.module.ts

import { Module } from '@nestjs/common';
import { InMemoryDBModule } from '@nestjs-addons/in-memory-db';
...

@Module({
...
imports: [InMemoryDBModule.forFeature('one', {})],
...
})
export class FeatureOneModule {}
```

As you can see we:

- Imported `InMemoryDBModule` from `@nestjs-addons/in-memory-db`
- Added `InMemoryDBModule` to the `imports` array in the `@Module` of your choice
- Added the `forFeature` method call passing `one` as the feature name

#### Using the Feature Instance

If you would like to use the feature-specific instance, make use of the included `@InjectInMemoryDBService` decorator:

```typescript
@Controller({...})
export class FeatureOneController {
constructor(@InjectInMemoryDBService('one') private oneService: InMemoryDBService<OneEntity>) {}
...
@Get()
getAll(): OneEntity[] {
return this.oneService.getAll();
}
}
```

Using this decorator ensures that the correct instance is injected.

## Docs

[Click here for more detailed API Documentation](API.md)
Expand Down
2 changes: 2 additions & 0 deletions lib/common/in-memory-db.constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const IN_MEMORY_DB_SERVICE = 'InMemoryDBService';
export const IN_MEMORY_DB_CONFIG = 'InMemoryDBConfig';
5 changes: 5 additions & 0 deletions lib/common/in-memory-db.decorators.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Inject } from '@nestjs/common';
import { getInMemoryDBServiceToken } from './in-memory-db.utils';

export const InjectInMemoryDBService = (featureName: string) =>
Inject(getInMemoryDBServiceToken(featureName));
19 changes: 19 additions & 0 deletions lib/common/in-memory-db.utils.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { getInMemoryDBServiceToken } from './in-memory-db.utils';

describe('getInMemoryDBServiceToken', () => {
test.each([
['oneInMemoryDBService', 'one'],
['InMemoryDBService', ''],
['InMemoryDBService', null],
['InMemoryDBService', undefined],
])(
'should return %p token given input featureName of %p',
(expectedToken: string, featureName: string) => {
// act
const actualToken = getInMemoryDBServiceToken(featureName);

// assert
expect(actualToken).toEqual(expectedToken);
},
);
});
7 changes: 7 additions & 0 deletions lib/common/in-memory-db.utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { IN_MEMORY_DB_SERVICE } from './in-memory-db.constants';

export function getInMemoryDBServiceToken(featureName?: string) {
return featureName && featureName !== IN_MEMORY_DB_SERVICE
? `${featureName}${IN_MEMORY_DB_SERVICE}`
: IN_MEMORY_DB_SERVICE;
}
2 changes: 2 additions & 0 deletions lib/common/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './in-memory-db.decorators';
export { getInMemoryDBServiceToken } from './in-memory-db.utils';
15 changes: 15 additions & 0 deletions lib/factories/in-memory-db-service.factory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { InMemoryDBConfig, InMemoryDBEntity } from '../interfaces';
import { InMemoryDBService } from '../services';

export function inMemoryDBServiceFactory<T extends InMemoryDBEntity>(
featureConfig: Partial<InMemoryDBConfig> = {},
featureName?: string,
) {
return () =>
new InMemoryDBService<T>({
featureName: featureName
? featureName
: featureConfig.featureName || 'root',
...featureConfig,
});
}
1 change: 1 addition & 0 deletions lib/factories/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './in-memory-db-service.factory';
27 changes: 19 additions & 8 deletions lib/in-memory-db.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,33 @@ import { DynamicModule, Module } from '@nestjs/common';

import { InMemoryDBConfig } from './interfaces';
import { InMemoryDBService } from './services';

import {
createInMemoryDBForRootProviders,
createInMemoryDBForFeatureProviders,
} from './providers';
@Module({
providers: [InMemoryDBService],
exports: [InMemoryDBService],
})
export class InMemoryDBModule {
public static forRoot(config: Partial<InMemoryDBConfig> = {}): DynamicModule {
const providers = createInMemoryDBForRootProviders(config);
return {
module: InMemoryDBModule,
providers,
exports: providers,
};
}

public static forFeature(
featureName: string,
config: Partial<InMemoryDBConfig> = {},
): DynamicModule {
const providers = createInMemoryDBForFeatureProviders(featureName, config);
return {
module: InMemoryDBModule,
providers: [
{
provide: InMemoryDBService,
useValue: new InMemoryDBService(config),
},
],
exports: [InMemoryDBService],
providers,
exports: providers,
};
}
}
3 changes: 3 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
import 'reflect-metadata';
import { InjectInMemoryDBService } from './common';

export * from './in-memory-db.module';
export * from './interfaces';
export * from './services';
export { InjectInMemoryDBService };
10 changes: 8 additions & 2 deletions lib/interfaces/in-memory-db-config.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
// tslint:disable-next-line: no-empty-interface
export interface InMemoryDBConfig {}
/**
* InMemoryDBConfig defines the config settings for InMemoryDBModule
*
* All properties should remain optional except featureName
*/
export interface InMemoryDBConfig {
featureName: string;
}
36 changes: 36 additions & 0 deletions lib/providers/in-memory-db-for-feature.providers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { FactoryProvider } from '@nestjs/common/interfaces';

import { getInMemoryDBServiceToken } from '../common/in-memory-db.utils';
import { createInMemoryDBForFeatureProviders } from './in-memory-db-for-feature.providers';
import { InMemoryDBConfig } from '../interfaces';
import { inMemoryDBServiceFactory } from '../factories';

describe('createInMemoryDBForFeatureProviders', () => {
test('returns correct providers array given featureName and featureConfig', () => {
// arrange
const inputFeatureName = 'myFeature';
const inputFeatureConfig: Partial<InMemoryDBConfig> = {};

const expectedProviders: Array<FactoryProvider<any>> = [
{
provide: getInMemoryDBServiceToken(inputFeatureName),
useFactory: inMemoryDBServiceFactory(
inputFeatureConfig,
inputFeatureName,
),
},
];

// act
const actualProviders = createInMemoryDBForFeatureProviders(
inputFeatureName,
inputFeatureConfig,
);

// assert
expect(actualProviders[0].provide).toEqual(expectedProviders[0].provide);
expect(actualProviders[0].useFactory()).toEqual(
expectedProviders[0].useFactory(),
);
});
});
17 changes: 17 additions & 0 deletions lib/providers/in-memory-db-for-feature.providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { InMemoryDBConfig } from '../interfaces';
import { getInMemoryDBServiceToken } from '../common';
import { inMemoryDBServiceFactory } from '../factories';
import { FactoryProvider } from '@nestjs/common/interfaces';

export function createInMemoryDBForFeatureProviders(
featureName: string,
featureConfig: Partial<InMemoryDBConfig> = {},
) {
const providers: FactoryProvider[] = [
{
provide: getInMemoryDBServiceToken(featureName),
useFactory: inMemoryDBServiceFactory(featureConfig, featureName),
},
];
return providers;
}
31 changes: 31 additions & 0 deletions lib/providers/in-memory-db-for-root.providers.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { FactoryProvider } from '@nestjs/common/interfaces';

import { getInMemoryDBServiceToken } from '../common/in-memory-db.utils';
import { createInMemoryDBForRootProviders } from './in-memory-db-for-root.providers';
import { InMemoryDBConfig } from '../interfaces';
import { inMemoryDBServiceFactory } from '../factories';

describe('createInMemoryDBForRootProviders', () => {
test('returns correct providers array given featureName and featureConfig', () => {
// arrange
const inputFeatureConfig: Partial<InMemoryDBConfig> = {};

const expectedProviders: Array<FactoryProvider<any>> = [
{
provide: getInMemoryDBServiceToken(),
useFactory: inMemoryDBServiceFactory(inputFeatureConfig),
},
];

// act
const actualProviders = createInMemoryDBForRootProviders(
inputFeatureConfig,
);

// assert
expect(actualProviders[0].provide).toEqual(expectedProviders[0].provide);
expect(actualProviders[0].useFactory()).toEqual(
expectedProviders[0].useFactory(),
);
});
});
17 changes: 17 additions & 0 deletions lib/providers/in-memory-db-for-root.providers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FactoryProvider } from '@nestjs/common/interfaces';

import { inMemoryDBServiceFactory } from '../factories';
import { getInMemoryDBServiceToken } from '../common';
import { InMemoryDBConfig } from '../interfaces';

export function createInMemoryDBForRootProviders(
featureConfig: Partial<InMemoryDBConfig> = {},
) {
const providers: FactoryProvider[] = [
{
provide: getInMemoryDBServiceToken(),
useFactory: inMemoryDBServiceFactory(featureConfig),
},
];
return providers;
}
2 changes: 2 additions & 0 deletions lib/providers/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './in-memory-db-for-root.providers';
export * from './in-memory-db-for-feature.providers';
Loading

0 comments on commit aae9146

Please sign in to comment.