UNPKG

@athenna/database

Version:

The Athenna database handler for SQL/NoSQL.

143 lines (142 loc) 4.17 kB
/** * @athenna/database * * (c) João Lenon <lenon@athenna.io> * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ import { debug } from '#src/debug'; import { Macroable } from '@athenna/common'; import { BaseModel } from '#src/models/BaseModel'; export class ModelFactory extends Macroable { constructor(model) { super(); /** * The number of models to be created. */ this._count = 1; /** * Set if the soft delete state is active or not. */ this._trashed = false; /** * Set the returning key that this factory will return. */ this._returning = '*'; this.Model = model; } /** * Set the returning key that this factory will * return after making or creating an instance. */ returning(key) { this._returning = key; return this; } /** * Same as returning method, but return the type of * the key of the model to avoid using "as any" or * other kind of stuffs to fix the type in definition * method. * * Only the type is modified for convenience, the real * return type of this method is still the ModelFactory * instance. */ returningAs(key) { this._returning = key; return this; } /** * Set the soft delete state in your model to * fabricate deleted data. */ trashed() { this._trashed = true; return this; } /** * Remove the soft delete state in your model to * not fabricate deleted data. */ untrashed() { this._trashed = false; return this; } /** * Set the number of models to be created. */ count(number) { this._count = number; return this; } /** * Make models without creating it on database. */ async make(override = {}) { const promises = []; for (let i = 1; i <= this._count; i++) { promises.push(this.getDefinition(override, 'make')); } let data = await Promise.all(promises); data = data.map(d => { if (this._returning !== '*') { return d[this._returning]; } const model = new this.Model(); Object.keys(d).forEach(key => (model[key] = d[key])); return model; }); if (this._count === 1) { return data[0]; } return data; } /** * Create models creating it on database. */ async create(override = {}) { const promises = []; for (let i = 1; i <= this._count; i++) { promises.push(this.getDefinition(override, 'create')); } let data = await this.Model.createMany(await Promise.all(promises), false); if (this._returning !== '*') { data = data.map(d => d[this._returning]); } if (this._count === 1) { return data[0]; } return data; } /** * Execute the definition method and return data. */ async getDefinition(override, method) { const data = await this.Model.definition(); const promises = Object.keys(data).reduce((promises, key) => { if ((override && override[key]) || !(data[key] instanceof ModelFactory)) { return promises; } const SubFactory = data[key]; const result = SubFactory[method]().then(r => (data[key] = r)); promises.push(result); return promises; }, []); await Promise.all(promises); if (this._trashed) { const column = this.Model.schema().getDeletedAtColumn(); if (!column) { debug('there is any column with isDeleteDate option as true in model %s. trashed option will be ignored.', this.Model.name); } else { data[column.property] = new Date(); } } return { ...data, ...override }; } }