diff --git a/src/container-instance.class.ts b/src/container-instance.class.ts index a2ee63a8..b1053c1d 100644 --- a/src/container-instance.class.ts +++ b/src/container-instance.class.ts @@ -46,6 +46,11 @@ export const enum ServiceIdentifierLocation { None = 'none', } +export const enum EagerLoadingStrategy { + Enabled, + Disabled +} + interface ManyServicesMetadata { tokens: Token[]; scope: ContainerScope; @@ -82,6 +87,18 @@ export class ContainerInstance implements Disposable { */ public static readonly defaultContainer = new ContainerInstance('default'); + /** + * The eager loading strategy for use for this container. + * + * If this is set to `Enabled`, then eager loading will take place. + * However, if this is `Disabled`, it shall not. + * + * @remarks + * It should generally be noted that, before any eager services are + * imported, this should be set to enabled to ensure expected behaviour. + */ + private eagerLoadingStrategy = EagerLoadingStrategy.Enabled; + /** * Create a ContainerInstance. * @@ -515,7 +532,11 @@ export class ContainerInstance implements Disposable { * when the service is also marked as transient. In that case we ignore * the eager flag to prevent creating a service what cannot be disposed later. */ - if (newMetadata.eager && newMetadata.scope !== 'transient') { + if ( + newMetadata.eager && + newMetadata.scope !== 'transient' && + this.eagerLoadingStrategy === EagerLoadingStrategy.Enabled + ) { this.get(newMetadata.id); } @@ -631,7 +652,9 @@ export class ContainerInstance implements Disposable { * @throws Error * This exception is thrown if the container has been disposed. */ - public reset(options: { strategy: 'resetValue' | 'resetServices' } = { strategy: 'resetValue' }): this { + public reset( + options: { strategy: 'resetValue' | 'resetServices' | 'clearServices' } = { strategy: 'resetValue' } + ): this { this[THROW_IF_DISPOSED](); switch (options.strategy) { @@ -643,6 +666,9 @@ export class ContainerInstance implements Disposable { this.metadataMap.clear(); this.multiServiceIds.clear(); break; + case 'clearServices': + this.metadataMap.clear(); + this.multiServiceIds.clear(); default: throw new Error('Received invalid reset strategy.'); } @@ -912,6 +938,29 @@ export class ContainerInstance implements Disposable { } } + /** + * Enable eager loading of services for this container. + * @experimental + *
+ * + * __Note: Ensure this is set before importing any eager services.__ + * + * @remarks + * Eager loading is generally discouraged, as it makes testing harder + * and makes the application more confusing to work with. + * For instance, see [typestack/typedi#380](https://github.com/typestack/typedi/issues/380). + * + * Consider an example of a DatabaseService with eager loading enabled. + * Once imported, database connections and more will immediately start taking place. + * In many cases, this will be unexpected and will ultimately be an unwanted side effect. + * + * Therefore, we place the eager loading functionality behind a toggleable option, + * which must be enabled prior to any eager loading strategies taking place. + */ + public enableEagerLoading () { + this.eagerLoadingStrategy = EagerLoadingStrategy.Enabled; + } + /** Iterate over each service in the container. */ public [Symbol.iterator](): IterableIterator<[ServiceIdentifier, ServiceMetadata]> { return this.metadataMap.entries();