Repository: rickbergfalk/sqlpad
Pull request #855 (2020-10-19 23:48:24)

Add getDbMajorVersion utility function
In preparation for v6 work we need a way to check for major version of a SQLPad's instance via the database. The migration scheme got a little messed up, and so this function will capture that complexity.

In order to migration to v6, databases must be on some version of v5, as some of the dependencies to do the migration from 4 to 5 are being dropped. 


Patch:
diff --git a/server/lib/make-migrator.js b/server/lib/make-migrator.js
index a8bf9b38..f83fc42a 100644
--- a/server/lib/make-migrator.js
+++ b/server/lib/make-migrator.js
@@ -29,11 +29,64 @@ function makeMigrator(config, appLog, nedb, sequelizeInstance) {
     migrate() {
       return umzug.up();
     },
+
     async schemaUpToDate() {
       const pending = await umzug.pending();
       const upToDate = pending.length === 0;
       return upToDate;
     },
+
+    async getDbMajorVersion() {
+      const executed = await umzug.executed();
+      if (executed.length === 0) {
+        return 0;
+      }
+
+      const migrationFileRegex = /\d\d-\d\d\d\d\d-(\w|-)+\.js/;
+
+      const migrationFiles = executed
+        .map((migration) => migration.file)
+        .sort()
+        .filter((name) => {
+          // regex.test() is stateful if /g is set
+          // It isn't in use now, but it was during initial dev and caused confusion
+          // Using string.search() to ensure this stops functioning in case of /g being set in future
+          return name.search(migrationFileRegex) > -1;
+        });
+
+      const lastMigrationFile = migrationFiles.pop();
+
+      // Migration files have format of 'nn-nnnnn-some-text.js'
+      // Those initial 2 numbers were intended on being the major version...
+      // but I messed that up pretty eary on 😬
+      //
+      // v5 migrations = anything starting with 05, or >= 04-00200
+      // 04-00200-nedb-sqlite-tables.js
+      // ... all the way to
+      // 05-00100-sessions.js
+      //
+      // v4 migrations = 04-00000 - 04-00199
+      // 04-00100-query-acl-schema.js
+      // ... all the way to
+      // 04-00129-service-tokens-schema.js
+      //
+      const [majorString, minorString] = lastMigrationFile.split('-');
+      const major = parseInt(majorString, 10);
+      const minor = parseInt(minorString, 10);
+
+      if (major === 5) {
+        return 5;
+      }
+
+      if (major === 4) {
+        if (minor >= 200) {
+          return 5;
+        }
+        return 4;
+      }
+
+      return -1;
+    },
   };
 }
 


Test patch:
diff --git a/server/test/migrations/get-db-major-version.js b/server/test/migrations/get-db-major-version.js
new file mode 100644
index 00000000..4487597d
--- /dev/null
+++ b/server/test/migrations/get-db-major-version.js
@@ -0,0 +1,61 @@
+/* eslint-disable no-await-in-loop */
+const assert = require('assert');
+const path = require('path');
+const ncp = require('ncp').ncp;
+const TestUtils = require('../utils');
+
+ncp.limit = 16;
+
+const sourceDir = path.join(__dirname, '../fixtures/v4.2.0-test-db/testdb');
+
+function copyDbFiles(source, destination) {
+  return new Promise((resolve, reject) => {
+    ncp(source, destination, function (err) {
+      if (err) {
+        return reject(err);
+      }
+      return resolve();
+    });
+  });
+}
+
+describe('migrations/get-db-major-version', function () {
+  /**
+   * @type {TestUtils}
+   */
+  let utils;
+
+  before('preps the env', async function () {
+    utils = new TestUtils({
+      dbPath: path.join(__dirname, '../artifacts/v4-to-v5'),
+      dbInMemory: false,
+      // Force this test to only run with SQLite
+      backendDatabaseUri: '',
+    });
+
+    const destination = utils.config.get('dbPath');
+
+    await utils.prepDbDir();
+    await copyDbFiles(sourceDir, destination);
+
+    await utils.initDbs();
+  });
+
+  after(function () {
+    return utils.sequelizeDb.sequelize.close();
+  });
+
+  it('Before migration - major version is 4', async function () {
+    const major = await utils.migrator.getDbMajorVersion();
+    assert.strictEqual(major, 4);
+  });
+
+  it('Migrates', async function () {
+    await utils.migrate();
+  });
+
+  it('After migration - major is 5', async function () {
+    const major = await utils.migrator.getDbMajorVersion();
+    assert.strictEqual(major, 5);
+  });
+});
diff --git a/server/test/migrations/make-migrator.js b/server/test/migrations/make-migrator.js
index 5c1c712c..b6d8a090 100644
--- a/server/test/migrations/make-migrator.js
+++ b/server/test/migrations/make-migrator.js
@@ -11,11 +11,17 @@ describe('lib/make-migrator', function () {
   it('Not up-to-date without running mirations', async function () {
     const upToDate = await utils.migrator.schemaUpToDate();
     assert(!upToDate);
+
+    const majorVersion = await utils.migrator.getDbMajorVersion();
+    assert.strictEqual(majorVersion, 0);
   });
 
   it('Up to date after running migrations', async function () {
     await utils.migrator.migrate();
     const upToDate = await utils.migrator.schemaUpToDate();
     assert(upToDate);
+
+    const majorVersion = await utils.migrator.getDbMajorVersion();
+    assert.strictEqual(majorVersion, 5);
   });
 });