Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #10521 from nestjs/feat/add-each-to-resolve-and-get
feat(core): expose each option to get and resolve methods
- Loading branch information
Showing
24 changed files
with
538 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { Test } from '@nestjs/testing'; | ||
import { expect } from 'chai'; | ||
import { MultipleProvidersModule } from '../src/multiple-providers/multiple-providers.module'; | ||
|
||
describe('Multiple providers under the same token ("each" feature)', () => { | ||
describe('get()', () => { | ||
it('should return an array of providers', async () => { | ||
const builder = Test.createTestingModule({ | ||
imports: [MultipleProvidersModule], | ||
}); | ||
const testingModule = await builder.compile(); | ||
|
||
const multiProviderInstances = testingModule.get<string>( | ||
'MULTI_PROVIDER', | ||
{ | ||
each: true, | ||
}, | ||
); | ||
|
||
// @ts-expect-error: make sure "multiProviderInstances" is string[] not string | ||
multiProviderInstances.charAt; | ||
|
||
expect(multiProviderInstances).to.be.eql(['A', 'B', 'C']); | ||
}); | ||
}); | ||
describe('resolve()', () => { | ||
it('should return an array of providers', async () => { | ||
const builder = Test.createTestingModule({ | ||
imports: [MultipleProvidersModule], | ||
}); | ||
const testingModule = await builder.compile(); | ||
|
||
const multiProviderInstances = await testingModule.resolve<string>( | ||
'REQ_SCOPED_MULTI_PROVIDER', | ||
undefined, | ||
{ | ||
each: true, | ||
}, | ||
); | ||
|
||
// @ts-expect-error: make sure "multiProviderInstances" is string[] not string | ||
multiProviderInstances.charAt; | ||
|
||
expect(multiProviderInstances).to.be.eql(['A', 'B', 'C']); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Module, Scope } from '@nestjs/common'; | ||
|
||
@Module({ | ||
providers: [ | ||
{ | ||
provide: 'MULTI_PROVIDER', | ||
useValue: 'A', | ||
}, | ||
{ | ||
provide: 'REQ_SCOPED_MULTI_PROVIDER', | ||
useFactory: () => 'A', | ||
scope: Scope.REQUEST, | ||
}, | ||
], | ||
}) | ||
export class AModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Module, Scope } from '@nestjs/common'; | ||
|
||
@Module({ | ||
providers: [ | ||
{ | ||
provide: 'MULTI_PROVIDER', | ||
useValue: 'B', | ||
}, | ||
{ | ||
provide: 'REQ_SCOPED_MULTI_PROVIDER', | ||
useFactory: () => 'B', | ||
scope: Scope.REQUEST, | ||
}, | ||
], | ||
}) | ||
export class BModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { Module, Scope } from '@nestjs/common'; | ||
|
||
@Module({ | ||
providers: [ | ||
{ | ||
provide: 'MULTI_PROVIDER', | ||
useValue: 'C', | ||
}, | ||
{ | ||
provide: 'REQ_SCOPED_MULTI_PROVIDER', | ||
useFactory: () => 'C', | ||
scope: Scope.REQUEST, | ||
}, | ||
], | ||
}) | ||
export class CModule {} |
9 changes: 9 additions & 0 deletions
9
integration/injector/src/multiple-providers/multiple-providers.module.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { Module } from '@nestjs/common'; | ||
import { AModule } from './a.module'; | ||
import { BModule } from './b.module'; | ||
import { CModule } from './c.module'; | ||
|
||
@Module({ | ||
imports: [AModule, BModule, CModule], | ||
}) | ||
export class MultipleProvidersModule {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
import { Abstract, Scope, Type } from '@nestjs/common'; | ||
import { GetOrResolveOptions } from '@nestjs/common/interfaces'; | ||
import { | ||
InvalidClassScopeException, | ||
UnknownElementException, | ||
} from '../errors/exceptions'; | ||
import { Injector } from './injector'; | ||
import { InstanceLink, InstanceLinksHost } from './instance-links-host'; | ||
import { ContextId } from './instance-wrapper'; | ||
import { Module } from './module'; | ||
|
||
export abstract class AbstractInstanceResolver { | ||
protected abstract instanceLinksHost: InstanceLinksHost; | ||
protected abstract injector: Injector; | ||
|
||
protected abstract get<TInput = any, TResult = TInput>( | ||
typeOrToken: Type<TInput> | Function | string | symbol, | ||
options?: GetOrResolveOptions, | ||
): TResult | Array<TResult>; | ||
|
||
protected find<TInput = any, TResult = TInput>( | ||
typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol, | ||
options: { moduleId?: string; each?: boolean }, | ||
): TResult | Array<TResult> { | ||
const instanceLinkOrArray = this.instanceLinksHost.get<TResult>( | ||
typeOrToken, | ||
options, | ||
); | ||
const pluckInstance = ({ wrapperRef }: InstanceLink) => { | ||
if ( | ||
wrapperRef.scope === Scope.REQUEST || | ||
wrapperRef.scope === Scope.TRANSIENT | ||
) { | ||
throw new InvalidClassScopeException(typeOrToken); | ||
} | ||
return wrapperRef.instance; | ||
}; | ||
if (Array.isArray(instanceLinkOrArray)) { | ||
return instanceLinkOrArray.map(pluckInstance); | ||
} | ||
return pluckInstance(instanceLinkOrArray); | ||
} | ||
|
||
protected async resolvePerContext<TInput = any, TResult = TInput>( | ||
typeOrToken: Type<TInput> | Abstract<TInput> | string | symbol, | ||
contextModule: Module, | ||
contextId: ContextId, | ||
options?: GetOrResolveOptions, | ||
): Promise<TResult | Array<TResult>> { | ||
const instanceLinkOrArray = options?.strict | ||
? this.instanceLinksHost.get(typeOrToken, { | ||
moduleId: contextModule.id, | ||
each: options.each, | ||
}) | ||
: this.instanceLinksHost.get(typeOrToken, { | ||
each: options.each, | ||
}); | ||
|
||
const pluckInstance = async (instanceLink: InstanceLink) => { | ||
const { wrapperRef, collection } = instanceLink; | ||
if (wrapperRef.isDependencyTreeStatic() && !wrapperRef.isTransient) { | ||
return this.get(typeOrToken, { strict: options.strict }); | ||
} | ||
|
||
const ctorHost = wrapperRef.instance || { constructor: typeOrToken }; | ||
const instance = await this.injector.loadPerContext( | ||
ctorHost, | ||
wrapperRef.host, | ||
collection, | ||
contextId, | ||
wrapperRef, | ||
); | ||
if (!instance) { | ||
throw new UnknownElementException(); | ||
} | ||
return instance; | ||
}; | ||
|
||
if (Array.isArray(instanceLinkOrArray)) { | ||
return Promise.all( | ||
instanceLinkOrArray.map(instanceLink => pluckInstance(instanceLink)), | ||
); | ||
} | ||
return pluckInstance(instanceLinkOrArray); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,6 @@ | ||
export * from './container'; | ||
export * from './inquirer'; | ||
export { ContextId, HostComponentInfo } from './instance-wrapper'; | ||
export * from './lazy-module-loader'; | ||
export * from './lazy-module-loader/lazy-module-loader'; | ||
export * from './module-ref'; | ||
export * from './modules-container'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './internal-core-module'; |
16 changes: 8 additions & 8 deletions
16
.../injector/internal-core-module-factory.ts → ...re-module/internal-core-module-factory.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
Oops, something went wrong.