All files / framework/src/api/db/dao BasicDAO.js

57.81% Statements 37/64
56.25% Branches 9/16
58.06% Functions 18/31
59.32% Lines 35/59
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 2251x 1x 1x                           5x 1x   4x 4x       93x       4x                     4x 1x   3x   1x 1x                                                               2x                                                                                 12x 12x     12x 12x   12x 12x   1x 1x                       2x 1x   1x 1x                             4x 1x     3x 3x   1x 1x                       35x                                                                                     1x  
const _ = require('lodash');
const { Errors, options } = require('../../../constants');
const debug = require('../../../log')('BasicDAO');
 
/**
 * BasicDAO implementation with standard CRUD operations and query creator
 * @abstract
 */
class BasicDAO {
    /**
     * Constructor with model (required)
     * @param model {BasicModel} model class
     * @throws {AbstractClassConstructor} Cannot crate Basic class directly - subclass needed
     * @returns {BasicDAO}
     */
    constructor(model) {
        if (new.target === BasicDAO) {
            throw Error(Errors.AbstractClassConstructor('BasicDAO'));
        }
        this.setModel(model);
        return this;
    }
 
    getModel() {
        return this.model;
    }
 
    setModel(model) {
        this.model = model;
    }
 
    /**
     * Get entity by ID
     * @param id {number} entity id
     * @param context {ReqContext} request context
     * @throws {GetByIdFailed}
     * @returns {BasicModel} Promise that returns entity
     */
    getById(id, context) {
        if (!id) {
            throw new Error(Errors.InvalidArguments('BasicDAO.getById', 'id'));
        }
        return this.getModel().makeQuery((trx) => this.createQuery(trx, context).findById(id)
            .catch(err => {
                debug('GgetById error', err.message);
                throw new Error(Errors.GetByIdFailed('BasicDAO.getById'));
            }));
    }
 
    /**
     * Get entities by field value
     * @param field {Object} Field object
     * @param {string} field.name Database column name
     * @param {string} field.operation Operation for comparing values
     * @param {any} field.value Attribute value
     * @param context {ReqContext} request context
     * @throws {GetByFieldFailed}
     * @returns {BasicModel[]}Promise that returns list of entities
     */
    getByField(field, context) {
        return this.getModel()
            .makeQuery((trx) =>
                this.createQuery(trx, context)
                    .skipUndefined().where(field.name, field.operation, field.value))
            .catch(err => {
                debug('GetByField', err.message);
                throw new Error(Errors.GetByFieldFailed('BasicDAO'));
            });
    }
 
    /**
     * Get all entities
     * @param context {ReqContext} request context
     * @throws {GetAllFailed}
     * @returns {BasicModel[]} Promise that returns list of entites
     */
    getAll(context) {
        return this.getModel().makeQuery((trx) => this.createQuery(trx, context))
            .catch(err => {
                debug('GetAll', err.message);
                throw new Error(Errors.GetAllFailed('BasicDAO'));
            });
    }
 
    /**
     * Get entities by criteria array
     * @param filter {Object[]} Filter array
     * @param {string} filter[].name Database column name
     * @param {string} filter[].operation Operation for comparing values
     * @param {any} filter[].value Attribute value
     * @param context {ReqContext} request context
     * @throws {GetByCriteriaFailed}
     * @returns {BasicModel[]}Promise that returns list of entities
     */
    getByCriteria(filter, context) {
        return this.getModel().makeQuery(trx => {
            let query = this.createQuery(trx, context);
            if (_.isEmpty(filter)) return this.getAll(context);
            query = this.addWhere(query, filter[0].column, filter[0].value, filter[0].operation);
            if (filter.length === 1) return this.returnResult(query);
            for (let i = 1; i < filter.length; i += 1) {
                query = this.addAndWhere(query, filter[i].value, filter[i].column, filter[i].operation);
            }
            return this.returnResult(query);
        }).catch(err => {
            debug('GetByCriteria', err.message);
            throw new Error(Errors.GetByCriteriaFailed('BasicDAO'));
        });
    }
 
