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

pgmg

v0.0.11

Published

pgmg = postgres + migrations

Downloads

208

Readme

pgmg

pgmg = postgres + migrations

Quick Start

  • mkdir -p migrations
  • touch migrations/first-migration.mjs
// migrations/first-migration.js
export const name = 'First Migration'
export const description = `
    This is where you can describe what your migration does.

    We automatically trim this so don't worry about indentation etc.
`

// If this fails, any changes will be rolled back
export async function transaction(sql){

    await sql`
        create table example(
            a int,
            b int,
            primary key (a,b)
        )
    `
}
# We don't rely on alphabetical order, you just pass in the files
# you want to migrate.
npx pgmg "$DATABASE_URL" "migrations/first-migrations.mjs"

What

  • A forward only, idempotent, postgres migration tool, with minimal noise but also minimal magic
  • OOTB support for postgres.js, we pass in a preconfigured postgres.js instance just point us at migration files
  • A simple migration file format, just export a transaction function a name and a description
  • All metadata stored in 1 simple table in the same database that you are migrating, makes it easy to get fine-grained control

How

A very simple script, we simply inject a schema (pgmg) and table (migration) into your target database. And record whether or not a migration has run for that migration name before. If so, we skip that file, if not we run it.

If the migration file runs without error, we insert a migration row based on the exported properties (name, description). If it fails, we don't.

pgmg has no opinion on migration order, but most of the time, there is only new files that aren't recorded, and in that case they can be run in any order. So you can just pass migrations/* to pgmg and it will ignore migrations it has een before, and run new ones in sequence in glob order.

pgmg stores its metadata in the target database (instead of in a different config file or something). It does this because it makes it easy to escape out of the migration system when you know what you are doing. E.g. when you want to run all migrations from scratch in development (delete from pgmg.migration) or even (drop schema pgmg).

It also makes testing / local development super logical. When you wipe the DB, the migration tool will also be wiped and pgpg will reapply changes.

API

CLI

Usage: pgmg [CONNECTION] [OPTIONS] [FILES]

[CONNECTION]
- Pass a postgres connection string (just like psql)
- AND/OR Specify host/user etc as env flags (PGHOST, PGUSER, PGPORT)

[FILES]

Any files passed as arguments after the connection string will be imported as JS migration files.

[OPTIONS]

The only way to specify a connection is via a pg connection URL.

--ssl 
    | --ssl                 Enables ssl
    | --ssl=prefer          Prefers ssl
    | --ssl=require         Requires ssl
    | --ssl=reject          Reject unauthorized connections
    | --ssl=no-reject       Do not reject unauthorized connections
    | --ssl=heroku          --no-ssl-reject if the host ends with a .com

Migration File

A migration file can have either an action export or a transaction export. An action export gets a raw sql instance. And performs no rollbacks if there is a failure. That means you need to manually handle your own error and rollback cases.

The recommended approach is to use transaction instead wherever possible which automatically wraps your migration in sql.begin. This will work great for most migrations, sometimes though you cannot run your migration in a migration and then you'll need to use action.

Beyond that, you must export a unique name property, this name is used by pgmg to determine whether or not this migration has run before. But, it is also good for reference later to see what migrations have run on this db in the past. Especially when creating curated or conditional migrations.

description is an optional export, but a recommended export. It is rare you need to change the database schema and there isn't some helpful reason you can provide for the change. A migration is effectively an admission that our first idea of a model was incorrect or incomplete, that is always worthwhile to document.

export transaction

Perform your migration within a transaction.

export action

Perform your migration with a raw sql instance, no transaction.

This is necessary for some schema changes, e.g. role changes, or any usage of concurrently.

export name (required)

The name of the migration.

export description (recommended)

A description of why this migration needs to occur.

FAQ

How do I order my migrations?

pgmg will apply migrations in the order you pass them to pgmg as arguments.

So if you choose to number your migrations, a simple glob will order them.

# Alphabetical ordered files
$ ls -l migrations
01-user-permissions.js
02-full-text-search.js
03-magic-link.js

# globbing will natively order alphabetically by default
$ npx pgmg $DATABASE_URL migrations/*.js

You could also have a simple text file that acts a manifest and expand the file as arguments like so:

Imagine we have a migrations.txt file:

user-permissions.js
full-text-search.js
magic-link.js

We can expand that file as arguments like so:

npx pgmg $DATABASE_URL $(cat migrations.txt)

If you wanted, your manifest could be json, or yaml, or whatever you want, as long as you can extract the filenames and pass them as arguments.

Roadmap

There's a few things I would like to add.

  • A dry run, that shows what changes will be made without actually applying them.
  • Optional verbose logging
  • Some simple commands for housekeeping:
    • Show existing migrations
    • Remove migrations matching filenames
    • Remove migrations match a naming convention
  • An interactive bootstrap command that creates a new migration file