npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

agnostic-migrator

v1.0.0

Published

A data storage-agnostic migration library

Downloads

6

Readme

agnostic-migrator

A data storage-agnostic migration library. It does not come with batteries.

The migration logic is simple but should work for most applications.


Usage

You will need to implement the following interfaces,

  • StateStorage

    A persistent storage interface for keeping track of which migrations were completed, and whether it is safe to run a migration.

    You may find the interface here

    You may find an in-memory implementation here

  • Migration

    Performs up and down migrations.

    You may find the interface here

    You may find a mock implementation here


/**
 * Assume you have implemented the `StateStorage` and `Migration` interfaces
 */
import {MySqlStateStorage, MySqlMigration, CustomMigration} from "my-implementation";
import * as migrator from "agnostic-migrator";

const stateStorage = new MySqlStateStorage();
/**
 * The order of migrations specified in this array is important.
 */
const migrations = [
    new MySqlMigration({
        identifier : "a-unique-identifier-000",
        description : "This is the very first migration",
        upSqlFile : `${__dirname}/sql/migration-000-up.sql`,
        downSqlFile : `${__dirname}/sql/migration-000-down.sql`,
    }),
    new MySqlMigration({
        identifier : "a-unique-identifier-001",
        description : "This is the second migration",
        upSqlFile : `${__dirname}/sql/migration-001-up.sql`,
        downSqlFile : `${__dirname}/sql/migration-001-down.sql`,
    }),
    new MySqlMigration({
        identifier : "a-unique-identifier-002",
        description : "This is the third migration",
        upSqlFile : `${__dirname}/sql/migration-002-up.sql`,
        downSqlFile : `${__dirname}/sql/migration-002-down.sql`,
    }),
    /**
     * Assume this is some crazy `Migration` implementation that requires calling an external API,
     * or executing a bash file, or consulting a blockchain ledger,
     * or some other complicated thing.
     */
    new CustomMigration(),
    /**
     * snip other migrations
     */
];

migrator.migrateUp({
    migrations,
    stateStorage,
    /**
     * When no `identifier` is specified,
     * it runs an up-migration on the very first "pending" up migration
     * found in the `migrations` array.
     */
    identifier : undefined,
});

migrator.migrateUp({
    migrations,
    stateStorage,
    /**
     * When an `identifier` is specified,
     * it runs an up-migration on the specified migration,
     * if it is pending.
     */
    identifier : "a-unique-identifier-002",
});

/**
 * It runs all up-migrations in the `migrations` array.
 * It skips over up-migrations that have already been run.
 */
migrator.migrateUpToLatest({
    migrations,
    stateStorage,
});

migrator.migrateDown({
    migrations,
    stateStorage,
    /**
     * When no `identifier` is specified,
     * it runs a down-migration on the very last successful up migration.
     */
    identifier : undefined,
});

migrator.migrateDown({
    migrations,
    stateStorage,
    /**
     * When an `identifier` is specified,
     * it runs a down-migration on the specified migration,
     * if it is a successful up migration.
     */
    identifier : "a-unique-identifier-002",
});

/**
 * It runs down-migrations on all migrations in the last up-migration **batch**.
 * It skips over down-migrations that have already been run.
 */
migrator.rollbackLastBatch({
    migrations,
    stateStorage,
});

/**
 * It runs down-migrations on all migrations in the `migrations` array.
 * It skips over down-migrations that have already been run.
 */
migrator.rollbackAll({
    migrations,
    stateStorage,
});

You may find more usage samples in these test files,


Concepts

  • New Migration

    A Migration that has not been run. Ever. Not upwards. Not downwards.

  • Successful Up Migration

    A Migration that was up-migrated successfully.

    If you run a down-migration on migrationA and then run an up-migration, then migrationA is considered a successful up migration.

  • Successful Down Migration

    A Migration that was down-migrated successfully.

    If you run an up-migration on migrationA and then run a down-migration, then migrationA is considered a successful down migration.

  • Pending Up Migration

    A Migration that is either new, or a successful down migration.

  • Batch

    Up-migrations are run in batches. A batch may contain one-to-many up-migrations.

    A batch is identified by a batchNumber.


migrateUp()

With no identifier specified, it goes through the migrations array and looks for the first Migration that is a pending up migration.

If such a pending up Migration is found, an up-migration is run on it. Otherwise, no migration is performed.


With an identifier specified, it uses the specified Migration.

If the Migration is a pending up migration, an up-migration is run on it. Otherwise, no migration is performed.


migrateUpToLatest()

It iterates through the migrations array, and runs an up-migration on all pending up migrations.

If there are no pending up migrations, then no migrations are performed.


migrateDown()

With no identifier specified, it goes through the migrations array and looks for the last Migration that is a successful up migration.

If such a successful up Migration is found, a down-migration is run on it. Otherwise, no migration is performed.


With an identifier specified, it uses the specified Migration.

If the Migration is a successful up migration, a down-migration is run on it. Otherwise, no migration is performed.


rollbackLastBatch()

When an up-migration is performed (migrateUp()/migrateUpToLatest()), one or more migrations may get added to a batch.

Each batch is identified by a batch number.

The last batch should have a batch number that is larger than all other batch numbers.

When you rollback the last batch, it finds all successful up migrations in that batch and runs down-migrations on them.

The down-migrations are run in reverse order. The order depends on the migrations array.


rollbackAll()

When you rollback all migrations, it finds all successful up migrations and runs down-migrations on them.

The down-migrations are run in reverse order. The order depends on the migrations array.