# Factories

Diosaur allows you to declare factories to create your services. These make it possible to register anything as a service in Diosaur.

# Class factories

All class factories must implement the IFactory interface as well as be decorated with @Factory.

class MyService {
    constructor(@Parameter('param') private param: string) {}
}

@Factory(MyService, { /* other settings like tag, scope... */ })
class MyFactory implements IFactory {
    resolve(params: any[]) {
        // Using reflect to build your service
        return Reflect.construct(MyService, params);

        // Building it manually
        return new MyService(...params);
    }
}

The factory decorator takes a mandatory argument which is the service identifier. It can take a second optional argument to change service settings.

# Resolve method

Every factory class must implement the resolve method. As you can see, it provides a single argument, params: any[], which actually contains all parameters and services that should be injected through constructor. In the case of the upper example, params would be something like ['value of param']. Diosaur automatically builds this array with correct order of arguments, it's your job to inject it in your service.

WARNING

Avoid services which have Diosaur and non-diosaur injected constructor arguments, Diosaur only knows about the decorated ones, the order will be wrong if there's some he's not aware of.

# Async class factories

You can also set async class factories easily by setting the resolve method as async or returning a Promise.

@Factory(MyService, { /* other settings like tag, scope... */ })
class MyFactory implements IFactory {
    async resolve(params: any[]) {
        return new MyService(...params);
    }
}

# anonymous factories

You can register some anonymous factories with the register method to avoid creating a class. The first argument is the service identifier, the second is either a function that will generate the service or the service itself, the third is the service configuration.

import { register, getContainer } from 'diosaur';

register('a', 'a'); // register a primitive as service
register('b', () => 'b', { scope: 'renewable', tag: 'B' }); // register a primitive as service and custom config
register('c', { key: 'value' }); // register an object
register('d', new Something()); // Simple object creation
register('e', (args: any[]) => new SomethingElse(...args)); // object creation with injection

// These two do the same
register('a', 'a'); // Internally converted to () => 'a'
register('a', () => 'a');

# Async anonymous factories

You can also register async anonymous factories easily using registerAsync.

import{ registerAsync } from 'diosaur';

registerAsync('d', new Promise((resolve) => {
    setTimeout(() => {
        resolve('D');
    }, 100);
}));

# A note on async factories

All services registered through async factories must be scoped as singleton. That's because once registered, calling the await getContainer() will actually create those services and keep them in the service registry for future usage.

If we didn't do it, when a service would require a dependency on a service registered through an async factory we couldn't resolve it, but would resolve a Promise. That could work, but then how would we inject constructor dependencies, and you would have to await a promise to receive your service.

That's why all async services must be singleton scoped.

# Registering services after initialization

It is possible to register dynamic services and parameters after retrieving the container.

import { getContainer, register, refreshContainer } from 'diosaur';

let container = await getContainer();
register('a', () => 'a');

container.get('a'); // Will throw an error

container = await refreshContainer();

container.get('a'); // a

WARNING

Note that refreshing the container will completely wipe any existing scope along with all cached instance