UNPKG

@athenna/database

Version:

The Athenna database handler for SQL/NoSQL.

141 lines (140 loc) 4.98 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 { Macroable } from '@athenna/common'; import { ObjectId } from '#src/helpers/ObjectId'; import { ModelSchema } from '#src/models/schemas/ModelSchema'; import { HasOneRelation } from '#src/models/relations/HasOne/HasOneRelation'; import { HasManyRelation } from '#src/models/relations/HasMany/HasManyRelation'; import { HasOneThroughRelation } from '#src/models/relations/HasOneThrough/HasOneThroughRelation'; import { HasManyThroughRelation } from '#src/models/relations/HasManyThrough/HasManyThroughRelation'; import { BelongsToRelation } from '#src/models/relations/BelongsTo/BelongsToRelation'; import { BelongsToManyRelation } from '#src/models/relations/BelongsToMany/BelongsToManyRelation'; export class ModelGenerator extends Macroable { constructor(model, schema) { super(); this.Model = model; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore this.schema = schema; } /** * Generate one model instance with relations loaded. */ async generateOne(data) { if (!data) { return undefined; } const model = this.instantiateOne(data); return this.includeRelations(model); } /** * Generate models instances with relations loaded. */ async generateMany(data) { if (!data || !data.length) { return []; } const models = await Promise.all(data.map(d => this.instantiateOne(d))); return this.includeRelationsOfAll(models); } /** * Instantiate one model using vanilla database data. */ instantiateOne(data) { return this.populate(data, new this.Model()); } /** * Populate one object data in the model instance * using the column dictionary to map keys. */ populate(object, model) { Object.keys(object).forEach(key => { const column = this.schema.getColumnByName(key); if (!column) { return; } if (ObjectId.isValidObject(object[key])) { object[key] = object[key].toString(); } model[column.property] = object[key]; }); return model; } /** * Include one relation to one model. */ async includeRelation(model, relation) { switch (relation.type) { case 'hasOne': return HasOneRelation.load(model, relation); case 'hasMany': return HasManyRelation.load(model, relation); case 'hasOneThrough': return HasOneThroughRelation.load(model, relation); case 'hasManyThrough': return HasManyThroughRelation.load(model, relation); case 'belongsTo': return BelongsToRelation.load(model, relation); case 'belongsToMany': return BelongsToManyRelation.load(model, relation); default: return model; } } /** * Include all relations to one model. */ async includeRelations(model) { const relations = this.schema.getIncludedRelations(); if (!relations || !relations.length) { return model.setOriginal(); } for (const relation of relations) { model = await this.includeRelation(model, relation); } if (!model) { return undefined; } return model.setOriginal(); } /** * Include one relation for all models. */ async includeRelationOfAll(models, relation) { switch (relation.type) { case 'hasOne': return HasOneRelation.loadAll(models, relation); case 'hasMany': return HasManyRelation.loadAll(models, relation); case 'hasOneThrough': return HasOneThroughRelation.loadAll(models, relation); case 'hasManyThrough': return HasManyThroughRelation.loadAll(models, relation); case 'belongsTo': return BelongsToRelation.loadAll(models, relation); case 'belongsToMany': return BelongsToManyRelation.loadAll(models, relation); default: return models; } } /** * Include all relations for all models. */ async includeRelationsOfAll(models) { const relations = this.schema.getIncludedRelations(); if (!relations || !relations.length) { return models.map(model => model.setOriginal()); } for (const relation of relations) { models = await this.includeRelationOfAll(models, relation); } return models.map(model => model.setOriginal()); } }