@athenna/database
Version:
The Athenna database handler for SQL/NoSQL.
143 lines (142 loc) • 4.17 kB
JavaScript
/**
* @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
};
}
}