Skip to content

Commit

Permalink
Discover Method handlers and meta
Browse files Browse the repository at this point in the history
  • Loading branch information
WonderPanda committed Feb 10, 2019
1 parent ad2c110 commit d899e3d
Show file tree
Hide file tree
Showing 7 changed files with 72 additions and 29 deletions.
4 changes: 0 additions & 4 deletions examples/caching/tsconfig.build.json

This file was deleted.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"typescript": "^3.2.4"
},
"scripts": {
"publish": "lerna run tsc && lerna publish",
"publish:lerna": "lerna run build && lerna publish",
"build": "lerna run build",
"clean": "rimraf packages/**/lib",
"test": "jest"
Expand Down
20 changes: 20 additions & 0 deletions packages/common/src/discovery/discovery.interfaces.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Injectable } from '@nestjs/common/interfaces';
import { InstanceWrapper } from '@nestjs/core/injector/container';

export interface MethodMeta<T> {
meta: T;
handler: Function;
methodName: string;
provider: Injectable;
}

export interface ProviderMeta<T> {
meta: T;
provider: InstanceWrapper<Injectable>;
}

export type MetaKey = string | number | Symbol;

export type ProviderFilter = (
injectableWrapper: InstanceWrapper<Injectable>
) => boolean;
40 changes: 27 additions & 13 deletions packages/common/src/discovery/discovery.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import { InstanceWrapper } from '@nestjs/core/injector/container';
import { ModulesContainer } from '@nestjs/core/injector/modules-container';
import { MetadataScanner } from '@nestjs/core/metadata-scanner';
import { flatMap } from 'lodash';

export type MetaKey = string | number | Symbol;

type ProviderFilter = (
injectableWrapper: InstanceWrapper<NestInjectable>
) => boolean;
import { MetaKey, MethodMeta, ProviderFilter } from './discovery.interfaces';

type HandlerFilter = (
injectable: NestInjectable,
Expand Down Expand Up @@ -57,23 +52,25 @@ export class DiscoveryService {
}

/**
* Discovers all the handlers that exist on providers in a Nest App that match a filter
* Discovers all the handlers that exist on providers in a Nest App that contain metadata under a specific key
* @param providerFilter
* @param handlerFilter
*/
discoverHandlers(
discoverHandlersWithMeta<T>(
providerFilter: ProviderFilter,
handlerFilter: HandlerFilter
) {
metaKey: MetaKey
): MethodMeta<T>[] {
const providers = this.discoverProviders(providerFilter);

return flatMap(providers, provider => {
const { instance } = provider;
const prototype = Object.getPrototypeOf(instance);

return this.metadataScanner.scanFromPrototype(instance, prototype, name =>
handlerFilter(instance, prototype, name)
);
return this.metadataScanner
.scanFromPrototype(instance, prototype, name =>
extractMeta<T>(metaKey, instance, prototype, name)
)
.filter(x => !!x.meta);
});
}

Expand All @@ -83,3 +80,20 @@ export class DiscoveryService {
);
}
}

function extractMeta<T>(
metaKey: MetaKey,
provider: NestInjectable,
prototype: any,
methodName: string
): MethodMeta<T> {
const handler: Function = prototype[methodName];
const meta: T = Reflect.getMetadata(metaKey, handler);

return {
meta,
handler,
provider,
methodName
};
}
32 changes: 21 additions & 11 deletions packages/common/src/discovery/discovery.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { Injectable, Module, ReflectMetadata } from '@nestjs/common';
import { Test, TestingModule } from '@nestjs/testing';
import { DiscoveryModule, DiscoveryService, providerWithMetaKey } from '.';
import { handlerWithMetaKey } from './discovery.service';

const ExampleClassSymbol = Symbol('ExampleClassSymbol');

Expand All @@ -16,8 +15,8 @@ const ExampleMethodDecorator = (config: any) => (target, key, descriptor) =>
@Injectable()
@ExampleClassDecorator('class')
class ExampleService {
@ExampleMethodDecorator('method')
method() {}
@ExampleMethodDecorator('example method meta')
specialMethod() {}

anotherMethod() {}
}
Expand All @@ -38,25 +37,36 @@ describe('Discovery', () => {
await app.init();
});

it('should discover providers based on metadata', () => {
it('should discover providers based on a metadata key', () => {
const discoveryService = app.get<DiscoveryService>(DiscoveryService);

const testProviders = discoveryService.discoverProviders(
const providers = discoveryService.discoverProviders(
providerWithMetaKey(ExampleClassSymbol)
);

expect(testProviders).toHaveLength(1);
console.log(testProviders[0].instance);
expect(providers).toHaveLength(1);
const [provider] = providers;
expect(provider.metatype).toBe(ExampleService);
expect(provider.instance).toBeInstanceOf(ExampleService);
});

it('should discover method handlers based on a predicate', () => {
it('should discover method handler meta based on a metadata key', () => {
const discoveryService = app.get<DiscoveryService>(DiscoveryService);

const handlers = discoveryService.discoverHandlers(
const handlerMeta = discoveryService.discoverHandlersWithMeta(
injectable => true,
handlerWithMetaKey(ExampleMethodSymbol)
ExampleMethodSymbol
);

console.log(handlers);
expect(handlerMeta.length).toBe(1);

const meta = handlerMeta[0];

expect(meta).toMatchObject({
meta: 'example method meta',
methodName: 'specialMethod'
});

expect(meta.provider).toBeInstanceOf(ExampleService);
});
});
1 change: 1 addition & 0 deletions packages/common/src/discovery/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './discovery.interfaces';
export * from './discovery.module';
export * from './discovery.service';
2 changes: 2 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
"declaration": true,
"noImplicitAny": false,
"removeComments": false,
"strict": true,
"strictNullChecks": true,
"noLib": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
Expand Down

0 comments on commit d899e3d

Please sign in to comment.