Skip to content
This repository has been archived by the owner on May 8, 2020. It is now read-only.

Commit

Permalink
refactor(middleware):Refactor middleware to use common __metadata store
Browse files Browse the repository at this point in the history
  • Loading branch information
zakhenry committed Jul 6, 2016
1 parent 66d1916 commit c205ade
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 49 deletions.
11 changes: 7 additions & 4 deletions src/common/metadata/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@
/** End Typedoc Module Declaration */
import { TableOptions } from 'typeorm/decorator/options/TableOptions';
import { RelationType, Relation } from '../models/relations/index';
import { RegistryEntityConstructor } from '../registry/entityRegistry';
import {
RegistryEntityConstructor, EntityMetadata,
RegistryEntityStatic
} from '../registry/entityRegistry';
import { ColumnOptions } from 'typeorm/decorator/options/ColumnOptions';
import { MiddlewareRegistry } from '../../server/controllers/abstract.controller';

Expand Down Expand Up @@ -37,8 +40,8 @@ export interface ControllerMetadata {
* Common function used by many methods to ensure the entity has __metadata initialized on it's constructor
* @param target
*/
export function initializeMetadata(target: RegistryEntityConstructor<any>) {
if (!target.constructor.__metadata) {
target.constructor.__metadata = {};
export function initializeMetadata(target: RegistryEntityStatic<EntityMetadata>) {
if (!target.__metadata) {
target.__metadata = {};
}
}
2 changes: 1 addition & 1 deletion src/common/models/types/storedProperty.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export function StoredProperty(options?: ColumnOptions): PropertyDecorator {

return function storedProperty(target: ModelConstructor<any>, propertyKey: string): void {

initializeMetadata(target);
initializeMetadata(target.constructor);

if (!target.constructor.__metadata.storedProperties) {
target.constructor.__metadata.storedProperties = new Map();
Expand Down
2 changes: 1 addition & 1 deletion src/common/models/types/timestamp.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { initializeMetadata } from '../../metadata/metadata';
* @param target
*/
function initTimestamps(target: ModelConstructor<any>) {
initializeMetadata(target);
initializeMetadata(target.constructor);

if (!target.constructor.__metadata.timestamps) {
target.constructor.__metadata.timestamps = {};
Expand Down
2 changes: 1 addition & 1 deletion src/common/registry/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ModelMetadata, ControllerMetadata } from '../metadata/metadata';
*/
function entityRegistryFunction(type: EntityType, metadata?: EntityMetadata): ClassDecorator {
return function <TFunction extends Function>(target: TFunction): void {
registry.register(type, target.prototype.constructor, metadata);
registry.register(type, target, metadata);
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/common/registry/entityRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export class RegistryEntity<M> {
if (metadata || !this.__metadataDefault){
return metadata;
}
console.log('returning default');

return this.__metadataDefault;
}

Expand Down Expand Up @@ -87,7 +87,7 @@ export class EntityRegistry {
let typeRegistry = this.registry.get(type);

if (metadata){
initializeMetadata(entity.prototype);
initializeMetadata(entity);
_.merge(entity.__metadata, metadata);
}

Expand Down
66 changes: 43 additions & 23 deletions src/server/controllers/abstract.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
RegistryEntityStatic,
RegistryEntityConstructor, RegistryEntity
} from '../../common/registry/entityRegistry';
import { ModelMetadata, ControllerMetadata } from '../../common/metadata/metadata';
import {
ModelMetadata, ControllerMetadata,
initializeMetadata
} from '../../common/metadata/metadata';

export interface MethodDefinition {
method: HttpMethod;
Expand All @@ -33,9 +36,19 @@ export interface MethodDictionary {

export type MiddlewareLocation = 'before' | 'after';

export interface ControllerConstructor<T extends AbstractController> extends Function {
constructor: ControllerStatic<T>;
}

export interface ControllerStatic<T extends AbstractController> extends RegistryEntityStatic<ControllerMetadata> {
new(server: Server, logger: Logger): T;
prototype: T;
registerMiddleware(location: MiddlewareLocation, middlewareFactories: InjectableMiddlewareFactory[], methodSignature?: string): void;
}

/**
* Abstract controller that all controllers *must* extend from. The [[ControllerBootstrapper]] relies
* on the interface provided by this class to invoke registration of routes and middleware
* Abstract controller that all controllers *must* extend from. The [[ControllerBootstrapper]]
* relies on the interface provided by this class to invoke registration of routes and middleware
*/
@Injectable()
export abstract class AbstractController extends RegistryEntity<ControllerMetadata> {
Expand All @@ -45,10 +58,6 @@ export abstract class AbstractController extends RegistryEntity<ControllerMetada
};

protected actionMethods: Map<string, MethodDefinition>;
public registeredMiddleware: {
methods: Map<string, MiddlewareRegistry>
all: MiddlewareRegistry
};

/** Current controller instance */
protected logger: Logger;
Expand Down Expand Up @@ -98,26 +107,30 @@ export abstract class AbstractController extends RegistryEntity<ControllerMetada
* @param location
* @param middlewareFactories
* @param methodSignature
* @returns {AbstractController}
* @returns void
*/
public registerMiddleware(location: MiddlewareLocation, middlewareFactories: InjectableMiddlewareFactory[], methodSignature: string): this {
public static registerMiddleware(location: MiddlewareLocation, middlewareFactories: InjectableMiddlewareFactory[], methodSignature?: string): void {

initializeMiddlewareRegister(this);

let current: MiddlewareRegistry = this.registeredMiddleware.methods.get(methodSignature);
const middleware = (this.getMetadata() as ControllerMetadata).middleware;
if (methodSignature) {
let current: MiddlewareRegistry = middleware.methods.get(methodSignature);

if (!current) {
current = {
before: [],
after: []
};
if (!current) {
current = {
before: [],
after: []
};

this.registeredMiddleware.methods.set(methodSignature, current);
}
middleware.methods.set(methodSignature, current);
}

current[location].push(...middlewareFactories);
current[location].push(...middlewareFactories);
} else {
middleware.all[location].push(...middlewareFactories);
}

return this;
}

/**
Expand All @@ -132,13 +145,20 @@ export abstract class AbstractController extends RegistryEntity<ControllerMetada

callStack.push(this[methodSignature]);

if (this.registeredMiddleware) {
const methodMiddlewareFactories = this.registeredMiddleware.methods.get(methodSignature);
if (this.getMetadata().middleware) {
const methodMiddlewareFactories = this.getMetadata()
.middleware
.methods
.get(methodSignature);

//wrap method registered factories with the class defined ones [beforeAll, before, after,
// afterAll]
const beforeMiddleware = this.registeredMiddleware.all.before.concat(methodMiddlewareFactories.before);
const afterMiddleware = methodMiddlewareFactories.after.concat(this.registeredMiddleware.all.after);
const beforeMiddleware = this.getMetadata()
.middleware
.all
.before
.concat(methodMiddlewareFactories.before);
const afterMiddleware = methodMiddlewareFactories.after.concat(this.getMetadata().middleware.all.after);

if (methodMiddlewareFactories) {
callStack.unshift(...beforeMiddleware.map((middleware: MiddlewareFactory) => middleware(this.injector)));
Expand Down
35 changes: 21 additions & 14 deletions src/server/middleware/middleware.decorator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,16 @@
* @module server
*/
/** End Typedoc Module Declaration */
import { AbstractController, MiddlewareRegistry } from '../controllers/abstract.controller';
import {
AbstractController, MiddlewareRegistry,
ControllerConstructor, ControllerStatic
} from '../controllers/abstract.controller';
import { MiddlewareFactory } from './index';
import { initializeMetadata, ControllerMetadata } from '../../common/metadata/metadata';
import {
RegistryEntityStatic,
RegistryEntityConstructor
} from '../../common/registry/entityRegistry';

/**
* Decorator for assigning before middleware method in a controller
Expand All @@ -13,9 +21,9 @@ import { MiddlewareFactory } from './index';
*/
export function Before<T>(...middlewareFactories: MiddlewareFactory[]): MethodDecorator {

return function (target: AbstractController, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {
return function (target: ControllerConstructor<any>, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {

target.registerMiddleware('before', middlewareFactories, propertyKey);
target.constructor.registerMiddleware('before', middlewareFactories, propertyKey);
};
}

Expand All @@ -27,19 +35,20 @@ export function Before<T>(...middlewareFactories: MiddlewareFactory[]): MethodDe
*/
export function After<T>(...middlewareFactories: MiddlewareFactory[]): MethodDecorator {

return function (target: AbstractController, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {
return function (target: ControllerConstructor<any>, propertyKey: string, descriptor: TypedPropertyDescriptor<T>) {

target.registerMiddleware('after', middlewareFactories, propertyKey);
target.constructor.registerMiddleware('after', middlewareFactories, propertyKey);
};
}

/**
* Initializes the `registeredMiddleware` property on the controller with empty stores
* @param target
*/
export function initializeMiddlewareRegister(target: AbstractController): void {
if (!target.registeredMiddleware) {
target.registeredMiddleware = {
export function initializeMiddlewareRegister(target: RegistryEntityStatic<ControllerMetadata>): void {
initializeMetadata(target);
if (!target.__metadata.middleware) {
target.__metadata.middleware = {
methods: new Map<string, MiddlewareRegistry>(),
all: {
before: [],
Expand All @@ -56,9 +65,8 @@ export function initializeMiddlewareRegister(target: AbstractController): void {
* @constructor
*/
export function BeforeAll(...middlewareFactories: MiddlewareFactory[]): ClassDecorator {
return function (target: Function): void {
initializeMiddlewareRegister(target.prototype);
target.prototype.registeredMiddleware.all.before = middlewareFactories;
return function (target: ControllerStatic<any>): void {
target.registerMiddleware('before', middlewareFactories);
}
}

Expand All @@ -69,8 +77,7 @@ export function BeforeAll(...middlewareFactories: MiddlewareFactory[]): ClassDec
* @constructor
*/
export function AfterAll(...middlewareFactories: MiddlewareFactory[]): ClassDecorator {
return function (target: Function): void {
initializeMiddlewareRegister(target.prototype);
target.prototype.registeredMiddleware.all.after = middlewareFactories;
return function (target: ControllerStatic<any>): void {
target.registerMiddleware('after', middlewareFactories);
}
}
6 changes: 3 additions & 3 deletions src/server/middleware/middleware.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@ describe('Middleware Decorators', () => {
controller = c.registerRoutes()
.registerInjector(i);

expect(controller.registeredMiddleware)
expect(controller.getMetadata().middleware)
.not
.toBeNull();
expect(controller.registeredMiddleware.all.before.length)
expect(controller.getMetadata().middleware.all.before.length)
.toEqual(2);
expect(controller.registeredMiddleware.all.after.length)
expect(controller.getMetadata().middleware.all.after.length)
.toEqual(1);
}));

Expand Down

0 comments on commit c205ade

Please sign in to comment.