Procházet zdrojové kódy

Jemba-миграции

Book Pauk před 3 roky
rodič
revize
b5db2079d2

+ 86 - 5
server/db/JembaConnManager.js

@@ -1,9 +1,15 @@
 const fs = require('fs-extra');
+const _ = require('lodash');
 
 const ayncExit = new (require('../core/AsyncExit'))();//singleton
 const { JembaDb, JembaDbThread } = require('./JembaDb');
 const log = new (require('../core/AppLogger'))().log;//singleton
 
+const jembaMigrations = {
+    //'app': require('./jembaMigrations/app'),
+    'reader-storage': require('./jembaMigrations/reader-storage'),
+};
+
 let instance = null;
 
 //singleton
@@ -25,6 +31,8 @@ class JembaConnManager {
         this.config = config;
         this._db = {};
 
+        const force = null;//(config.branch == 'development' ? 'last' : null);
+
         for (const dbConfig of this.config.db) {
             const dbPath = `${this.config.dataDir}/db/${dbConfig.dbName}`;
 
@@ -69,18 +77,91 @@ class JembaConnManager {
             log(`Open "${dbConfig.dbName}" finish`);
 
             //миграции
-            /*const migs = migrations[dbConfig.poolName];
-            if (migs && migs.data.length) {
-                const applied = await connPool.migrate(migs.data, migs.table, force);
+            const mig = jembaMigrations[dbConfig.dbName];
+            if (mig && mig.data) {
+                const applied = await this.migrate(dbConn, mig.data, mig.table, force);
                 if (applied.length)
-                    log(`${applied.length} migrations applied to "${dbConfig.poolName}"`);
-            }*/
+                    log(`${applied.length} migrations applied to "${dbConfig.dbName}"`);
+            }
 
             this._db[dbConfig.dbName] = dbConn;
         }
         this.inited = true;
     }
 
+    async migrate(db, migs, table, force) {
+        const migrations = _.cloneDeep(migs).sort((a, b) => a.id - b.id);
+
+        if (!migrations.length) {
+            throw new Error('No migration data');
+        }
+
+        migrations.map(migration => {
+            const data = migration.data;
+            if (!data.up || !data.down) {
+                throw new Error(`The ${migration.id}:${migration.name} does not contain 'up' or 'down' instructions`);
+            } else {
+                migration.up = data.up;
+                migration.down = data.down;
+            }
+            delete migration.data;
+        });
+
+        // Create a database table for migrations meta data if it doesn't exist
+        // id, name, up, down
+        await db.create({
+            table, 
+            quietIfExists: true,
+            hash: {field: 'id', type: 'number'}
+        });
+
+        // Get the list of already applied migrations
+        let dbMigrations = await db.select({
+            table,
+            sort: '(a, b) => a.id - b.id'
+        });
+
+        const execUpDown = async(items) => {
+            for (const item of items) {
+                const action = item[0];
+                await db[action](item[1]);
+            }
+        };
+
+        // Undo migrations that exist only in the database but not in migs,
+        // also undo the last migration if the `force` option was set to `last`.
+        const lastMigration = migrations[migrations.length - 1];
+        for (const migration of dbMigrations.slice().sort((a, b) => b.id - a.id)) {
+            if (!migrations.some(x => x.id === migration.id) ||
+                (force === 'last' && migration.id === lastMigration.id)) {
+                    await execUpDown(migration.down);
+                    await db.delete({
+                        table, 
+                        where: `@@hash('id', ${db.esc(migration.id)})`
+                    });
+                    dbMigrations = dbMigrations.filter(x => x.id !== migration.id);
+            } else {
+                break;
+            }
+        }
+
+        // Apply pending migrations
+        let applied = [];
+        const lastMigrationId = dbMigrations.length ? dbMigrations[dbMigrations.length - 1].id : 0;
+        for (const migration of migrations) {
+            if (migration.id > lastMigrationId) {
+                await execUpDown(migration.up);
+                await db.insert({
+                    table,
+                    rows: [migration],
+                });
+                applied.push(migration.id);
+            }
+        }
+
+        return applied;
+    }
+
     get db() {
         return this._db;
     }

+ 14 - 0
server/db/jembaMigrations/reader-storage/001-create.js

@@ -0,0 +1,14 @@
+module.exports = {
+    up: [
+        //CREATE TABLE storage (id TEXT PRIMARY KEY, rev INTEGER, time INTEGER, data TEXT);
+        ['create', {
+            table: 'storage',
+            hash: {field: 'id', type: 'string', depth: 100}
+        }],
+    ],    
+    down: [
+        ['drop', {
+            table: 'storage'
+        }],
+    ]
+};

+ 6 - 0
server/db/jembaMigrations/reader-storage/index.js

@@ -0,0 +1,6 @@
+module.exports = {
+    table: 'migration1',
+    data: [
+        {id: 1, name: 'create', data: require('./001-create')}
+    ]
+}