maestro-server/server-app

View on GitHub
app/core/repositories/daos/DBConnector.js

Summary

Maintainability
C
1 day
Test Coverage
C
77%
'use strict';

const _ = require('lodash');
const Promise = require('bluebird');
const Connector = require('./connector/connector');
const Model = require('./connector/model');
const bcrypt = require('bcrypt');
const crypto = require('core/libs/crypto');

class Dao extends Model {

    _db() {
        let db = this.db ? this.db() : Connector._connection;
        return Promise.resolve(db);
    }

    _collection() {
        return this._db().then((db) => {
            if (_.isString(this.collection))
                return Connector._collection(db, this.collection);
    
            let defaultName = this.constructor.name.toLowerCase();
            let name = _.result(this, 'collection', defaultName);

            this.collection = this.constructor.prototype.collection = name;
    
            return Connector._collection(db, this.collection);
        });
    }

    get(key) {
        let value = key ? _.get(this.attributes, key) : this.attributes;
        return value && value.constructor === Object ? _.clone(value) : value;
    }
    
    set(key, value) {
        // if object passed instead of key-value pair
        // iterate and call set on each item
        if (_.isObject(key)) {
            let attrs = key;
 
            Object.keys(attrs).forEach((k) => {
                this.set(k, attrs[k]);
            });
    
            return;
        }
    
        // check if the value actually changed
        let previousValue = this.get(key);
    
        if (previousValue !== value) {
            _.set(this.previous, key, previousValue);
            _.set(this.attributes, key, value);
            _.set(this.changed, key, true);
        }
    
        return value;
    }
    
    save(options) {
        let id = this.get('_id');
        let fn = id ? this.update : this.create;
    
        if (!options)
            options = {};
    
        let populate = this.options.populate || {};
    
        Object.keys(populate).forEach((key) => {
            let value = this.get(key);
    
            if (Array.isArray(value)) {
                value = value.map((doc) => doc.get('_id'));
            } else {
                value = value.get('_id');
            }
    
            this.set(key, value);
        });
    
        return fn.call(this, options);
    }
    
    create() {
        let attrs = this.attributes;
        this.passHash();
        let date = new Date();
    
        this.set({
            'created_at': date,
            'updated_at': date
        });
    
        return this._collection()
            .then((collection) => collection.insertOne(attrs))
            .then((inserted) => {
                let doc = inserted.ops[0];
                this.set('_id', doc._id);
            })
            .return(this);
    }
    
    
    update() {
        let attrs = this.attributes;
        this.passHash();
    
        this.set('updated_at', new Date());
    
        return this._collection()
            .then((collection) => collection.updateOne({ _id: attrs._id }, attrs))
            .return(this);
    }
    
    passHash() {
        if (this.get('password'))
            this.set('password', this.makeHash(this.get('password')));
    }
    
    makeHash(string) {
        return bcrypt.hashSync(string, crypto.getCryptLevel());
    }
    
    inc(props) {
        let id = this.get('_id');
    
        if (!id)
            throw new Error('Can\'t atomically increment a property of unsaved document.');
    
        return this._collection()
            .then( (collection) => collection.updateOne({ _id: id }, { '$inc': props }))
            .then(() => {
                Object.keys(props).forEach((key) => {
                    let value = this.get(key);
                    value += props[key];
                    this.set(key, value);
                });
            })
            .return(this);
    }

    updateFull(filter, options) {
        this.set('updated_at', new Date());

        let entity = filter;
        let entry = null;

        this.passHash();

        return this._collection()
            .then((collection) => {
                const subs = entry ? {[entry]: this.get()} : this.get();
                return collection.replaceOne(entity, subs, options);
            })
            .then((e) => {
                return this.isUpdater = e.result;
            })
            .return(this);
    }

    updateAndModify(filter, options) {
        const opts = _.get(options, 'oUpdater', '');
        const opp = `update${opts}Factory`;
        this.set('updated_at', new Date());

        return this[opp](filter, '$set', options);
    }

    updateByPushUnique(filter, options) {
        const opts = _.get(options, 'oUpdater', '');
        const opp = `update${opts}Factory`;

        return this[opp](filter, '$addToSet', options);
    }

    updateByPull(filter, options) {
        const opts = _.get(options, 'oUpdater', '');
        const opp = `update${opts}Factory`;

        return this[opp](filter, '$pull', options);
    }

    incrementBY(filter, options) {
        const {oUpdater} = options;
        const opp = `update${oUpdater||''}Factory`;

        return this[opp](filter, '$inc', options);
    }

    updateFactory(entity, entry, options) {

        this.passHash();

        return this._collection()
            .then((collection) => {
                const subs = entry ? {[entry]: this.get()} : this.get();
                return collection.updateOne(entity, subs, options);
            })
            .then((e) => {
                return this.isUpdater = e.result;
            })
            .return(this);
    }

    updateManyFactory(entity, entry, options) {

        return this._collection()
            .then((collection) => {
                const subs = entry ? {[entry]: this.get()} : this.get();
                return collection.updateMany(entity, subs, options);
            })
            .then((e) => {
                return this.isUpdater = e.result;
            })
            .return(this);
    }

    updateBatch(data, options) {

        return this._collection()
            .then((collection) => {
                return collection.bulkWrite(data, options);
            })
            .then((e) => {
                return this.isBatch = e;
            })
            .return(this);
    }
}

module.exports = Dao;