Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix controller inheritance #339

Merged
merged 8 commits into from
Oct 4, 2021
11 changes: 7 additions & 4 deletions src/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,13 @@ export function httpMethod(

let metadataList: Array<ControllerMethodMetadata> = [];

if (!Reflect.hasMetadata(METADATA_KEY.controllerMethod, target.constructor)) {
if (!Reflect.hasOwnMetadata(METADATA_KEY.controllerMethod, target.constructor)) {
Reflect.defineMetadata(METADATA_KEY.controllerMethod, metadataList, target.constructor);
} else {
metadataList = Reflect.getMetadata(METADATA_KEY.controllerMethod, target.constructor);
metadataList = Reflect.getOwnMetadata(
METADATA_KEY.controllerMethod,
target.constructor,
);
}

metadataList.push(metadata);
Expand Down Expand Up @@ -137,10 +140,10 @@ export function params(type: PARAMETER_TYPE, parameterName?: string) {
parameterName,
type,
};
if (!Reflect.hasMetadata(METADATA_KEY.controllerParameter, target.constructor)) {
if (!Reflect.hasOwnMetadata(METADATA_KEY.controllerParameter, target.constructor)) {
parameterMetadataList.unshift(parameterMetadata);
} else {
metadataList = Reflect.getMetadata(
metadataList = Reflect.getOwnMetadata(
METADATA_KEY.controllerParameter,
target.constructor,
);
Expand Down
24 changes: 21 additions & 3 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export function getControllersFromMetadata(): Array<new() => Controller> {
}

export function getControllerMetadata(constructor: any): ControllerMetadata {
const controllerMetadata: ControllerMetadata = Reflect.getMetadata(
const controllerMetadata: ControllerMetadata = Reflect.getOwnMetadata(
METADATA_KEY.controller,
constructor,
);
Expand All @@ -40,20 +40,38 @@ export function getControllerMetadata(constructor: any): ControllerMetadata {
export function getControllerMethodMetadata(
constructor: any,
): Array<ControllerMethodMetadata> {
const methodMetadata: Array<ControllerMethodMetadata> = Reflect.getMetadata(
const methodMetadata: Array<ControllerMethodMetadata> = Reflect.getOwnMetadata(
METADATA_KEY.controllerMethod,
constructor,
);
const genericMetadata = Reflect.getMetadata(
METADATA_KEY.controllerMethod,
Reflect.getPrototypeOf(constructor) as any,
);
if (genericMetadata !== undefined && methodMetadata !== undefined) {
return methodMetadata.concat(genericMetadata);
} if (genericMetadata !== undefined) {
return genericMetadata;
}
return methodMetadata;
}

export function getControllerParameterMetadata(
constructor: any,
): ControllerParameterMetadata {
const parameterMetadata: ControllerParameterMetadata = Reflect.getMetadata(
const parameterMetadata: ControllerParameterMetadata = Reflect.getOwnMetadata(
METADATA_KEY.controllerParameter,
constructor,
);
const genericMetadata: ControllerParameterMetadata = Reflect.getMetadata(
METADATA_KEY.controllerParameter,
Reflect.getPrototypeOf(constructor) as any,
);
if (genericMetadata !== undefined && parameterMetadata !== undefined) {
return {...parameterMetadata, ...genericMetadata};
} if (genericMetadata !== undefined) {
return genericMetadata;
}
return parameterMetadata;
}

Expand Down
53 changes: 51 additions & 2 deletions test/fetures/controller_inheritance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
httpDelete, httpPost, httpPut, requestBody,
} from '../../src/decorators';
import {cleanUpMetadata} from '../../src/utils';
import {getRouteInfo} from '../../src';

function getDemoServer() {
interface Movie {
Expand Down Expand Up @@ -65,7 +66,29 @@ function getDemoServer() {
@requestParam('movieId') movieId: string,
@requestParam('actorId') actorId: string,
) {
return {status: `DERIVED DELETE ACTOR! ${ movieId } ${ actorId }`};
return {status: `DERIVED DELETE ACTOR! MOVIECONTROLLER1 ${ movieId } ${ actorId }`};
}
}

@controller('/api/v1/movies2')
class MoviesController2 extends GenericController<Movie> {
@httpDelete('/:movieId2/actors/:actorId2')
public deleteActor(
@requestParam('movieId2') movieId: string,
@requestParam('actorId2') actorId: string,
) {
return {status: `DERIVED DELETE ACTOR! MOVIECONTROLLER2 ${ movieId } ${ actorId }`};
}
}

@controller('/api/v1/movies3')
class MoviesController3 extends GenericController<Movie> {
@httpDelete('/:movieId3/actors/:actorId3')
public deleteActor(
@requestParam('movieId3') movieId: string,
@requestParam('actorId3') actorId: string,
) {
return {status: `DERIVED DELETE ACTOR! MOVIECONTROLLER3 ${ movieId } ${ actorId }`};
}
}

Expand Down Expand Up @@ -164,7 +187,33 @@ describe('Derived controller', () => {
supertest(server).delete(`/api/v1/movies/${ movieId }/actors/${ actorId }`)
.expect(200)
.then(res => {
expect(res.body.status).toEqual(`DERIVED DELETE ACTOR! ${ movieId } ${ actorId }`);
expect(res.body.status).toEqual(`DERIVED DELETE ACTOR! MOVIECONTROLLER1 ${ movieId } ${ actorId }`);
done();
});
});

it('Derived controller 2 can have its own methods', done => {
const server = getDemoServer();
const movieId = 5;
const actorId = 3;

supertest(server).delete(`/api/v1/movies2/${ movieId }/actors/${ actorId }`)
.expect(200)
.then(res => {
expect(res.body.status).toEqual(`DERIVED DELETE ACTOR! MOVIECONTROLLER2 ${ movieId } ${ actorId }`);
done();
});
});

it('Derived controller 3 can have its own methods', done => {
const server = getDemoServer();
const movieId = 5;
const actorId = 3;

supertest(server).delete(`/api/v1/movies3/${ movieId }/actors/${ actorId }`)
.expect(200)
.then(res => {
expect(res.body.status).toEqual(`DERIVED DELETE ACTOR! MOVIECONTROLLER3 ${ movieId } ${ actorId }`);
done();
});
});
Expand Down