@sscovil/migrate

A simple Node.js database migration utility that works with ES Module syntax.

Usage no npm install needed!

<script type="module">
  import sscovilMigrate from 'https://cdn.skypack.dev/@sscovil/migrate';
</script>

README

Migrate

A simple Node.js database migration utility that works with ES Module syntax.

Installation

yarn add @sscovil/migrate
# OR
npm install @sscovil/migrate

Usage

Suppose your application directory structure looks like this:

app/
├─ node_modules/
├─ src/
│  ├─ db/
│  │  └─ migrations/
│  │     ├─ 0001_create-table-films.sql
│  │     └─ 0002_create-table-distributors.sql
│  └─ app.js
├─ package.json
└─ README.md

...and you want to be able to run your SQL database migrations, located in the src/db/migrations/ directory.

In this case, you might add a file called src/db/migrate.js like this:

// ES Module syntax
import migrate from "@sscovil/migrate";
import pg from "pg";

// CommonJS syntax
// const migrate = require("@sscovil/migrate");
// const pg = require("pg");
// const path = require("path");

// This example uses node-postgres, but any SQL client with a similar query() method should work
const db = new pg.Client();

// ES Module syntax
const directory = new URL("./migrations", import.meta.url).pathname;

// CommonJS syntax
// const directory = path.join(__dirname, "migrations");

// If you use a PostgreSQL schema, you can include that in the table name (ex: "foobar.migrations")
const table = "migrations";

// Immediately Invoked Function Expression (IIFE)
(async () => {
    try {
        await db.connect();
        const result = await migrate(db, directory, table);
        await db.end();
        console.log(result);
    } catch (err) {
        console.error(err);
    }
})();

...and then run it like this:

node src/db/migrate.js

Return Value

The migrate function returns a Promise that resolves with an object like this:

{
    success: boolean,
    message: string,
    count: integer,
    lastRun: string|null,
    error: Error|null,
    code: string|null
}

success

The success field will be true if the function ran without error, even if there were no new migrations to run.

message

The message field is a human-readable description of the results.

count

The count field will indicate the number of migrations run.

lastRun

The lastRun field will be the filename of the last migration run, or null if no migrations were run.

error

The error field will contain the actual Error object that was thrown, or null if no error was thrown.

code

The code field will contain an error code that can be referenced below when troubleshooting.

Error Codes

Error codes are prefixed with DB or FS, indicating whether the error occurred at the database or filesystem.

Code Description Troubleshooting
DB01 Error creating migrations database table Ensure database user can CREATE TABLE in the current db/schema
DB02 Error querying migrations database table Ensure database user can SELECT records in the migrations table
DB03 Error executing SQL contained in a migration file Check for SQL errors in your migration file
FS01 Error reading files from the migrations directory Ensure migrations directory exists and user has read access
FS02 One or more previously run migration files not found Replace any missing files for previously run migrations
FS03 Order of previously run migration files has changed Ensure migration filenames are sequential
FS04 Contents of a previously run migration file have changed Revert changes to any previously run migration files

Running Tests

The test suite for this library requires you to have Docker and Docker Compose installed. This ensures that the test database is a clean PostgreSQL installation, and the server running the tests is using Node.js v16 (LTS) with the experimental-vm-modules flag for Jest ES Module support.

To run tests, use:

yarn run test
# OR
npm test