//--------------------------------------------------------
//-- Node IoC - Database - Services - Factory
//--------------------------------------------------------
import __ from '@absolunet/private-registry';
/**
* Factory service that helps build factoried model instances through defined model factories.
*
* @memberof database.services
* @hideconstructor
*/
class Factory {
/**
* Class dependencies: <code>['app', 'db.model', 'faker']</code>.
*
* @type {Array<string>}
*/
static get dependencies() {
return ['app', 'db.model', 'faker'];
}
/**
* @inheritdoc
* @private
*/
init() {
__(this).set('factories', {});
}
/**
* Get model factory instance by name.
*
* @param {string} name - The model factory name.
* @returns {database.Factory} The model factory instance.
*/
get(name) {
const factory = __(this).get('factories')[name];
if (!factory) {
throw new TypeError(`Cannot find factory for model [${name}].`);
}
return factory;
}
/**
* Make a model with attributes from its associated factory.
*
* @example
* factory.make('user'); // User { name: "John Smith", email: "john.smith@example.com" }
* factory.make('user', { name: 'John Doe' }); // User { name: "John Doe", email: "john.smith@example.com" }
* factory.make('user', 3); // Collection { [User { name: 'John Smith', email: 'john.smith@example.com }, User { ... }, User { ... }] }
* factory.make('user, { name: 'John Doe' }, 2); // Collection { []User { name: 'John Doe', email: 'johm.smith@example.com' }, User { ... }] }
*
* @param {string} model - The model name.
* @param {object<string, *>|number} [parameters={}] - The parameters to put into the model manually, overwriting matching factoried values. Can also be the times if no parameter are given.
* @param {number} [times=1] - The quantity of models that needed to be factoried. Minimum 1 model is required.
* @returns {Model|Collection} Either a single Model instance or a Model Collection instance, containing N times the requested model.
*/
make(model, parameters = {}, times = 1) {
const ModelInstance = __(this).get('db.model').get(model);
const factory = this.get(model);
const count = typeof parameters === 'number' ? parameters : times;
const properties = typeof parameters === 'number' ? {} : parameters;
if (count <= 0) {
throw new TypeError('Cannot make less than one model.');
}
const models = [...new Array(count).keys()].map(() => {
return new ModelInstance({ ...factory.make(), ...properties });
});
return count === 1 ? models[0] : ModelInstance.collection(models);
}
/**
* Register factory for a given model.
* If the model name is not provided, it will be taken from the factory instance.
*
* @param {database.Factory} factory - The factory class.
* @param {string|null} [model] - The model name. If no value is provided, the factory model will be taken.
* @returns {database.services.Factory} The factory service instance.
*/
register(factory, model = null) {
const instance = this.app.make(factory, { faker: this.app.make('faker') });
__(this).get('factories')[model || instance.model] = instance;
return this;
}
}
export default Factory;