trex-arms / ley

(WIP) Driver-agnostic database migrations

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

ley
Driver agnostic database migrations

TODO

WIP: What's here is the end of Night #1

Features

  • Agnostic
    Supports postgres, pg, better-sqlite3, sqlite, mysql, and mysql2

  • Lightweight
    Does not include any driver dependencies.

  • Transactional
    Runs all migration files within a transaction for rollback safety.

  • Familiar
    Does not invent new syntax or abstractions.
    You're always working directly with your driver of choice.

  • Flexible
    Find the CLI to restrictive? You may require ley for your own scripting!

Install

$ npm install --save-dev ley

Usage

Both Programmatic and CLI usages are supported.

Setup

You must have a migrations directory created, preferably in your project's root.

Note: You may configure the target directory and location.

Your filenames within this directory determine the order of their execution.
Because of this, it's often recommended to prefix migrations with a timestamp or numerical sequence.

Numerical Sequence

/migrations
  |-- 000-users.js
  |-- 001-teams.js
  |-- 002-seats.js

Note: You may create the next file via ley new todos --length 3 where todos is a meaningful name.
The above command will create the migrations/003-todos.js filepath.

Timestamped

/migrations
  |-- 1581323445-users.js
  |-- 1581323453-teams.js
  |-- 1581323458-seats.js

Note: You may create the next file via ley new todos --timestamp where todos is a meaningful name.
The above command will create the migrations/1584389617-todos.js filepath...or similar.

The order of your migrations is critically important!
Migrations must be treated as an append-only immutable task chain. Without this, there's no way to reliably rollback or recreate your database.

Example: (Above) You cannot apply/create 001-teams.js after 002-seats.js has already been applied.
Doing so would force your teammates or database replicas to recreate "the world" in the wrong sequence.
This may not always pose a problem (eg, unrelated tasks) but it often does and so ley enforces this practice.

Lastly, each migration file must have an up and a down task.
These must be exported functions — async okay! — and will receive your pre-installed client driver as its only argument:

exports.up = async function (DB) {
  // with `pg` :: DB === pg.Client
  await DB.query(`select * from users`);

  // with `postgres` :: DB === sql``
  await DB`select * from users`;
}

exports.down = async function (DB) {
  // My pre-configured "undo" function
}

CLI

  1. Add ley as one of your package.json scripts; "migrate", for example:

    // package.json
    {
      "scripts": {
        "migrate": "ley"
      }
    }
  2. Invoke ley up to apply new migrations, or ley down to rollback previous migrations.

    $ npm run migrate up
    $ yarn migrate up

    ley up screenshot #1
    ley up screenshot #2
    ley up screenshot #3

Programmatic

Note: See API for documentation

With programmatic/scripting usage, you will not inherit any of ley's CLI tooling, which includes all colors and error formatting. Instead, you must manually catch & handle all thrown Errors.

const ley = require('ley');

const successes = await ley.up({ ... });

API

ley.up(opts?)

Returns: Promise<string[]>

Returns a list of the relative filenames (eg, 000-users.js) that were successfully applied.

opts.cwd

Type: string
Default: .

A target location to treat as the current working directory.

Note: This value is path.resolve()d from the current process.cwd() location.

opts.dir

Type: string
Default: migrations

The directory (relative to opts.cwd) to find migration files.

opts.client

Type: string
Default: undefined

The name of your desired client driver; for example, pg.
When unspecified, ley searches for all supported client drivers in this order:

['postgres', 'pg']; // TODO: more

opts.config

Type: object
Default: undefined

A configuration object for your client driver to establish a connection.
When unspecified, ley assumes that your client driver is able to connect through process.env variables.

Note: The ley CLI will search for a ley.config.js config file (configurable).
If found, this file may contain an object or a function that resolves to your config object.

opts.single

Type: boolean
Default: false

Enable to apply only one migration file's up task.
By default, all migration files will be queue for application.

ley.down(opts?)

Returns: Promise<string[]>

Returns a list of the relative filenames (eg, 000-users.js) that were successfully applied.

opts.cwd

Type: string
Default: .

A target location to treat as the current working directory.

Note: This value is path.resolve()d from the current process.cwd() location.

opts.dir

Type: string
Default: migrations

The directory (relative to opts.cwd) to find migration files.

opts.client

Type: string
Default: undefined

The name of your desired client driver; for example, pg.
When unspecified, ley searches for all supported client drivers in this order:

['postgres', 'pg']; // TODO: more

opts.all

Type: boolean
Default: false

Enable to apply all migration files' down task.
By default, only the most recently-applied migration file is invoked.

ley.new(opts?)

Returns: Promise<string>

Returns the newly created relative filename (eg, 000-users.js).

opts.filename

Type: string

Required. The name of the file to be created.

Note: A prefix will be prepended based on opts.timestamp and opts.length values.
The .js extension will be applied unless your input already has an extension.

opts.timestamp

Type: boolean
Default: false

Should the migration file have a timestamped prefix?
If so, will use Date.now() floored to the nearest second.

opts.length

Type: number
Default: 5

When not using a timestamped prefix, this value controls the prefix total length.
For example, 00000-users.js will be followed by 00001-teams.js.

opts.cwd

Type: string
Default: .

A target location to treat as the current working directory.

Note: This value is path.resolve()d from the current process.cwd() location.

opts.dir

Type: string
Default: migrations

The directory (relative to opts.cwd) to find migration files.

License

MIT © Luke Edwards

About

(WIP) Driver-agnostic database migrations

License:MIT License


Languages

Language:JavaScript 100.0%