Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sql-migrations-core

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sql-migrations-core

Database framework-agnostic solution for migrations with zero dependencies

  • 0.0.3
  • latest
  • Source
  • npm
  • Socket score

Version published
Maintainers
1
Created
Source

[WIP] SQL Migrations Core

npm node npm

Database framework-agnostic package for DIY migrations solutions with zero dependencies, written in TypeScript.

With sql-migrations-core you can write sql migrations as you want. Use ANY database framework and prepare CLI as you feel comfortable.

Table of Contents

Installation

Install with npm:

npm i sql-migrations-core

Or with yarn:

yarn add sql-migrations-core

...Or with pnpm:

pnpm add sql-migrations-core

Initialization

Minimal configuration looks like this:

const migrationsCore = MigrationsCore.create({
  path: path.join('..', 'path/to/migrations/dir'),
  sqlActions: {
    async createMigrationTable() {
      // TODO implement
    },
    async getMigrationsNames() {
      // TODO implement
      return [];
    },
    async migrateDown(migrations) {
      // TODO implement
    },
    async migrateUp(migrations) {
      // TODO implement
    },
  },
});

There is a trade-off - you can use any db framework, but you need to implement SQL queries by yourself. For example, with kysely:

import { db } from './database';

// Probably you'll want to move SQL logic to repository.
// In this example I'm just showing a minimal SQL implementation.

const migrationsCore = MigrationsCore.create({
  path: path.join('/migrations'),
  sqlActions: {
    async createMigrationTable() {
      await db.schema.createTable('__migrations')
        .ifNotExists()
        .addColumn('name', 'varchar', (cb) => cb.notNull().unique())
        .addColumn('migrated_at', 'timestamp', (cb) =>
          cb.notNull().defaultTo(sql`now()`)
        )
        .execute()
    },

    async getMigrationsNames() {
      const records = await db.selectFrom('__migrations')
        .select('name')
        .execute();
      return records.map(r => r.name);
    },

    async migrateDown(migrations) {
      await db.transaction().execute(async (trx) => {
        for (const migration of migrations) {
          await trx.deleteFrom('__migrations')
            .where({ name: migration.name })
            .execute();
          await sql`${migration.sql}`.execute(trx);
        }
      })
    },

    async migrateUp(migrations) {
      await db.transaction().execute(async (trx) => {
        for (const migration of migrations) {
          await trx.insertInto('__migrations')
            .values({ name: migration.name })
            .execute();
          await sql`${migration.sql}`.execute(trx);
        }
      })
    },
  },
});

See other examples here.

Usage

After initializing migrationsCore you can use methods:

await migrationsCore.createFiles('example'); // creates blank sql files

await migrationsCore.up(); // one migration up
await migrationsCore.down(); // one migration down
await migrationsCore.sync(); // all pending up migrations
await migrationsCore.drop(); // all down migrations of executed migrations
await migrationsCore.toLatest(); // all pending up migrations from last executed
await migrationsCore.to('123-example'); // all up/down migrations between last executed and provided

await migrationsCore.status(); // get statuses of migrations (name and is synced)

Also, you can pass chunkSize in some methods to run migrations by chunks in synchronous way:

await migrationsCore.sync(100); // runs migrations in chunks limit by 100 

See API for more info.

Migration files

Migrations core creates 2 migration files - up and down. It uses {timestamp}-${title}${postfix} format (name of migration is {timestamp}-{title}):

await migrationsCore.createFile('example');

// Will create something like this
// ./migrations/1718394484921-example.down.sql
// ./migrations/1718394484921-example.up.sql

CLI

There is no out-of-box CLI solution, so you need implement one by yourself. For example, create migration file:

import { migrationsCore } from './migrations-core';
import path from 'node:path';

const migrationsPath = path.join('./migrations');
migrationsCore.createFile(process.args[2]);

Usage:

node ./scripts/migrations-create.js example

See other CLI examples here.

API

There are several classes available to use:

  1. MigrationsCore - main class that gives access to all needed migration actions.
  2. LocalMigrations - class used by MigrationsCore. Hides all filesystem operations to access local migrations. For advanced usage.
  3. StoredMigrations - class used by MigrationsCore. Hides all database operations to run migrations and access metadata of executed migrations. For advanced usage.

Creating migrationsCore object

There are two ways to create instance of MigrationsCore:

  1. Using static MigrationsCore.create() method
  2. Using new MigrationsCore() constructor

Using create(config)

create() method receives config object and returns instance of MigrationsCore. Actually it's constructor wrapper, which creates LocalMigrations and StoredMigrations by itself. Config options are passed to these objects. Config options:

  • path - string, path to migrations directory. Used by LocalMigrations.
  • postfix - object, optional, custom postfix for migrations files. Used by LocalMigrations.
  • postfix.up - string, postfix for up migrations (default: .up.sql).
  • postfix.down - string, postfix for down migrations (default: .down.sql).
  • sqlActions - object, postfix for down migrations (default: .down.sql). Used by StoredMigrations.
  • sqlActions.createMigrationTable - function, used to create table before every StoredMigrations action. Recommended to use with IF NOT EXISTS statement.
  • sqlActions.migrateUp - function, used to run up migrations. Receives array of migration objects.
  • sqlActions.migrateDown - function, used to run down migrations. Receives array of migration objects.
  • sqlActions.getMigrationsNames - function, used to get executed migrations names. Should return array of migration names.
  • sqlActions.getLastMigrationName - function, optional, used to get last executed migrations name. Should return name or null. If function not provided - getMigrationsNames used instead.

Example:

const migrationsCore = MigrationsCore.create({
  path: path.join(__dirname, '../migrations'),
  postfix: {
    up: '.custom.up.sql',
    down: '.custom.down.sql',
  },
  sqlActions: {
    createMigrationTable() { /* ... */ },
    migrateUp(migrations) { /* ... */ },
    migrateDown(migrations) { /* ... */ },
    getMigrationsNames() { /* ... */ },
    getLastMigrationName() { /* ... */ },
  }
});

Using new MigrationsCore()

For options refer to Using create() method section.

Example:

const localMigrations = new LocalMigrations({
  dirPath: path.join(__dirname, '../migrations'),
  postfix: {
    up: '.up.sql',
    down: '.down.sql',
  },
});

const storedMigrations = new StoredMigrations({
  sqlActions: {
    createMigrationTable() { /* ... */ },
    migrateUp(migrations) { /* ... */ },
    migrateDown(migrations) { /* ... */ },
    getMigrationsNames() { /* ... */ },
    getLastMigrationName() { /* ... */ },
  }
});

const migrationsCore = new MigrationsCore(localMigrations, storedMigrations);

Methods of migrationsCore object

See migrations-core.interface.ts

Methods of localMigrations object

See local-migrations.interface.ts

Methods of storedMigrations object

See stored-migrations.interface.ts

Keywords

FAQs

Package last updated on 21 Sep 2024

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc