All files Migrate.js

13.95% Statements 6/43
0% Branches 0/8
0% Functions 0/14
13.95% Lines 6/43

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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          1x 1x 1x 1x 1x                                                                                                                                                                                                     1x  
/**
 * @author David Menger
 */
'use strict';
 
const loadMigrationsIntoSet = require('migrate/lib/load-migrations');
const migrate = require('migrate');
const mssql = require('mssql');
const { format } = require('sqlstring');
const MigrationSet = require('./MigrationSet');
 
class Migrate {
 
    /**
     *
     * @param {Promise<mssql.ConnectionPool>} pool
     * @param {string} migrationsPath
     * @param {string} tableName
     */
    constructor (pool, migrationsPath, tableName = 'migrations') {
        this._pool = pool;
        this._tableName = tableName;
        this._migrationsPath = migrationsPath;
    }
 
    load (cb) {
        this._load()
            .then((set) => cb(null, set))
            .catch((e) => cb(e));
    }
 
    async _load () {
        const cp = await this._pool;
        try {
            const r = cp.request();
            const res = await r.query(`SELECT TOP 1 data FROM ${this._tableName} WHERE id=1`);
            const [item = null] = res.recordset;
            if (!item) {
                return { lastRun: null, migrations: [] };
            }
            return JSON.parse(item.data);
        } catch (e) {
            const r = cp.request();
            await r.query(`CREATE TABLE ${this._tableName} (id int, data text)`);
            return { lastRun: null, migrations: [] };
        }
    }
 
    save (set, cb) {
        this._save(set)
            .then(() => cb())
            .catch((e) => cb(e));
    }
 
    async _save (set) {
        const cp = await this._pool;
        const r = cp.request();
 
        await r
            .input('data', mssql.Text, JSON.stringify(set))
            .query(`MERGE INTO ${this._tableName} AS target
                USING (SELECT 1 as id) AS source (id)
                ON source.id = target.id
                WHEN MATCHED THEN
                    UPDATE SET data = @data
                WHEN NOT MATCHED THEN
                    INSERT (id, data) VALUES (1, @data);`);
    }
 
    migrate () {
        const query = async (string, ...args) => {
            const q = await this._pool;
 
            const r = q.request();
 
            return r.query(format(string, args));
        };
 
        const set = new MigrationSet(this, query);
 
        // @ts-ignore
        migrate.set = set;
 
        return new Promise((resolve, reject) => {
            loadMigrationsIntoSet({
                set,
                store: this,
                ignoreMissing: true,
                migrationsDirectory: this._migrationsPath
            }, (err) => {
                if (err) {
                    reject(err);
                } else {
                    // @ts-ignore
                    set.up((er) => {
                        if (er) {
                            reject(er);
                        } else {
                            resolve();
                        }
                    });
                }
            });
        });
    }
 
}
 
module.exports = Migrate;