Centralize configure-able factory classes
This commit is contained in:
parent
5557aae543
commit
c0595f3ef9
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@extollo/lib",
|
"name": "@extollo/lib",
|
||||||
"version": "0.14.4",
|
"version": "0.14.5",
|
||||||
"description": "The framework library that lifts up your code.",
|
"description": "The framework library that lifts up your code.",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"types": "lib/index.d.ts",
|
"types": "lib/index.d.ts",
|
||||||
|
@ -1,73 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../di'
|
||||||
AbstractFactory,
|
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable, FactoryProducer, getPropertyInjectionMetadata,
|
|
||||||
} from '../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../util'
|
|
||||||
import {Config} from '../../service/Config'
|
|
||||||
import {AuthenticatableRepository} from '../types'
|
import {AuthenticatableRepository} from '../types'
|
||||||
import {ORMUserRepository} from './orm/ORMUserRepository'
|
import {ORMUserRepository} from './orm/ORMUserRepository'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection factory that matches the abstract ClientRepository class
|
* A dependency injection factory that matches the abstract ClientRepository class
|
||||||
* and produces an instance of the configured repository driver implementation.
|
* and produces an instance of the configured repository driver implementation.
|
||||||
*/
|
*/
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class AuthenticatableRepositoryFactory extends AbstractFactory<AuthenticatableRepository> {
|
export class AuthenticatableRepositoryFactory extends ConfiguredSingletonFactory<AuthenticatableRepository> {
|
||||||
protected get config(): Config {
|
protected getConfigKey(): string {
|
||||||
return Container.getContainer().make<Config>(Config)
|
return 'auth.storage'
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): AuthenticatableRepository {
|
protected getDefaultImplementation(): Instantiable<AuthenticatableRepository> {
|
||||||
return new (this.getAuthenticatableRepositoryClass())()
|
return ORMUserRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === AuthenticatableRepository
|
return AuthenticatableRepository
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getAuthenticatableRepositoryClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getAuthenticatableRepositoryClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured user repository backend.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
protected getAuthenticatableRepositoryClass(): Instantiable<AuthenticatableRepository> {
|
|
||||||
const AuthenticatableRepositoryClass = this.config.get('auth.storage', ORMUserRepository)
|
|
||||||
|
|
||||||
if ( !isInstantiable(AuthenticatableRepositoryClass) || !(AuthenticatableRepositoryClass.prototype instanceof AuthenticatableRepository) ) {
|
|
||||||
const e = new ErrorWithContext('Provided client repository class does not extend from @extollo/lib.AuthenticatableRepository')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'auth.storage',
|
|
||||||
class: AuthenticatableRepositoryClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return AuthenticatableRepositoryClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../../di'
|
||||||
AbstractFactory,
|
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable, FactoryProducer, getPropertyInjectionMetadata,
|
|
||||||
} from '../../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../../util'
|
|
||||||
import {Config} from '../../../service/Config'
|
|
||||||
import {ClientRepository} from '../types'
|
import {ClientRepository} from '../types'
|
||||||
import {ConfigClientRepository} from './ConfigClientRepository'
|
import {ConfigClientRepository} from './ConfigClientRepository'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection factory that matches the abstract ClientRepository class
|
* A dependency injection factory that matches the abstract ClientRepository class
|
||||||
* and produces an instance of the configured repository driver implementation.
|
* and produces an instance of the configured repository driver implementation.
|
||||||
*/
|
*/
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class ClientRepositoryFactory extends AbstractFactory<ClientRepository> {
|
export class ClientRepositoryFactory extends ConfiguredSingletonFactory<ClientRepository> {
|
||||||
protected get config(): Config {
|
protected getConfigKey(): string {
|
||||||
return Container.getContainer().make<Config>(Config)
|
return 'oauth2.repository.client'
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): ClientRepository {
|
protected getDefaultImplementation(): Instantiable<ClientRepository> {
|
||||||
return new (this.getClientRepositoryClass())()
|
return ConfigClientRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === ClientRepository
|
return ClientRepository
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getClientRepositoryClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getClientRepositoryClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured client repository backend.
|
|
||||||
* @protected
|
|
||||||
* @return Instantiable<ClientRepository>
|
|
||||||
*/
|
|
||||||
protected getClientRepositoryClass(): Instantiable<ClientRepository> {
|
|
||||||
const ClientRepositoryClass = this.config.get('oauth2.repository.client', ConfigClientRepository)
|
|
||||||
|
|
||||||
if ( !isInstantiable(ClientRepositoryClass) || !(ClientRepositoryClass.prototype instanceof ClientRepository) ) {
|
|
||||||
const e = new ErrorWithContext('Provided client repository class does not extend from @extollo/lib.ClientRepository')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'oauth2.repository.client',
|
|
||||||
class: ClientRepositoryClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ClientRepositoryClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../../di'
|
||||||
AbstractFactory,
|
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable, FactoryProducer, getPropertyInjectionMetadata,
|
|
||||||
} from '../../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../../util'
|
|
||||||
import {Config} from '../../../service/Config'
|
|
||||||
import {RedemptionCodeRepository} from '../types'
|
import {RedemptionCodeRepository} from '../types'
|
||||||
import {CacheRedemptionCodeRepository} from './CacheRedemptionCodeRepository'
|
import {CacheRedemptionCodeRepository} from './CacheRedemptionCodeRepository'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection factory that matches the abstract RedemptionCodeRepository class
|
* A dependency injection factory that matches the abstract RedemptionCodeRepository class
|
||||||
* and produces an instance of the configured repository driver implementation.
|
* and produces an instance of the configured repository driver implementation.
|
||||||
*/
|
*/
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class RedemptionCodeRepositoryFactory extends AbstractFactory<RedemptionCodeRepository> {
|
export class RedemptionCodeRepositoryFactory extends ConfiguredSingletonFactory<RedemptionCodeRepository> {
|
||||||
protected get config(): Config {
|
protected getConfigKey(): string {
|
||||||
return Container.getContainer().make<Config>(Config)
|
return 'oauth2.repository.client'
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): RedemptionCodeRepository {
|
protected getDefaultImplementation(): Instantiable<RedemptionCodeRepository> {
|
||||||
return new (this.getRedemptionCodeRepositoryClass())()
|
return CacheRedemptionCodeRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === RedemptionCodeRepository
|
return RedemptionCodeRepository
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getRedemptionCodeRepositoryClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getRedemptionCodeRepositoryClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured client repository backend.
|
|
||||||
* @protected
|
|
||||||
* @return Instantiable<RedemptionCodeRepository>
|
|
||||||
*/
|
|
||||||
protected getRedemptionCodeRepositoryClass(): Instantiable<RedemptionCodeRepository> {
|
|
||||||
const RedemptionCodeRepositoryClass = this.config.get('oauth2.repository.client', CacheRedemptionCodeRepository)
|
|
||||||
|
|
||||||
if ( !isInstantiable(RedemptionCodeRepositoryClass) || !(RedemptionCodeRepositoryClass.prototype instanceof RedemptionCodeRepository) ) {
|
|
||||||
const e = new ErrorWithContext('Provided client repository class does not extend from @extollo/lib.RedemptionCodeRepository')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'oauth2.repository.client',
|
|
||||||
class: RedemptionCodeRepositoryClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return RedemptionCodeRepositoryClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../../di'
|
||||||
AbstractFactory,
|
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable, FactoryProducer, getPropertyInjectionMetadata,
|
|
||||||
} from '../../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../../util'
|
|
||||||
import {Config} from '../../../service/Config'
|
|
||||||
import {ScopeRepository} from '../types'
|
import {ScopeRepository} from '../types'
|
||||||
import {ConfigScopeRepository} from './ConfigScopeRepository'
|
import {ConfigScopeRepository} from './ConfigScopeRepository'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection factory that matches the abstract ScopeRepository class
|
* A dependency injection factory that matches the abstract ScopeRepository class
|
||||||
* and produces an instance of the configured repository driver implementation.
|
* and produces an instance of the configured repository driver implementation.
|
||||||
*/
|
*/
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class ScopeRepositoryFactory extends AbstractFactory<ScopeRepository> {
|
export class ScopeRepositoryFactory extends ConfiguredSingletonFactory<ScopeRepository> {
|
||||||
protected get config(): Config {
|
protected getConfigKey(): string {
|
||||||
return Container.getContainer().make<Config>(Config)
|
return 'oauth2.repository.scope'
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): ScopeRepository {
|
protected getDefaultImplementation(): Instantiable<ScopeRepository> {
|
||||||
return new (this.getScopeRepositoryClass())()
|
return ConfigScopeRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === ScopeRepository
|
return ScopeRepository
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getScopeRepositoryClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getScopeRepositoryClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured scope repository backend.
|
|
||||||
* @protected
|
|
||||||
* @return Instantiable<ScopeRepository>
|
|
||||||
*/
|
|
||||||
protected getScopeRepositoryClass(): Instantiable<ScopeRepository> {
|
|
||||||
const ScopeRepositoryClass = this.config.get('oauth2.repository.scope', ConfigScopeRepository)
|
|
||||||
|
|
||||||
if ( !isInstantiable(ScopeRepositoryClass) || !(ScopeRepositoryClass.prototype instanceof ScopeRepository) ) {
|
|
||||||
const e = new ErrorWithContext('Provided client repository class does not extend from @extollo/lib.ScopeRepository')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'oauth2.repository.client',
|
|
||||||
class: ScopeRepositoryClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ScopeRepositoryClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../../di'
|
||||||
AbstractFactory,
|
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable, FactoryProducer, getPropertyInjectionMetadata,
|
|
||||||
} from '../../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../../util'
|
|
||||||
import {Config} from '../../../service/Config'
|
|
||||||
import {TokenRepository} from '../types'
|
import {TokenRepository} from '../types'
|
||||||
import {ORMTokenRepository} from './ORMTokenRepository'
|
import {ORMTokenRepository} from './ORMTokenRepository'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection factory that matches the abstract TokenRepository class
|
* A dependency injection factory that matches the abstract TokenRepository class
|
||||||
* and produces an instance of the configured repository driver implementation.
|
* and produces an instance of the configured repository driver implementation.
|
||||||
*/
|
*/
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class TokenRepositoryFactory extends AbstractFactory<TokenRepository> {
|
export class TokenRepositoryFactory extends ConfiguredSingletonFactory<TokenRepository> {
|
||||||
protected get config(): Config {
|
protected getConfigKey(): string {
|
||||||
return Container.getContainer().make<Config>(Config)
|
return 'oauth2.repository.token'
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): TokenRepository {
|
protected getDefaultImplementation(): Instantiable<TokenRepository> {
|
||||||
return new (this.getTokenRepositoryClass())()
|
return ORMTokenRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === TokenRepository
|
return TokenRepository
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getTokenRepositoryClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getTokenRepositoryClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured token repository backend.
|
|
||||||
* @protected
|
|
||||||
* @return Instantiable<TokenRepository>
|
|
||||||
*/
|
|
||||||
protected getTokenRepositoryClass(): Instantiable<TokenRepository> {
|
|
||||||
const TokenRepositoryClass = this.config.get('oauth2.repository.token', ORMTokenRepository)
|
|
||||||
|
|
||||||
if ( !isInstantiable(TokenRepositoryClass) || !(TokenRepositoryClass.prototype instanceof TokenRepository) ) {
|
|
||||||
const e = new ErrorWithContext('Provided token repository class does not extend from @extollo/lib.TokenRepository')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'oauth2.repository.client',
|
|
||||||
class: TokenRepositoryClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return TokenRepositoryClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'reflect-metadata'
|
import 'reflect-metadata'
|
||||||
import {collect, Collection} from '../../util'
|
import {collect, Collection} from '../../util/collection/Collection'
|
||||||
import {logIfDebugging} from '../../util/support/debug'
|
import {logIfDebugging} from '../../util/support/debug'
|
||||||
import {
|
import {
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
DEPENDENCY_KEYS_METADATA_KEY,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import {DependencyKey, DependencyRequirement, PropertyDependency} from '../types'
|
import {DependencyKey, DependencyRequirement, Instantiable, PropertyDependency} from '../types'
|
||||||
import { Collection } from '../../util'
|
import {Collection, logIfDebugging} from '../../util'
|
||||||
|
import {getPropertyInjectionMetadata} from '../decorator/getPropertyInjectionMetadata'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract base class for dependency container factories.
|
* Abstract base class for dependency container factories.
|
||||||
@ -42,6 +43,22 @@ export abstract class AbstractFactory<T> {
|
|||||||
*/
|
*/
|
||||||
abstract getInjectedProperties(): Collection<PropertyDependency>
|
abstract getInjectedProperties(): Collection<PropertyDependency>
|
||||||
|
|
||||||
|
/** Helper method that returns all `@Inject()`'ed properties for a token and its prototypical ancestors. */
|
||||||
|
protected getInjectedPropertiesForPrototypeChain(token: Instantiable<any>): Collection<PropertyDependency> {
|
||||||
|
const meta = new Collection<PropertyDependency>()
|
||||||
|
|
||||||
|
do {
|
||||||
|
const loadedMeta = getPropertyInjectionMetadata(token)
|
||||||
|
if ( loadedMeta ) {
|
||||||
|
meta.concat(loadedMeta)
|
||||||
|
}
|
||||||
|
token = Object.getPrototypeOf(token)
|
||||||
|
logIfDebugging('extollo.di.injection', 'next currentToken:', token)
|
||||||
|
} while (token !== Function.prototype && token !== Object.prototype)
|
||||||
|
|
||||||
|
return meta
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a human-readable name of the token this factory produces.
|
* Get a human-readable name of the token this factory produces.
|
||||||
* This is meant for debugging output only.
|
* This is meant for debugging output only.
|
||||||
|
84
src/di/factory/ConfiguredSingletonFactory.ts
Normal file
84
src/di/factory/ConfiguredSingletonFactory.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
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>
|
||||||
|
}
|
||||||
|
}
|
@ -5,9 +5,8 @@ import {
|
|||||||
Instantiable,
|
Instantiable,
|
||||||
PropertyDependency,
|
PropertyDependency,
|
||||||
} from '../types'
|
} from '../types'
|
||||||
import {Collection, logIfDebugging} from '../../util'
|
import {Collection} from '../../util'
|
||||||
import 'reflect-metadata'
|
import 'reflect-metadata'
|
||||||
import {getPropertyInjectionMetadata} from '../decorator/getPropertyInjectionMetadata'
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard static-class factory. The token of this factory is a reference to a
|
* Standard static-class factory. The token of this factory is a reference to a
|
||||||
@ -53,18 +52,6 @@ export class Factory<T> extends AbstractFactory<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
getInjectedProperties(): Collection<PropertyDependency> {
|
||||||
const meta = new Collection<PropertyDependency>()
|
return this.getInjectedPropertiesForPrototypeChain(this.token)
|
||||||
let currentToken = this.token
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
logIfDebugging('extollo.di.injection', 'Factory.getInjectedProperties() target:', currentToken, 'loaded:', loadedMeta)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,12 +7,13 @@ export * from './factory/Factory'
|
|||||||
export * from './factory/NamedFactory'
|
export * from './factory/NamedFactory'
|
||||||
export * from './factory/SingletonFactory'
|
export * from './factory/SingletonFactory'
|
||||||
|
|
||||||
|
export * from './types'
|
||||||
export * from './ContainerBlueprint'
|
export * from './ContainerBlueprint'
|
||||||
|
export * from './decorator/getPropertyInjectionMetadata'
|
||||||
|
export * from './decorator/injection'
|
||||||
|
|
||||||
export * from './Container'
|
export * from './Container'
|
||||||
export * from './ScopedContainer'
|
export * from './ScopedContainer'
|
||||||
export * from './types'
|
|
||||||
|
|
||||||
export * from './decorator/injection'
|
|
||||||
export * from './decorator/getPropertyInjectionMetadata'
|
|
||||||
export * from './InjectionAware'
|
export * from './InjectionAware'
|
||||||
export * from './constructable'
|
export * from './constructable'
|
||||||
|
@ -20,7 +20,7 @@ export class InjectSessionHTTPModule extends HTTPKernelModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async apply(request: Request): Promise<Request> {
|
public async apply(request: Request): Promise<Request> {
|
||||||
request.registerFactory(new SessionFactory())
|
request.registerFactory(request.make(SessionFactory))
|
||||||
|
|
||||||
const session = <Session> request.make(Session)
|
const session = <Session> request.make(Session)
|
||||||
const id = request.cookies.get('extollo.session')
|
const id = request.cookies.get('extollo.session')
|
||||||
|
@ -1,87 +1,23 @@
|
|||||||
import {
|
import {Instantiable} from '../../di'
|
||||||
AbstractFactory,
|
import {Maybe} from '../../util'
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable, getPropertyInjectionMetadata,
|
|
||||||
} from '../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../util'
|
|
||||||
import {MemorySession} from './MemorySession'
|
import {MemorySession} from './MemorySession'
|
||||||
import {Session} from './Session'
|
import {Session} from './Session'
|
||||||
import {Logging} from '../../service/Logging'
|
import {ConfiguredSingletonFactory} from '../../di/factory/ConfiguredSingletonFactory'
|
||||||
import {Config} from '../../service/Config'
|
|
||||||
|
|
||||||
/**
|
export class SessionFactory extends ConfiguredSingletonFactory<Session> {
|
||||||
* A dependency injection factory that matches the abstract Session class
|
protected getConfigKey(): string {
|
||||||
* and produces an instance of the configured session driver implementation.
|
return 'server.session.driver'
|
||||||
*/
|
|
||||||
export class SessionFactory extends AbstractFactory<Session> {
|
|
||||||
protected readonly logging: Logging
|
|
||||||
|
|
||||||
protected readonly config: Config
|
|
||||||
|
|
||||||
/** True if we have printed the memory session warning at least once. */
|
|
||||||
private static loggedMemorySessionWarningOnce = false
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super({})
|
|
||||||
this.logging = Container.getContainer().make<Logging>(Logging)
|
|
||||||
this.config = Container.getContainer().make<Config>(Config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): Session {
|
protected getDefaultImplementation(): Instantiable<Session> {
|
||||||
return new (this.getSessionClass())()
|
return MemorySession
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === Session
|
return Session
|
||||||
}
|
}
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
protected getDefaultImplementationWarning(): Maybe<string> {
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getSessionClass())
|
return 'You are using the default memory-based session driver. It is recommended you configure a persistent session driver instead.'
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getSessionClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured session backend.
|
|
||||||
* @protected
|
|
||||||
* @return Instantiable<Session>
|
|
||||||
*/
|
|
||||||
protected getSessionClass(): Instantiable<Session> {
|
|
||||||
const SessionClass = this.config.get('server.session.driver', MemorySession)
|
|
||||||
if ( SessionClass === MemorySession && !SessionFactory.loggedMemorySessionWarningOnce ) {
|
|
||||||
this.logging.warn(`You are using the default memory-based session driver. It is recommended you configure a persistent session driver instead.`)
|
|
||||||
SessionFactory.loggedMemorySessionWarningOnce = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !isInstantiable(SessionClass) || !(SessionClass.prototype instanceof Session) ) {
|
|
||||||
const e = new ErrorWithContext('Provided session class does not extend from @extollo/lib.Session')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'server.session.driver',
|
|
||||||
class: SessionClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return SessionClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,86 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../di'
|
||||||
AbstractFactory,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
Instantiable,
|
|
||||||
Injectable,
|
|
||||||
Inject,
|
|
||||||
FactoryProducer,
|
|
||||||
getPropertyInjectionMetadata,
|
|
||||||
} from '../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../util'
|
|
||||||
import {Logging} from '../../service/Logging'
|
|
||||||
import {Config} from '../../service/Config'
|
|
||||||
import {Migrator} from './Migrator'
|
import {Migrator} from './Migrator'
|
||||||
import {DatabaseMigrator} from './DatabaseMigrator'
|
import {DatabaseMigrator} from './DatabaseMigrator'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dependency injection factory that matches the abstract Migrator class
|
* A dependency injection factory that matches the abstract Migrator class
|
||||||
* and produces an instance of the configured session driver implementation.
|
* and produces an instance of the configured session driver implementation.
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class MigratorFactory extends AbstractFactory<Migrator> {
|
export class MigratorFactory extends ConfiguredSingletonFactory<Migrator> {
|
||||||
@Inject()
|
protected getConfigKey(): string {
|
||||||
protected readonly logging!: Logging
|
return 'database.migrations.driver'
|
||||||
|
|
||||||
@Inject()
|
|
||||||
protected readonly config!: Config
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super({})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): Migrator {
|
protected getDefaultImplementation(): Instantiable<Migrator> {
|
||||||
return new (this.getMigratorClass())()
|
return DatabaseMigrator
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === Migrator
|
return Migrator
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getMigratorClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getMigratorClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the instantiable class of the configured migrator backend.
|
|
||||||
* @protected
|
|
||||||
* @return Instantiable<Migrator>
|
|
||||||
*/
|
|
||||||
protected getMigratorClass(): Instantiable<Migrator> {
|
|
||||||
const MigratorClass = this.config.get('database.migrations.driver', DatabaseMigrator)
|
|
||||||
|
|
||||||
if ( !isInstantiable(MigratorClass) || !(MigratorClass.prototype instanceof Migrator) ) {
|
|
||||||
const e = new ErrorWithContext('Provided migration driver class does not extend from @extollo/lib.Migrator')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'database.migrations.driver',
|
|
||||||
class: MigratorClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return MigratorClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import {collect, Collection, ErrorWithContext, Maybe} from '../../util'
|
|||||||
import {HasSubtree} from './relation/HasSubtree'
|
import {HasSubtree} from './relation/HasSubtree'
|
||||||
import {Related} from './relation/decorators'
|
import {Related} from './relation/decorators'
|
||||||
import {HasTreeParent} from './relation/HasTreeParent'
|
import {HasTreeParent} from './relation/HasTreeParent'
|
||||||
|
import {ModelBuilder} from './ModelBuilder'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Model implementation with helpers for querying tree-structured data.
|
* Model implementation with helpers for querying tree-structured data.
|
||||||
@ -44,6 +45,12 @@ export abstract class TreeModel<T extends TreeModel<T>> extends Model<T> {
|
|||||||
|
|
||||||
public static readonly parentIdField = 'parent_id'
|
public static readonly parentIdField = 'parent_id'
|
||||||
|
|
||||||
|
/** @override to include the tree fields */
|
||||||
|
public static query<T2 extends Model<T2>>(): ModelBuilder<T2> {
|
||||||
|
return super.query<T2>()
|
||||||
|
.fields(this.rightTreeField, this.leftTreeField, this.parentIdField)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override to eager-load the subtree by default
|
* @override to eager-load the subtree by default
|
||||||
* @protected
|
* @protected
|
||||||
@ -52,6 +59,13 @@ export abstract class TreeModel<T extends TreeModel<T>> extends Model<T> {
|
|||||||
|
|
||||||
protected removedChildren: Collection<TreeModel<T>> = collect()
|
protected removedChildren: Collection<TreeModel<T>> = collect()
|
||||||
|
|
||||||
|
/** @override to include the tree fields */
|
||||||
|
public query(): ModelBuilder<T> {
|
||||||
|
const ctor = this.constructor as typeof TreeModel
|
||||||
|
return super.query()
|
||||||
|
.fields(ctor.leftTreeField, ctor.rightTreeField, ctor.parentIdField)
|
||||||
|
}
|
||||||
|
|
||||||
/** Get the left tree number for this model. */
|
/** Get the left tree number for this model. */
|
||||||
public leftTreeNum(): Maybe<number> {
|
public leftTreeNum(): Maybe<number> {
|
||||||
const ctor = this.constructor as typeof TreeModel
|
const ctor = this.constructor as typeof TreeModel
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {Canonical} from './Canonical'
|
import {Canonical} from './Canonical'
|
||||||
import {Singleton} from '../di'
|
import {Singleton} from '../di/decorator/injection'
|
||||||
import {Maybe} from '../util'
|
import {Maybe} from '../util'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import {DebuggingTraceIsNotAnError, Logger, LoggingLevel, LogMessage} from '../util'
|
import {Singleton} from '../di/decorator/injection'
|
||||||
import {Singleton} from '../di'
|
import {DebuggingTraceIsNotAnError} from '../util/error/DebuggingTraceIsNotAnError'
|
||||||
|
import {LoggingLevel, LogMessage} from '../util/logging/types'
|
||||||
|
import {Logger} from '../util/logging/Logger'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A singleton service that manages loggers registered in the application, and
|
* A singleton service that manages loggers registered in the application, and
|
||||||
|
@ -1,86 +1,28 @@
|
|||||||
import {
|
import {FactoryProducer, Instantiable} from '../../../di'
|
||||||
AbstractFactory,
|
import {Maybe} from '../../../util'
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
StaticInstantiable,
|
|
||||||
FactoryProducer, getPropertyInjectionMetadata,
|
|
||||||
} from '../../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../../util'
|
|
||||||
import {Logging} from '../../../service/Logging'
|
|
||||||
import {Config} from '../../../service/Config'
|
|
||||||
import {Queue} from './Queue'
|
import {Queue} from './Queue'
|
||||||
import {SyncQueue} from './SyncQueue'
|
import {SyncQueue} from './SyncQueue'
|
||||||
|
import {ConfiguredSingletonFactory} from '../../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dependency container factory that matches the abstract Queue token, but
|
* Dependency container factory that matches the abstract Queue token, but
|
||||||
* produces an instance of whatever Queue driver is configured in the `server.queue.driver` config.
|
* produces an instance of whatever Queue driver is configured in the `server.queue.driver` config.
|
||||||
*/
|
*/
|
||||||
@FactoryProducer()
|
@FactoryProducer()
|
||||||
export class QueueFactory extends AbstractFactory<Queue> {
|
export class QueueFactory extends ConfiguredSingletonFactory<Queue> {
|
||||||
/** true if we have printed the synchronous queue driver warning once. */
|
protected getConfigKey(): string {
|
||||||
private static loggedSyncQueueWarningOnce = false
|
return 'server.queue.driver'
|
||||||
|
|
||||||
private di(): [Logging, Config] {
|
|
||||||
return [
|
|
||||||
Container.getContainer().make(Logging),
|
|
||||||
Container.getContainer().make(Config),
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): Queue {
|
protected getDefaultImplementation(): Instantiable<Queue> {
|
||||||
return new (this.getQueueClass())()
|
return SyncQueue
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === Queue
|
return Queue
|
||||||
}
|
}
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
protected getDefaultImplementationWarning(): Maybe<string> {
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getQueueClass())
|
return 'You are using the default synchronous queue driver. It is recommended you configure a background queue driver instead.'
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getQueueClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configured queue driver and return some Instantiable<Queue>.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
protected getQueueClass(): StaticInstantiable<Queue> {
|
|
||||||
const [logging, config] = this.di()
|
|
||||||
const QueueClass = config.get('server.queue.driver', SyncQueue)
|
|
||||||
if ( QueueClass === SyncQueue && !QueueFactory.loggedSyncQueueWarningOnce ) {
|
|
||||||
logging.warn(`You are using the default synchronous queue driver. It is recommended you configure a background queue driver instead.`)
|
|
||||||
QueueFactory.loggedSyncQueueWarningOnce = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !isInstantiable(QueueClass) || !(QueueClass.prototype instanceof Queue) ) {
|
|
||||||
const e = new ErrorWithContext('Provided queue class does not extend from @extollo/lib.Queue')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'server.queue.driver',
|
|
||||||
class: QueueClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return QueueClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
85
src/support/cache/CacheFactory.ts
vendored
85
src/support/cache/CacheFactory.ts
vendored
@ -1,86 +1,27 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../../di'
|
||||||
AbstractFactory,
|
import {InMemCache, Maybe} from '../../util'
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
StaticClass, Instantiable, getPropertyInjectionMetadata,
|
|
||||||
} from '../../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../../util'
|
|
||||||
import {Logging} from '../../service/Logging'
|
|
||||||
import {Config} from '../../service/Config'
|
|
||||||
import {Cache} from '../../util'
|
import {Cache} from '../../util'
|
||||||
import {MemoryCache} from './MemoryCache'
|
import {ConfiguredSingletonFactory} from '../../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dependency container factory that matches the abstract Cache token, but
|
* Dependency container factory that matches the abstract Cache token, but
|
||||||
* produces an instance of whatever Cache driver is configured in the `server.cache.driver` config.
|
* produces an instance of whatever Cache driver is configured in the `server.cache.driver` config.
|
||||||
*/
|
*/
|
||||||
export class CacheFactory extends AbstractFactory<Cache> {
|
@FactoryProducer()
|
||||||
protected readonly logging: Logging
|
export class CacheFactory extends ConfiguredSingletonFactory<Cache> {
|
||||||
|
protected getConfigKey(): string {
|
||||||
protected readonly config: Config
|
return 'server.cache.driver'
|
||||||
|
|
||||||
/** true if we have printed the memory-based cache driver warning once. */
|
|
||||||
private static loggedMemoryCacheWarningOnce = false
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super({})
|
|
||||||
this.logging = Container.getContainer().make<Logging>(Logging)
|
|
||||||
this.config = Container.getContainer().make<Config>(Config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): Cache {
|
protected getDefaultImplementation(): Instantiable<Cache> {
|
||||||
return new (this.getCacheClass())()
|
return InMemCache
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === Cache
|
return Cache
|
||||||
}
|
}
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
protected getDefaultImplementationWarning(): Maybe<string> {
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getCacheClass())
|
return 'You are using the default memory-based cache driver. It is recommended you configure a persistent cache driver instead.'
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getCacheClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the configured cache driver and return some Instantiable<Cache>.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
protected getCacheClass(): StaticClass<Cache, Instantiable<Cache>> {
|
|
||||||
const CacheClass = this.config.get('server.cache.driver', MemoryCache)
|
|
||||||
if ( CacheClass === MemoryCache && !CacheFactory.loggedMemoryCacheWarningOnce ) {
|
|
||||||
this.logging.warn(`You are using the default memory-based cache driver. It is recommended you configure a persistent cache driver instead.`)
|
|
||||||
CacheFactory.loggedMemoryCacheWarningOnce = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( !isInstantiable(CacheClass) || !(CacheClass.prototype instanceof Cache) ) {
|
|
||||||
const e = new ErrorWithContext('Provided session class does not extend from @extollo/lib.Cache')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'server.cache.driver',
|
|
||||||
class: CacheClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return CacheClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import {Collection} from './Collection'
|
import {Collection} from './Collection'
|
||||||
import {InjectionAware} from '../../di'
|
import {InjectionAware} from '../../di/InjectionAware'
|
||||||
|
|
||||||
export type MaybeIterationItem<T> = { done: boolean, value?: T }
|
export type MaybeIterationItem<T> = { done: boolean, value?: T }
|
||||||
export type ChunkCallback<T> = (items: Collection<T>) => any
|
export type ChunkCallback<T> = (items: Collection<T>) => any
|
||||||
|
@ -2,6 +2,8 @@ import {RequestInfo, RequestInit, Response} from 'node-fetch'
|
|||||||
import {unsafeESMImport} from './unsafe'
|
import {unsafeESMImport} from './unsafe'
|
||||||
export const fetch = (url: RequestInfo, init?: RequestInit): Promise<Response> => unsafeESMImport('node-fetch').then(({default: nodeFetch}) => nodeFetch(url, init))
|
export const fetch = (url: RequestInfo, init?: RequestInit): Promise<Response> => unsafeESMImport('node-fetch').then(({default: nodeFetch}) => nodeFetch(url, init))
|
||||||
|
|
||||||
|
export * from './support/operator'
|
||||||
|
|
||||||
export * from './cache/Cache'
|
export * from './cache/Cache'
|
||||||
export * from './cache/InMemCache'
|
export * from './cache/InMemCache'
|
||||||
|
|
||||||
|
27
src/util/support/operator.ts
Normal file
27
src/util/support/operator.ts
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/**
|
||||||
|
* Apply a series of operators to a value, returning the original value.
|
||||||
|
*
|
||||||
|
* Helpful for values/methods that don't support chaining.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```ts
|
||||||
|
* const inOneHour = () => tap(new Date, d => d.setMinutes(d.getMinutes() + 60))
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* This is equivalent to:
|
||||||
|
*
|
||||||
|
* ```ts
|
||||||
|
* const inOneHour = () => {
|
||||||
|
* const d = new Date
|
||||||
|
* d.setMinutes(d.getMinutes() + 60)
|
||||||
|
* return d
|
||||||
|
* }
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* @param ops
|
||||||
|
*/
|
||||||
|
export function tap<T>(value: T, ...ops: ((t: T) => unknown)[]): T {
|
||||||
|
ops.forEach(op => op(value))
|
||||||
|
return value
|
||||||
|
}
|
@ -1,79 +1,23 @@
|
|||||||
import {
|
import {Instantiable, FactoryProducer} from '../di'
|
||||||
AbstractFactory,
|
|
||||||
Container,
|
|
||||||
DependencyRequirement,
|
|
||||||
PropertyDependency,
|
|
||||||
isInstantiable,
|
|
||||||
DEPENDENCY_KEYS_METADATA_KEY,
|
|
||||||
StaticClass, Instantiable, getPropertyInjectionMetadata,
|
|
||||||
} from '../di'
|
|
||||||
import {Collection, ErrorWithContext} from '../util'
|
|
||||||
import {Logging} from '../service/Logging'
|
|
||||||
import {Config} from '../service/Config'
|
|
||||||
import {ViewEngine} from './ViewEngine'
|
import {ViewEngine} from './ViewEngine'
|
||||||
import {PugViewEngine} from './PugViewEngine'
|
import {PugViewEngine} from './PugViewEngine'
|
||||||
|
import {ConfiguredSingletonFactory} from '../di/factory/ConfiguredSingletonFactory'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dependency factory whose token matches the abstract ViewEngine class, but produces
|
* Dependency factory whose token matches the abstract ViewEngine class, but produces
|
||||||
* a particular ViewEngine implementation based on the configuration.
|
* a particular ViewEngine implementation based on the configuration.
|
||||||
*/
|
*/
|
||||||
export class ViewEngineFactory extends AbstractFactory<ViewEngine> {
|
@FactoryProducer()
|
||||||
protected readonly logging: Logging
|
export class ViewEngineFactory extends ConfiguredSingletonFactory<ViewEngine> {
|
||||||
|
protected getConfigKey(): string {
|
||||||
protected readonly config: Config
|
return 'server.view_engine.driver'
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super({})
|
|
||||||
this.logging = Container.getContainer().make<Logging>(Logging)
|
|
||||||
this.config = Container.getContainer().make<Config>(Config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
produce(): ViewEngine {
|
protected getDefaultImplementation(): Instantiable<ViewEngine> {
|
||||||
return new (this.getViewEngineClass())()
|
return PugViewEngine
|
||||||
}
|
}
|
||||||
|
|
||||||
match(something: unknown): boolean {
|
protected getAbstractImplementation(): any {
|
||||||
return something === ViewEngine
|
return ViewEngine
|
||||||
}
|
|
||||||
|
|
||||||
getDependencyKeys(): Collection<DependencyRequirement> {
|
|
||||||
const meta = Reflect.getMetadata(DEPENDENCY_KEYS_METADATA_KEY, this.getViewEngineClass())
|
|
||||||
if ( meta ) {
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
return new Collection<DependencyRequirement>()
|
|
||||||
}
|
|
||||||
|
|
||||||
getInjectedProperties(): Collection<PropertyDependency> {
|
|
||||||
const meta = new Collection<PropertyDependency>()
|
|
||||||
let currentToken = this.getViewEngineClass()
|
|
||||||
|
|
||||||
do {
|
|
||||||
const loadedMeta = getPropertyInjectionMetadata(currentToken)
|
|
||||||
if ( loadedMeta ) {
|
|
||||||
meta.concat(loadedMeta)
|
|
||||||
}
|
|
||||||
currentToken = Object.getPrototypeOf(currentToken)
|
|
||||||
} while (Object.getPrototypeOf(currentToken) !== Function.prototype && Object.getPrototypeOf(currentToken) !== Object.prototype)
|
|
||||||
|
|
||||||
return meta
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Using the config, get the implementation of the ViewEngine that should be used in the application.
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
protected getViewEngineClass(): StaticClass<ViewEngine, Instantiable<ViewEngine>> {
|
|
||||||
const ViewEngineClass = this.config.get('server.view_engine.driver', PugViewEngine)
|
|
||||||
|
|
||||||
if ( !isInstantiable(ViewEngineClass) || !(ViewEngineClass.prototype instanceof ViewEngine) ) {
|
|
||||||
const e = new ErrorWithContext('Provided session class does not extend from @extollo/lib.ViewEngine')
|
|
||||||
e.context = {
|
|
||||||
configKey: 'server.view_engine.driver',
|
|
||||||
class: ViewEngineClass.toString(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ViewEngineClass
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user