Skip to content

Commit 571049c

Browse files
fix(core): fix invalid transient & request-scoped behavior nestjs#3303
1 parent e69b0f6 commit 571049c

4 files changed

Lines changed: 46 additions & 36 deletions

File tree

integration/scopes/e2e/transient-scope.spec.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,16 +62,16 @@ describe('Transient scope', () => {
6262
expect(Meta.COUNTER).to.be.eql(7);
6363
});
6464

65-
it(`should create transient pipe for each controller`, async () => {
66-
expect(UserByIdPipe.COUNTER).to.be.eql(2);
65+
it(`should create transient pipe for each controller (3 requests, 1 static)`, async () => {
66+
expect(UserByIdPipe.COUNTER).to.be.eql(4);
6767
});
6868

69-
it(`should create transient interceptor for each controller`, async () => {
70-
expect(Interceptor.COUNTER).to.be.eql(2);
69+
it(`should create transient interceptor for each controller (3 requests, 1 static)`, async () => {
70+
expect(Interceptor.COUNTER).to.be.eql(4);
7171
});
7272

73-
it(`should create transient guard for each controller`, async () => {
74-
expect(Guard.COUNTER).to.be.eql(2);
73+
it(`should create transient guard for each controller (3 requests, 1 static)`, async () => {
74+
expect(Guard.COUNTER).to.be.eql(4);
7575
});
7676
});
7777

packages/core/injector/injector.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
isFunction,
1313
isNil,
1414
isObject,
15+
isString,
1516
isUndefined,
1617
} from '@nestjs/common/utils/shared.utils';
1718
import { RuntimeException } from '../errors/exceptions/runtime.exception';
@@ -242,7 +243,7 @@ export class Injector {
242243
: [];
243244

244245
let isResolved = true;
245-
const resolveParam = async (param, index) => {
246+
const resolveParam = async (param: unknown, index: number) => {
246247
try {
247248
const paramWrapper = await this.resolveSingleParam<T>(
248249
wrapper,
@@ -251,6 +252,7 @@ export class Injector {
251252
module,
252253
contextId,
253254
inquirer,
255+
index,
254256
);
255257
const instanceHost = paramWrapper.getInstanceByContextId(
256258
contextId,
@@ -259,7 +261,6 @@ export class Injector {
259261
if (!instanceHost.isResolved && !paramWrapper.forwardRef) {
260262
isResolved = false;
261263
}
262-
wrapper.addCtorMetadata(index, paramWrapper);
263264
return instanceHost && instanceHost.instance;
264265
} catch (err) {
265266
const isOptional = optionalDependenciesIds.includes(index);
@@ -296,6 +297,7 @@ export class Injector {
296297
module: Module,
297298
contextId = STATIC_CONTEXT,
298299
inquirer?: InstanceWrapper,
300+
keyOrIndex?: string | number,
299301
) {
300302
if (isUndefined(param)) {
301303
throw new UndefinedDependencyException(
@@ -312,6 +314,7 @@ export class Injector {
312314
wrapper,
313315
contextId,
314316
inquirer,
317+
keyOrIndex,
315318
);
316319
}
317320

@@ -333,6 +336,7 @@ export class Injector {
333336
wrapper: InstanceWrapper<T>,
334337
contextId = STATIC_CONTEXT,
335338
inquirer?: InstanceWrapper,
339+
keyOrIndex?: string | number,
336340
): Promise<InstanceWrapper> {
337341
const providers = module.providers;
338342
const instanceWrapper = await this.lookupComponent(
@@ -343,6 +347,10 @@ export class Injector {
343347
contextId,
344348
inquirer,
345349
);
350+
isString(keyOrIndex)
351+
? wrapper.addPropertiesMetadata(keyOrIndex, instanceWrapper)
352+
: wrapper.addCtorMetadata(keyOrIndex, instanceWrapper);
353+
346354
return this.resolveComponentHost(
347355
module,
348356
instanceWrapper,
@@ -535,12 +543,11 @@ export class Injector {
535543
module,
536544
contextId,
537545
inquirer,
546+
item.key,
538547
);
539548
if (!paramWrapper) {
540549
return undefined;
541550
}
542-
wrapper.addPropertiesMetadata(item.key, paramWrapper);
543-
544551
const inquirerId = this.getInquirerId(inquirer);
545552
const instanceHost = paramWrapper.getInstanceByContextId(
546553
contextId,

packages/core/injector/instance-wrapper.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ export class InstanceWrapper<T = any> {
263263
inquirer: InstanceWrapper | undefined,
264264
): boolean {
265265
const isInquirerRequestScoped =
266-
inquirer && inquirer.scope === Scope.REQUEST;
266+
inquirer && !inquirer.isDependencyTreeStatic();
267267

268268
return (
269269
this.isDependencyTreeStatic() &&
@@ -278,7 +278,7 @@ export class InstanceWrapper<T = any> {
278278
inquirer: InstanceWrapper | undefined,
279279
): boolean {
280280
const isInquirerRequestScoped =
281-
inquirer && inquirer.scope === Scope.REQUEST;
281+
inquirer && !inquirer.isDependencyTreeStatic();
282282
const isStaticTransient = this.isTransient && !isInquirerRequestScoped;
283283

284284
return (

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

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -526,81 +526,84 @@ describe('Injector', () => {
526526

527527
describe('when instanceWrapper is not resolved and does not have forward ref', () => {
528528
it('should call loadProvider', async () => {
529+
const wrapper = new InstanceWrapper({ isResolved: false });
530+
529531
const loadStub = sinon
530532
.stub(injector, 'loadProvider')
531533
.callsFake(() => null);
532534
sinon
533535
.stub(injector, 'lookupComponent')
534-
.returns(Promise.resolve(new InstanceWrapper({ isResolved: false })));
536+
.returns(Promise.resolve(wrapper));
535537

536538
await injector.resolveComponentInstance(
537539
module,
538540
'',
539541
{ index: 0, dependencies: [] },
540-
{} as any,
542+
wrapper,
541543
);
542544
expect(loadStub.called).to.be.true;
543545
});
544546
it('should not call loadProvider (isResolved)', async () => {
547+
const wrapper = new InstanceWrapper({ isResolved: true });
545548
const loadStub = sinon
546549
.stub(injector, 'loadProvider')
547550
.callsFake(() => null);
551+
548552
sinon
549553
.stub(injector, 'lookupComponent')
550-
.returns(Promise.resolve(new InstanceWrapper({ isResolved: true })));
554+
.returns(Promise.resolve(wrapper));
551555

552556
await injector.resolveComponentInstance(
553557
module,
554558
'',
555559
{ index: 0, dependencies: [] },
556-
{} as any,
560+
wrapper,
557561
);
558562
expect(loadStub.called).to.be.false;
559563
});
560564
it('should not call loadProvider (forwardRef)', async () => {
565+
const wrapper = new InstanceWrapper({
566+
isResolved: false,
567+
forwardRef: true,
568+
});
561569
const loadStub = sinon
562570
.stub(injector, 'loadProvider')
563571
.callsFake(() => null);
572+
564573
sinon
565574
.stub(injector, 'lookupComponent')
566-
.returns(
567-
Promise.resolve(
568-
new InstanceWrapper({ isResolved: false, forwardRef: true }),
569-
),
570-
);
575+
.returns(Promise.resolve(wrapper));
571576

572577
await injector.resolveComponentInstance(
573578
module,
574579
'',
575580
{ index: 0, dependencies: [] },
576-
{} as any,
581+
wrapper,
577582
);
578583
expect(loadStub.called).to.be.false;
579584
});
580585
});
581586

582587
describe('when instanceWraper has async property', () => {
583588
it('should await instance', async () => {
584-
const loadStub = sinon
585-
.stub(injector, 'loadProvider')
586-
.callsFake(() => null);
589+
sinon.stub(injector, 'loadProvider').callsFake(() => null);
587590

588591
const instance = Promise.resolve(true);
589-
sinon.stub(injector, 'lookupComponent').returns(
590-
Promise.resolve(
591-
new InstanceWrapper({
592-
isResolved: false,
593-
forwardRef: true,
594-
async: true,
595-
instance,
596-
}),
597-
),
598-
);
592+
const wrapper = new InstanceWrapper({
593+
isResolved: false,
594+
forwardRef: true,
595+
async: true,
596+
instance,
597+
});
598+
sinon
599+
.stub(injector, 'lookupComponent')
600+
.returns(Promise.resolve(wrapper));
601+
599602
const result = await injector.resolveComponentInstance(
600603
module,
601604
'',
602605
{ index: 0, dependencies: [] },
603-
{} as any,
606+
wrapper,
604607
);
605608
expect(result.instance).to.be.true;
606609
});

0 commit comments

Comments
 (0)