    /**
     * Create entity (graph style, with all relations)
     * @param data {BasicModel} data object
     * @param context {ReqContext} request context
     * @throws {CreateEntityFailed | InvalidArguments}
     * @returns {BasicModel} Promise that returns created entity
     */
    create(data, context) {
        const object = data;
        Iif (!object) {
            throw new Error(Errors.InvalidArguments('BasicDAO.create', 'object'));
        }
        return this.getModel().makeQuery(trx =>
            this.createQuery(trx, context).insertGraph({})
                .then(entity => {
                    object.id = entity.id;
                    return this.createQuery(trx, context).upsertGraph(object, options.UpsertOptions);
                }).catch(err => {
                    debug('Create', err.message);
                    throw new Error(Errors.CreateEntityFailed('BasicDAO'));
                }));
    }
 
    /**
     * Update entity (graph style, with all relations)
     * @param object {BasicModel} data object
     * @param context {ReqContext} request context
     * @throws {UpdateEntityFailed | InvalidArguments}
     * @returns {BasicModel} Promise that returns updated entity
     */
    update(object, context) {
        if (!object) {
            throw new Error(Errors.InvalidArguments('BasicDAO.update', 'object'));
        }
        return this.getModel().makeQuery(trx =>
            this.createQuery(trx, context).upsertGraph(object, options.UpsertOptions)
                .catch(err => {
                    debug('Update', err.message);
                    throw new Error(Errors.UpdateEntityFailed('BasicDAO'));
                }));
    }
 
    /**
     * Remove entity by id
     * @param id {number} id of entity to be removed
     * @param context {ReqContext} request context
     * @throws {RemoveEntityFailed | InvalidArguments}
     * @returns {Object} result
     */
    remove(id, context) {
        if (!id) {
            throw new Error(Errors.InvalidArguments('BasicDAO.remove', 'id'));
        }
 
        return this.getModel().makeQuery(trx =>
            this.createQuery(trx, context).deleteById(id)
                .catch(err => {
                    debug('Remove', err.message);
                    throw new Error(Errors.RemoveEntityFailed(err.message));
                }));
    }
 
    /**
     * Transactional query creator
     * @param trx {Objection.Transaction} transaction
     * @param context {ReqContext} request context
     * @returns {Objection.QueryBuilder<BasicModel>}
     * Transactional query builder transactional with request context injected
     */
    createQuery(trx, context) {
        return this.getModel().query(trx).eager(this.getModel().relations).context(context);
    }
 
    /**
     * Add where condition to query
     * @param query {Objection.QueryBuilder<BasicModel>} Query builder
     * @param field {Object} field
     * @param {string} field.name Database column name
     * @param {string} field.operation Operation for comparing values
     * @param {any} field.value Attribute value
     * @returns {Objection.QueryBuilder<BasicModel>}
     */
    addAndWhere(query, { name, value, operation = '=' }) {
        return query.andWhere(name, operation, value);
    }
 
    /**
     * Add first where condition to query
     * @param query {Objection.QueryBuilder<BasicModel>} Query builder
     * @param field {Object} field
     * @param {string} field.name Database column name
     * @param {string} field.operation Operation for comparing values
     * @param {any} field.value Attribute value
     * @returns {Objection.QueryBuilder<BasicModel>}
     */
    addWhere(query, { name, operation = '=', value }) {
        return query.skipUndefined().where(name, operation, value);
    }
 
    /**
     * Resolve query builder or log error and pass them to next catcher
     * @param query {Objection.QueryBuilder<BasicModel>} Query builder, that will be resolved
     * @returns {BasicEntity[]} Promise that return list of entities
     */
    returnResult(query) {
        return query.then(result => result)
            .catch((err) => {
                debug('Return result', err.message);
                throw err;
            });
    }
}
 
module.exports = BasicDAO;