Skip to content

Commit

Permalink
🌿 refactor: lazy load services instead of instantiate them direclty i…
Browse files Browse the repository at this point in the history
…n addFactory
  • Loading branch information
Victor MENDELE committed May 21, 2020
1 parent 0a59298 commit 53a03e8
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 14 deletions.
27 changes: 22 additions & 5 deletions src/ReflectServiceContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ export class ReflectServiceContainer implements IServiceContainer {

private _options: IServiceContainerOptions

private _serviceFactories: { [key: string]: IServiceFactoryFunction } = {}

constructor(containerOptions: IServiceContainerOptions = defaultReflectServiceContainerOptions) {
this._options = containerOptions
}
Expand Down Expand Up @@ -82,11 +84,18 @@ export class ReflectServiceContainer implements IServiceContainer {
* @throws ServiceAlreadyRegisteredError
*/
addFactory(key: string, factory: IServiceFactoryFunction): this {
if (!this._options.allowServiceOverride && key in this._services) {
if (!this._options.allowServiceOverride && key in this._serviceFactories) {
throw new ServiceAlreadyRegisteredError(key)
}

this._services[key] = factory(this)
this._serviceFactories[key] = factory
delete this._services[key]

// if (!this._options.allowServiceOverride && key in this._services) {
// throw new ServiceAlreadyRegisteredError(key)
// }
//
// this._services[key] = factory(this)

return this
}
Expand All @@ -99,10 +108,14 @@ export class ReflectServiceContainer implements IServiceContainer {
* @throws ServiceNotFoundError
*/
get<T>(key: string): T {
if (!(key in this._services)) {
if (!(key in this._serviceFactories)) {
throw new ServiceNotFoundError(key)
}

if (!(key in this._services)) {
this._services[key] = this._serviceFactories[key] (this)
}

return this._services[key] as T
}

Expand All @@ -114,11 +127,15 @@ export class ReflectServiceContainer implements IServiceContainer {
* @throws ServiceNotFoundError Thrown when no service is matching the passed key.
*/
delete(key: string): this {
if (!(key in this._services)) {
if (!(key in this._serviceFactories)) {
throw new ServiceNotFoundError(key)
}

delete this._services[key]
delete this._serviceFactories[key]

if (key in this._services) {
delete this._services[key]
}

return this
}
Expand Down
29 changes: 24 additions & 5 deletions src/ServiceContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const defaultServiceContainerOptions: IServiceContainerOptions = {
*/
export class ServiceContainer implements IServiceContainer {
private _services: ServiceContainerDictionary = {}
private _serviceFactories: { [key: string]: IServiceFactoryFunction } = {}
private _options: IServiceContainerOptions

constructor(containerOptions: IServiceContainerOptions = defaultServiceContainerOptions) {
Expand Down Expand Up @@ -80,11 +81,13 @@ export class ServiceContainer implements IServiceContainer {
* @throws ServiceAlreadyRegisteredError
*/
addFactory(key: string, factory: IServiceFactoryFunction): this {
if (!this._options.allowServiceOverride && key in this._services) {
if (!this._options.allowServiceOverride && key in this._serviceFactories) {
throw new ServiceAlreadyRegisteredError(key)
}

this._services[key] = factory(this)
this._serviceFactories[key] = factory
delete this._services[key]
// this._services[key] = factory(this)

return this
}
Expand All @@ -97,10 +100,14 @@ export class ServiceContainer implements IServiceContainer {
* @throws ServiceNotFoundError
*/
get<T>(key: string): T {
if (!(key in this._services)) {
if (!(key in this._serviceFactories)) {
throw new ServiceNotFoundError(key)
}

if (!(key in this._services)) {
this._services[key] = this._serviceFactories[key] (this)
}

return this._services[key] as T
}

Expand All @@ -112,6 +119,14 @@ export class ServiceContainer implements IServiceContainer {
return this._services
}

/**
* Return the service factories collection.
* YOu should use this only for test proposes.
*/
get factories() {
return this._serviceFactories
}

/**
* Delete the service matching the given key.
*
Expand All @@ -120,11 +135,15 @@ export class ServiceContainer implements IServiceContainer {
* @throws ServiceNotFoundError Thrown when no service is matching the passed key.
*/
delete(key: string): this {
if (!(key in this._services)) {
if (!(key in this._serviceFactories)) {
throw new ServiceNotFoundError(key)
}

delete this._services[key]
delete this._serviceFactories[key]

if (key in this._services) {
delete this._services[key]
}

return this
}
Expand Down
2 changes: 1 addition & 1 deletion tests/ReflectServiceContainer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {
IServiceContainer,
ReflectServiceContainer,
ServiceAlreadyRegisteredError,
ServiceContainer, ServiceNotFoundError
ServiceNotFoundError
} from '../src'
import {Inject} from '../src'

Expand Down
17 changes: 15 additions & 2 deletions tests/ServiceContainer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@ describe('#ServiceContainer', () => {
describe('#addFactory', () => {

it('adds a new service', () => {
const factory = () => ({ hello: 'world' })

const container: ServiceContainer = new ServiceContainer()
.addFactory('my service', () => ({ hello: 'world' }))
.addFactory('my service', factory)

expect(container.factories).toEqual({
'my service': factory
})

expect(container.services).toEqual({})

container.get<{ hello: string }> ('my service')

expect(container.services).toEqual({
'my service': {
Expand Down Expand Up @@ -112,8 +122,11 @@ describe('#ServiceContainer', () => {
it('deletes services', () => {
const c = new ServiceContainer()
.addFactory('hello', () => 'world')
.delete('hello')

c.get('hello')
c.delete('hello')

expect(c.factories).toEqual({})
expect(c.services).toEqual({})
})
})
Expand Down
26 changes: 25 additions & 1 deletion tests/sandbox.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,33 @@
import {createServiceContainer} from '../src'
import 'reflect-metadata'
import {createServiceContainer, Inject} from '../src'
import {createPlainServiceLoader} from '../src/factories/createPlainServiceLoader'
import {createReflectServiceLoader} from '../src/factories/createReflectServiceLoader'
import {Service} from '../src/decorators/Service'

it('should work', function () {
const container = createServiceContainer({
useReflection: false,
serviceLoader: createPlainServiceLoader([], [])
})
})

it('should work 2', function () {

@Service('myService')
class MyService {
constructor(
@Inject('myFactory') hello: string
) {
console.log(hello)
}
}

const loader = createReflectServiceLoader([ MyService ], [])

const container = createServiceContainer({
useReflection: true,
serviceLoader: loader
})

container.addFactory('myFactory', () => 'hello world')
})

0 comments on commit 53a03e8

Please sign in to comment.