You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
lib/src/di/factory/ConfiguredSingletonFactory.ts

85 lines
2.8 KiB

import {AbstractFactory} from './AbstractFactory'
import {Inject, Injectable} from '../decorator/injection'
import {Logging} from '../../service/Logging'
import {Config} from '../../service/Config'
import {
DEPENDENCY_KEYS_METADATA_KEY,
DependencyRequirement,
Instantiable,
isInstantiable,
PropertyDependency,
} from '../types'
import {Collection, ErrorWithContext, Maybe} from '../../util'
import 'reflect-metadata'
@Injectable()
export abstract class ConfiguredSingletonFactory<T> extends AbstractFactory<T> {
protected static loggedDefaultImplementationWarningOnce = false
@Inject()
protected readonly logging!: Logging
@Inject()
protected readonly config!: Config
constructor() {
super({})
}
protected abstract getConfigKey(): string
protected abstract getDefaultImplementation(): Instantiable<T>
protected abstract getAbstractImplementation(): any
protected getDefaultImplementationWarning(): Maybe<string> {
return undefined
}
produce(dependencies: any[], parameters: any[]): T {
return new (this.getImplementation())(...dependencies, ...parameters)
}
match(something: unknown): boolean {
return something === this.getAbstractImplementation()
}
getDependencyKeys(): Collection<DependencyRequirement> {
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getImplementation())
if ( meta ) {
return meta
}
return new Collection<DependencyRequirement>()
}
getInjectedProperties(): Collection<PropertyDependency> {
return this.getInjectedPropertiesForPrototypeChain(this.getImplementation())
}
protected getImplementation(): Instantiable<T> {
const ctor = this.constructor as typeof ConfiguredSingletonFactory
const ImplementationClass = this.config.get(this.getConfigKey(), this.getDefaultImplementation())
if ( ImplementationClass === this.getDefaultImplementation() ) {
const warning = this.getDefaultImplementationWarning()
if ( warning && !ctor.loggedDefaultImplementationWarningOnce ) {
this.logging.warn(warning)
ctor.loggedDefaultImplementationWarningOnce = true
}
}
if (
!isInstantiable(ImplementationClass)
|| !(ImplementationClass.prototype instanceof this.getAbstractImplementation())
) {
throw new ErrorWithContext('Configured service clas does not properly extend from implementation base class.', {
configKey: this.getConfigKey(),
class: `${ImplementationClass}`,
mustExtendBase: `${this.getAbstractImplementation()}`,
})
}
return ImplementationClass as Instantiable<T>
}
}