All files / src Migrate.js

62.79% Statements 27/43
50% Branches 4/8
57.14% Functions 8/14
62.79% Lines 27/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 1x 1x       1x 1x         1x 1x 1x 1x 1x 1x     1x                                                           1x               1x     1x   1x 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;
            Iif (!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) => {
                Iif (err) {
                    reject(err);
                } else {
                    // @ts-ignore
                    set.up((er) => {
                        Iif (er) {
                            reject(er);
                        } else {
                            resolve();
                        }
                    });
                }
            });
        });
    }
 
}
 
module.exports = Migrate;