UNPKG

@reldens/storage

Version:
357 lines (316 loc) 11.4 kB
/** * * Reldens - MikroOrmDriver * */ const { BaseDriver } = require('../base-driver'); const { ErrorManager, Logger, sc } = require('@reldens/utils'); class MikroOrmDriver extends BaseDriver { constructor(props) { // @TODO - BETA - Finish implementation. super(props); if(!props.orm){ ErrorManager.error('Missing ORM on Mikro ORM driver.'); } if(!props.server){ ErrorManager.error('Missing Server Driver on Mikro ORM driver.'); } if(!this.rawModel){ ErrorManager.error('Missing raw entity on Mikro ORM driver.'); } this.orm = props.orm; this.server = props.server; this.repository = this.orm.em.getRepository(this.rawModel); } databaseName() { return this.config.dbName || ''; } id() { return this.rawModel.entity.name || this.name(); } name() { return this.rawModel.entity.name || this.config.dbName; } tableName() { return this.rawModel.entity.name; } property(propertyName) { return this.rawModel[propertyName] || null; } async create(params) { let newInstance = await this.orm.em.create(this.rawModel, params); await this.orm.em.upsert(newInstance); return newInstance; } async createWithRelations(params, relations) { let newInstance = await this.create(params, relations); await this.createNested(newInstance, params); return newInstance; } async update(filters, updatePatch) { let entities = await this.repository.find(filters, this.queryBuilder(true, true, true)); if(0 === entities.length){ return false; } for(let entity of entities){ Object.assign(entity, updatePatch); await this.orm.em.upsert(entity); await this.orm.em.flush(); } return entities; } async updateBy(field, fieldValue, updatePatch, operator = null) { let filter = this.createSingleFilter(field, fieldValue, operator); let entities = await this.repository.find(filter, this.queryBuilder(true, true, true)); if(0 === entities.length){ return false; } for(let entity of entities){ Object.assign(entity, updatePatch); await this.orm.em.upsert(entity); await this.orm.em.flush(); } return entities; } updateById(id, params) { return this.update({id}, params); } async upsert(params, filters) { if(params.id){ let patch = Object.assign({}, params); delete patch.id; return this.updateById(params.id, patch); } if(filters){ let existent = await this.loadOne(filters); if(existent){ return this.updateById(existent.id, params); } } return this.create(params); } async delete(filters = {}) { let entries = await this.load(filters); if (!entries){ return false; } for(let entry of Object.keys(entries)){ await this.repository.nativeDelete(entry.id); } } deleteById(id) { return this.repository.nativeDelete(id); } async count(filters) { return this.repository.count(filters); } async countWithRelations(filters, relations) { // @TODO - BETA - Look a way to filter by sub-entities properties before count. return this.count(filters); } loadAll() { return this.repository.findAll(); } async loadAllWithRelations(relations) { let entities = await this.loadAll(); return await this.appendRelationsToCollection(entities, relations); } load(filters) { return this.repository.find(filters, this.queryBuilder(true, true, true)); } async loadWithRelations(filters, relations) { let entitiesCollection = await this.repository.findAll(filters, this.queryBuilder(true, true, true)); return await this.appendRelationsToCollection(entitiesCollection, relations); } loadBy(field, fieldValue, operator = null) { let filter = this.createSingleFilter(field, fieldValue, operator); return this.repository.find(filter, this.queryBuilder(true, true, true)); } async loadByWithRelations(field, fieldValue, relations, operator = null) { let filter = this.createSingleFilter(field, fieldValue, operator); let entitiesCollection = await this.repository.find(filter, this.queryBuilder(true, true, true)); return await this.appendRelationsToCollection(entitiesCollection, relations); } loadById(id) { return this.loadBy({id}); } async loadByIdWithRelations(id, relations) { let entity = await this.loadBy({id}); return await this.appendRelationsToCollection(entity, relations); } loadByIds(ids) { this.repository.find({id: {$in: ids}}); } loadOne(filters) { return this.repository.findOne(filters, this.queryBuilder(false, true, true)); } async loadOneWithRelations(filters, relations) { let entitiesCollection = await this.loadOne(filters); return this.appendRelationsToCollection(entitiesCollection, relations); } loadOneBy(field, fieldValue, operator = null) { let filter = this.createSingleFilter(field, fieldValue, operator); return this.repository.findOne(filter, this.queryBuilder(false, true, true)); } async loadOneByWithRelations(field, fieldValue, relations, operator = null) { let filter = this.createSingleFilter(field, fieldValue, operator); let entitiesCollection = await this.repository.findOne(filter, this.queryBuilder(false, true, true)); return this.appendRelationsToCollection(entitiesCollection, relations); } // @TODO - BETA - Refactor and improve. queryBuilder(useLimit = false, useOffset = false, useSort = false) { let queryBuilder = {}; if(0 < this.select.length){ queryBuilder.select(...this.select); } if(useLimit && 0 !== this.limit){ queryBuilder.limit = this.limit; } if(useOffset && 0 !== this.offset){ queryBuilder.offset = this.offset; } if(useSort && false !== this.sortBy && false !== this.sortDirection){ queryBuilder.orderBy = { [this.sortBy]: this.sortDirection, }; } return queryBuilder; } // @TODO - BETA - Refactor and improve. createSingleFilter(field, fieldValue, operator = null) { let filter = {}; if(null === operator) { filter[field] = fieldValue; return filter; } filter[field] = {}; filter[field][operator] = fieldValue; return filter; } // @TODO - BETA - Refactor and improve. async appendRelationsToCollection(entitiesCollection, relations) { // @TODO - BETA - Refactor. I would like to use populate but it may not work if the driver is not Mongo DB. if('function' !== typeof this.rawModel.entity.relationMappings){ return entitiesCollection; } if(!sc.isArray(relations) || 0 === relations.length){ relations = Object.keys(this.rawModel.entity.relationMappings() || {}); } if(0 === relations.length){ return entitiesCollection; } if(sc.isArray(entitiesCollection)){ for(let entity of entitiesCollection){ await this.appendRelatedEntities(entity, relations); } } if(!sc.isArray(entitiesCollection)){ await this.appendRelatedEntities(entitiesCollection, relations); } return entitiesCollection; } // @TODO - BETA - Refactor and improve. async appendRelatedEntities(entity, relations) { if('function' !== typeof this.rawModel.entity.relationMappings){ return entity; } let relationMappings = this.rawModel.entity.relationMappings(); for(let i of relations){ let relation = relationMappings[i]; let relationRepository = this.server.getEntity(relation.entityName); let isManyToOne = 'm:1' === relation.reference; let isOneToMany = '1:m' === relation.reference; if(isManyToOne){ entity[i] = await relationRepository.loadOneBy(relation.join.to, entity[relation.join.from]); } if(isOneToMany){ entity[i] = await relationRepository.loadBy(relation.join.to, entity[relation.join.from]); } } return entity; } // @TODO - BETA - Refactor and improve. async createNested(newInstance, params) { if('function' !== typeof this.rawModel.entity.relationMappings){ return false; } let relationMappings = this.rawModel.entity.relationMappings(); for(let i of Object.keys(relationMappings)){ let relation = relationMappings[i]; let relationEntity = this.server.entityManager.get(relation.entityName).rawModel.entity; if(!relationEntity){ Logger.warning('Factory not found for relation definition:', relation); continue; } let isArray = sc.isArray(params); if(!isArray){ if(!sc.hasOwn(params, relation.join.from) || !params[relation.join.from]){ continue; } await this.createOne(params, i, relationEntity, newInstance, relation); continue; } if(isArray){ await this.createMany(params, i, relationEntity, newInstance, relation); } } } // @TODO - BETA - Refactor and improve. async createOne(params, i, relationEntity, newInstance, relation) { params[i] = newInstance[relation.join.from]; let nestedObject = relationEntity.createByProps(params[i]); await this.repository.persist(nestedObject).flush(); await this.orm.em.flush(); newInstance[i] = nestedObject; } // @TODO - BETA - Refactor and improve. async createMany(params, i, relationEntity, newInstance, relation) { let nestedArray = []; for(let objectData of params[i]){ objectData[relation.join.to] = newInstance[relation.join.from]; let nestedObject = relationEntity.createByProps(objectData); await this.repository.persist(nestedObject).flush(); await this.orm.em.flush(); nestedArray.push(nestedObject); } newInstance[i] = nestedArray; } } module.exports.MikroOrmDriver = MikroOrmDriver;