Skip to content

Commit 64bc85a

Browse files
Merge branch 'middleware-order' of https://github.com/underfin/nest into underfin-middleware-order
2 parents e0fd3b8 + fcf5042 commit 64bc85a

4 files changed

Lines changed: 112 additions & 2 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { INestApplication, MiddlewareConsumer, Module } from '@nestjs/common';
2+
import { Test } from '@nestjs/testing';
3+
import * as request from 'supertest';
4+
5+
const RETURN_VALUE_A = 'test_A';
6+
const RETURN_VALUE_B = 'test_B';
7+
8+
@Module({
9+
imports: [],
10+
})
11+
class TestAModule {
12+
configure(consumer: MiddlewareConsumer) {
13+
consumer
14+
.apply((req, res, next) => {
15+
res.send(RETURN_VALUE_A);
16+
})
17+
.forRoutes('hello');
18+
}
19+
}
20+
21+
@Module({
22+
imports: [TestAModule],
23+
})
24+
class TestBModule {
25+
configure(consumer: MiddlewareConsumer) {
26+
consumer
27+
.apply((req, res, next) => {
28+
res.send(RETURN_VALUE_B);
29+
})
30+
.forRoutes('hello');
31+
}
32+
}
33+
34+
@Module({
35+
imports: [TestBModule],
36+
})
37+
class TestModule {
38+
}
39+
40+
describe('Middleware Execute Order', () => {
41+
let app: INestApplication;
42+
43+
beforeEach(async () => {
44+
app = (await Test.createTestingModule({
45+
imports: [TestModule],
46+
}).compile()).createNestApplication();
47+
48+
await app.init();
49+
});
50+
51+
it(`Execute middleware of dependent modules first `, () => {
52+
return request(app.getHttpServer())
53+
.get('/hello')
54+
.expect(200, RETURN_VALUE_A);
55+
});
56+
57+
afterEach(async () => {
58+
await app.close();
59+
});
60+
});

packages/core/injector/module.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ export class Module {
4343
InstanceWrapper<Controller>
4444
>();
4545
private readonly _exports = new Set<string | symbol>();
46+
private _distance: number = 0;
4647

4748
constructor(
4849
private readonly _metatype: Type<any>,
@@ -114,6 +115,17 @@ export class Module {
114115
return this._metatype;
115116
}
116117

118+
get distance(): number {
119+
return this._distance;
120+
}
121+
122+
set distance(distance: number){
123+
this._distance = distance;
124+
Array.from(this._imports)
125+
.filter((module) => !module.imports.has(this))
126+
.forEach((module) => module.distance = distance + 1);
127+
}
128+
117129
public addCoreProviders(container: NestContainer) {
118130
this.addModuleAsProvider();
119131
this.addModuleRef();
@@ -398,8 +410,9 @@ export class Module {
398410
);
399411
}
400412

401-
public addRelatedModule(module: any) {
413+
public addRelatedModule(module: Module) {
402414
this._imports.add(module);
415+
module.distance = this._distance + 1 > module._distance ? this._distance + 1 : module._distance;
403416
}
404417

405418
public replace(toReplace: string | symbol | Type<any>, options: any) {

packages/core/middleware/middleware-module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,9 @@ export class MiddlewareModule {
110110
});
111111

112112
await Promise.all(
113-
[...configs.entries()].map(async ([module, moduleConfigs]) => {
113+
[...configs.entries()].sort(([moduleA, moduleAConfigs], [moduleB, moduleBConfigs]) => {
114+
return this.container.getModuleByKey(moduleB).distance - this.container.getModuleByKey(moduleA).distance;
115+
}).map(async ([module, moduleConfigs]) => {
114116
await Promise.all(registerAllConfigs(module, [...moduleConfigs]));
115117
}),
116118
);

packages/core/test/injector/module.spec.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -481,4 +481,39 @@ describe('Module', () => {
481481
});
482482
});
483483
});
484+
485+
describe('getter "distance"', () => {
486+
@ModuleDecorator({})
487+
class ModuleA {}
488+
489+
@ModuleDecorator({})
490+
class ModuleB {}
491+
492+
@ModuleDecorator({})
493+
class ModuleC {}
494+
495+
let moduleA, moduleB, moduleC;
496+
beforeEach(() => {
497+
moduleA = new Module(ModuleA as any, [], container);
498+
moduleB = new Module(ModuleB as any, [], container);
499+
moduleC = new Module(ModuleC as any, [], container);
500+
});
501+
502+
it('should get "distance" correct', () => {
503+
moduleA.addRelatedModule(moduleB);
504+
moduleC.addRelatedModule(moduleB);
505+
moduleA.addRelatedModule(moduleC);
506+
507+
expect(moduleA.distance).to.be.equal(0);
508+
expect(moduleB.distance).to.be.equal(2);
509+
expect(moduleC.distance).to.be.equal(1);
510+
});
511+
512+
it('should don`t throw exception when circular dependency', () => {
513+
expect(() => {
514+
moduleA.addRelatedModule(moduleB);
515+
moduleB.addRelatedModule(moduleA);
516+
}).to.not.throw;
517+
});
518+
});
484519
});

0 commit comments

Comments
 (0)