Skip to content

Commit

Permalink
docs: refactor docs to use VitePress (#1132)
Browse files Browse the repository at this point in the history
Co-authored-by: Shinigami <[email protected]>
brenoepics and Shinigami92 authored Apr 30, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
1 parent b9cf8e9 commit 357c911
Showing 49 changed files with 2,272 additions and 2,099 deletions.
63 changes: 63 additions & 0 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Deploy GitHub Pages

on:
workflow_dispatch:
push:
paths:
- 'docs/**'
- '.github/workflows/docs.yml'
- 'package.json'
branches:
- 'main'

permissions:
contents: read
pages: write
id-token: write

concurrency:
group: pages
cancel-in-progress: false

jobs:
build-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
with:
fetch-depth: 0

- name: Install pnpm
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d # v3.0.0

- name: Set node version to 20
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 20
cache: 'pnpm'

- name: Setup Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0

- name: Install deps
run: pnpm install

- name: Build with VitePress
run: pnpm run docs:build

- name: Upload artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1
with:
path: ./docs/.vitepress/dist/

deploy-docs:
runs-on: ubuntu-latest
needs: build-docs
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
Empty file removed docs/.nojekyll
Empty file.
192 changes: 192 additions & 0 deletions docs/.vitepress/config.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import { DefaultTheme, defineConfig } from 'vitepress';

import pkg from '../../package.json';

const repository = 'https://github.com/salsita/node-pg-migrate';
export default defineConfig({
title: 'node-pg-migrate',
description: 'PostgreSQL database migration management tool',
base: '/node-pg-migrate/', // for GitHub Pages
srcDir: 'src',
lastUpdated: true,
cleanUrls: true,
metaChunk: true,

themeConfig: {
nav: navBarItems(),
sidebar: sidebar(),

search: {
provider: 'local',
},

socialLinks: [
{ icon: 'github', link: repository },
{ icon: 'npm', link: 'https://www.npmjs.com/package/node-pg-migrate' },
],

editLink: {
pattern: repository + '/edit/main/docs/src/:path',
text: 'Edit this page on GitHub',
},
},
});

function navBarItems(): DefaultTheme.NavItem[] {
return [
{ text: 'Home', link: '/' },
{ text: 'Getting Started', link: '/getting-started' },
{
text: 'Migrations',
link: '/migrations/',
activeMatch: `^/migrations/`,
},
{
text: pkg.version,
items: [
{ text: 'Changelog', link: repository + '/blob/main/CHANGELOG.md' },
{ text: 'Releases', link: repository + '/releases' },
{ text: 'License', link: repository + '/blob/main/LICENSE' },
],
},
];
}

function sidebar(): DefaultTheme.Sidebar {
return [
{
base: '/',
text: 'Reference',
collapsed: false,
items: sidebarReference(),
},
{
base: '/migrations/',
text: 'Defining Migrations',
link: '/',
collapsed: false,
items: sidebarMigrations(),
},
{
base: '/faq/',
text: 'FAQ',
collapsed: false,
items: sidebarFAQ(),
},
];
}

function sidebarReference(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Introduction',
link: 'introduction',
},
{
text: 'Getting Started',
link: 'getting-started',
},
{
text: 'CLI',
link: 'cli',
},
{
text: 'Programmatic API',
link: 'api',
},
];
}

function sidebarFAQ(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Transpiling Migrations',
link: 'transpiling',
},
{
text: 'Troubleshooting',
link: 'troubleshooting',
},
];
}

function sidebarMigrations(): DefaultTheme.SidebarItem[] {
return [
{
text: 'Tables',
link: 'tables',
},
{
text: 'Columns',
link: 'columns',
},
{
text: 'Constraints',
link: 'constraints',
},
{
text: 'Indexes',
link: 'indexes',
},
{
text: 'Functions',
link: 'functions',
},
{
text: 'Triggers',
link: 'triggers',
},
{
text: 'Schemas',
link: 'schemas',
},
{
text: 'Sequences',
link: 'sequences',
},
{
text: 'Views',
link: 'views',
},
{
text: 'Materialized Views',
link: 'mViews',
},
{
text: 'Types',
link: 'types',
},
{
text: 'Domains',
link: 'domains',
},
{
text: 'Operators',
link: 'operators',
},
{
text: 'Roles',
link: 'roles',
},
{
text: 'Policies',
link: 'policies',
},
{
text: 'Extensions',
link: 'extensions',
},
{
text: 'Grants',
link: 'grants',
},
{
text: 'Casts',
link: 'casts',
},
{
text: 'Miscellaneous',
link: 'misc',
},
];
}
17 changes: 17 additions & 0 deletions docs/.vitepress/theme/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// https://vitepress.dev/guide/custom-theme
import type { Theme } from 'vitepress';
import DefaultTheme from 'vitepress/theme';
import { h } from 'vue';
import './style.css';

export default {
extends: DefaultTheme,
Layout: () => {
return h(DefaultTheme.Layout, null, {
// https://vitepress.dev/guide/extending-default-theme#layout-slots
});
},
enhanceApp({ app, router, siteData }) {
// ...
},
} satisfies Theme;
123 changes: 123 additions & 0 deletions docs/.vitepress/theme/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Customize default theme styling by overriding CSS variables:
* https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
*/

:root {
--c-brown-1: #d26b38;
--c-brown-2: #e88d54;
--c-brown-3: #c27647;
--c-brown-soft-1: #a0623b;
--c-brown-soft-2: #2a2420;
--vp-c-brand-soft: #fbf6f4;
}

html.dark:root {
--vp-c-brand-soft: #2a2420;
--vp-c-bg-soft: #141414;
--vp-c-bg-alt: #121212;
--vp-c-bg-elv: #1b1b1b;
--vp-c-bg: #181818;
--vp-home-hero-name-background: -webkit-linear-gradient(
78deg,
var(--c-brown-1) 40%,
var(--c-brown-2)
);
}

/**
* Component: Layout
* -------------------------------------------------------------------------- */

:root {
--vp-c-brand-1: var(--c-brown-1);
--vp-c-brand-2: var(--c-brown-2);
--vp-c-brand-3: var(--c-brown-3);

--vp-c-default-1: var(--vp-c-gray-1);
--vp-c-default-2: var(--vp-c-gray-2);
--vp-c-default-3: var(--vp-c-gray-3);
--vp-c-default-soft: var(--vp-c-gray-soft);

--vp-c-tip-1: var(--vp-c-brand-1);
--vp-c-tip-2: var(--vp-c-brand-2);
--vp-c-tip-3: var(--vp-c-brand-3);
--vp-c-tip-soft: var(--vp-c-brand-soft);

--vp-c-warning-1: var(--vp-c-yellow-1);
--vp-c-warning-2: var(--vp-c-yellow-2);
--vp-c-warning-3: var(--vp-c-yellow-3);
--vp-c-warning-soft: var(--vp-c-yellow-soft);

--vp-c-danger-1: var(--vp-c-red-1);
--vp-c-danger-2: var(--vp-c-red-2);
--vp-c-danger-3: var(--vp-c-red-3);
--vp-c-danger-soft: var(--vp-c-red-soft);
}

/**
* Component: Button
* -------------------------------------------------------------------------- */

:root {
--vp-button-brand-border: transparent;
--vp-button-brand-text: var(--vp-c-white);
--vp-button-brand-bg: var(--vp-c-brand-3);
--vp-button-brand-hover-border: transparent;
--vp-button-brand-hover-text: var(--vp-c-white);
--vp-button-brand-hover-bg: var(--vp-c-brand-2);
--vp-button-brand-active-border: transparent;
--vp-button-brand-active-text: var(--vp-c-white);
--vp-button-brand-active-bg: var(--vp-c-brand-1);
}

/**
* Component: Home
* -------------------------------------------------------------------------- */

:root {
--vp-home-hero-name-color: transparent;
--vp-home-hero-name-background: -webkit-linear-gradient(
120deg,
var(--vp-c-brand-1) 30%,
var(--vp-c-brand-3)
);

--vp-home-hero-image-background-image: linear-gradient(
-45deg,
var(--vp-c-brand-1) 50%,
var(--vp-c-brand-3) 50%
);
--vp-home-hero-image-filter: blur(44px);
}

@media (min-width: 640px) {
:root {
--vp-home-hero-image-filter: blur(56px);
}
}

@media (min-width: 960px) {
:root {
--vp-home-hero-image-filter: blur(68px);
}
}

/**
* Component: Custom Block
* -------------------------------------------------------------------------- */

:root {
--vp-custom-block-tip-border: transparent;
--vp-custom-block-tip-text: var(--vp-c-text-1);
--vp-custom-block-tip-bg: var(--vp-c-brand-soft);
--vp-custom-block-tip-code-bg: var(--vp-c-brand-soft);
}

/**
* Component: Algolia
* -------------------------------------------------------------------------- */

.DocSearch {
--docsearch-primary-color: var(--vp-c-brand-1) !important;
}
132 changes: 0 additions & 132 deletions docs/README.md

This file was deleted.

25 changes: 0 additions & 25 deletions docs/_sidebar.md

This file was deleted.

27 changes: 0 additions & 27 deletions docs/api.md

This file was deleted.

45 changes: 0 additions & 45 deletions docs/casts.md

This file was deleted.

107 changes: 0 additions & 107 deletions docs/cli.md

This file was deleted.

111 changes: 0 additions & 111 deletions docs/columns.md

This file was deleted.

57 changes: 0 additions & 57 deletions docs/constraints.md

This file was deleted.

59 changes: 0 additions & 59 deletions docs/domains.md

This file was deleted.

28 changes: 0 additions & 28 deletions docs/extensions.md

This file was deleted.

31 changes: 0 additions & 31 deletions docs/index.html

This file was deleted.

110 changes: 0 additions & 110 deletions docs/migrations.md

This file was deleted.

40 changes: 0 additions & 40 deletions docs/misc.md

This file was deleted.

34 changes: 34 additions & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Programmatic API

Alongside command line, you can use `node-pg-migrate` also programmatically. It exports runner function,
which takes options argument with the following structure (similar to [command line arguments](cli.md#configuration)):

## Options

> [!NOTE]
> If you use `dbClient`, you should not use `databaseUrl` at the same time and vice versa.
| Option | Type | Description |
| ------------------------ | ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `databaseUrl` | `string or object` | Connection string or client config which is passed to [new pg.Client](https://node-postgres.com/api/client#constructor) |
| `dbClient` | `pg.Client` | Instance of [new pg.Client](https://node-postgres.com/api/client). Instance should be connected to DB, and after finishing migration, user is responsible to close connection |
| `migrationsTable` | `string` | The table storing which migrations have been run |
| `migrationsSchema` | `string` | The schema storing table which migrations have been run (defaults to same value as `schema`) |
| `schema` | `string or array[string]` | The schema on which migration will be run (defaults to `public`) |
| `dir` | `string` | The directory containing your migration files |
| `checkOrder` | `boolean` | Check order of migrations before running them |
| `direction` | `enum` | `up` or `down` |
| `count` | `number` | Amount of migration to run |
| `timestamp` | `boolean` | Treats `count` as timestamp |
| `ignorePattern` | `string` | Regex pattern for file names to ignore (ignores files starting with `.` by default) |
| `file` | `string` | Run-only migration with this name |
| `singleTransaction` | `boolean` | Combines all pending migrations into a single transaction so that if any migration fails, all will be rolled back (defaults to `true`) |
| `createSchema` | `boolean` | Creates the configured schema if it doesn't exist |
| `createMigrationsSchema` | `boolean` | Creates the configured migration schema if it doesn't exist |
| `noLock` | `boolean` | Disables locking mechanism and checks |
| `fake` | `boolean` | Mark migrations as run without actually performing them (use with caution!) |
| `dryRun` | `boolean` | |
| `log` | `function` | Redirect log messages to this function, rather than `console` |
| `logger` | `object with debug/info/warn/error methods` | Redirect messages to this logger object, rather than `console` |
| `verbose` | `boolean` | Print all debug messages like DB queries run (if you switch it on, it will disable `logger.debug` method) |
| `decamelize` | `boolean` | Runs [`decamelize`](https://github.com/salsita/node-pg-migrate/blob/main/src/utils/decamelize.ts) on table/column/etc. names |
141 changes: 141 additions & 0 deletions docs/src/cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# CLI Usage

## Database Connection

You can specify your database connection information using [config](https://www.npmjs.com/package/config).

```jsonc
// config/default.json
{
"db": {
"url": "postgres://postgres:password@localhost:5432/database",
},
}
```

or

```jsonc
// config/default.json
{
"db": {
"user": "postgres",
"password": "",
"host": "localhost",
"port": 5432,
"database": "database",
},
}
```

You could also specify your database url by setting the environment variable `DATABASE_URL`.

```
DATABASE_URL=postgres://postgres@localhost/database node-pg-migrate
```

You can specify custom JSON file with config (the format is same as for `db` entry
of [config](https://www.npmjs.com/package/config) file), for example:

```jsonc
// path/to/config.json
{
"user": "postgres",
"password": "",
"host": "localhost",
"port": 5432,
"database": "database",
}
```

> [!TIP]
> If a `.env` file exists, it will be loaded using [dotenv](https://www.npmjs.com/package/dotenv) (if installed) when
> running the node-pg-migrate binary.
> If the .env file is not on the same level where the command has been called, you
> can
> use the `--envPath` option to point to the location of your .env file.
Depending on your project's setup, it may make sense to write some custom grunt/gulp/whatever tasks that set this env
var and run your migration commands.
More on that below.

## Available Commands

| Command | Description |
| ----------------------------------------- | :---------------------------------------------------------------------------------------------------------------------: |
| `node-pg-migrate create {migration-name}` | creates a new migration file with a timestamp prepended to the name you provide. Dashes replace spaces and underscores. |
| `node-pg-migrate up` | runs all up migrations from the current state. |
| `node-pg-migrate up {N}` | runs N up migrations from the current state. |
| `node-pg-migrate down` | runs a single down migration. |
| `node-pg-migrate down {N}` | runs N down migrations from the current state. |
| `node-pg-migrate redo` | redoes last migration (runs a single down migration, then single up migration). |
| `node-pg-migrate redo {N}` | redoes N last migrations (runs N down migrations, then N up migrations). |

## Configuration

> [!TIP]
> See all by running `node-pg-migrate --help`.
>
> Most of the configuration options can be also specified in [config](https://www.npmjs.com/package/config) file.
You can adjust defaults by passing arguments to `node-pg-migrate`:

| Argument | Aliases | Default | Description |
| --------------------------- | ------- | ------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `config-file` | `f` | `undefined` | The file with migration JSON config |
| `config-value` | | `db` | Name of config section with db options |
| `schema` | `s` | `public` | The schema(s) on which migration will be run, used to set `search_path` |
| `create-schema` | | `false` | Create the configured schema if it doesn't exist |
| `database-url-var` | `d` | `DATABASE_URL` | Name of env variable with database url string |
| `migrations-dir` | `m` | `migrations` | The directory containing your migration files |
| `migrations-schema` | | same value as `schema` | The schema storing table which migrations have been run |
| `create-migrations-schema` | | `false` | Create the configured migrations schema if it doesn't exist |
| `migrations-table` | `t` | `pgmigrations` | The table storing which migrations have been run |
| `ignore-pattern` | | `undefined` | Regex pattern for file names to ignore |
| `migration-filename-format` | | `utc` | Choose prefix of file, `utc` (`20200605075829074`) or `timestamp` (`1591343909074`) |
| `migration-file-language` | `j` | `js` | Language of the migration file to create (`js`, `ts` or `sql`) |
| `template-file-name` | | `undefined` | Utilize a custom migration template file with language inferred from its extension. The file should export the up method, accepting a MigrationBuilder instance. |
| `tsconfig` | | `undefined` | Path to tsconfig.json. Used to setup transpiling of TS migration files. (Also sets `migration-file-language` to typescript, if not overridden) |
| `envPath` | | `same level where it's invoked` | Retrieve the path to a .env file. This feature proves handy when dealing with nested projects or when referencing a global .env file. |
| `timestamp` | | `false` | Treats number argument to up/down migration as timestamp (running up migrations less or equal to timestamp or down migrations greater or equal to timestamp) |
| `check-order` | | `true` | Check order of migrations before running them, to switch it off supply `--no-check-order` |
| `single-transaction` | | `true` | Combines all pending migrations into a single transaction so that if any migration fails, all will be rolled back, to switch it off supply `--no-single-transaction` |
| `no-lock` | | `false` | Disables locking mechanism and checks |
| `fake` | | `false` | Mark migrations as run without actually performing them, (use with caution!) |
| `decamelize` | | `false` | Runs `decamelize` on table/column/etc. names |
| `verbose` | | `true` | Print all debug messages like DB queries run, to switch it off supply `--no-verbose` |
| `reject-unauthorized` | | `undefined` | Sets ssl `rejectUnauthorized` parameter. Use for e.g. self-signed certificates on the server. [see](https://node-postgres.com/announcements#2020-02-25) |

For SSL connection to DB you can set `PGSSLMODE` environment variable to value
from [list](https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) other
than `disable`.
e.g. `PGSSLMODE=require node-pg-migrate up` ([pg](https://github.com/brianc/node-postgres/blob/main/CHANGELOG.md#v260)
will take it into account)

### JSON Configuration

> [!TIP]
> You can use [config](https://www.npmjs.com/package/config) or your own json file with configuration
> (`config-file` command line option).
You can also specify your database connection here, [see](#database-connection).

Other available options are:

```jsonc
{
"schema": "public",
"createSchema": false,
"migrationsDir": "migrations",
"migrationsSchema": "public",
"createMigrationsSchema": false,
"migrationsTable": "pgmigrations",
"migrationFilenameFormat": "utc",
"migrationFileLanguage": "js",
"ignorePattern": undefined,
"checkOrder": true,
"verbose": true,
"decamelize": false,
"tsconfig": "tsconfig.json",
}
```
66 changes: 66 additions & 0 deletions docs/src/faq/transpiling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Transpiling

## Transpiling Babel

You can use babel for transpiling migration files. You have e.g. these options:

### Use global configuration

Update `scripts` section in your `package.json` to contain babel-node command:

```jsonc
{
"scripts": {
// ..
"migrate": "babel-node node_modules/node-pg-migrate/bin/node-pg-migrate.js", // [!code ++]
},
}
```

### Use custom configuration

It requires a little setup to use:

1. Update `scripts` section in your `package.json` to contain `'migrate': 'node migrate.js'`
2. Create `migrate.js` file with contents:

```js
require('babel-core/register')({
/* ... your babel config ... */
});
require('./node_modules/node-pg-migrate/bin/node-pg-migrate.js');
```

## Transpiling Typescript

### Use flag

Typescript is supported out of the box. You need to have installed `ts-node` package and need to pass `tsconfig`
arg ([see](/cli#configuration))

### Use global configuration

Another option is to use [ts-node](https://www.npmjs.com/package/ts-node) CLI directly and it needs to be available
globally or as a dependency.

```jsonc
{
"scripts": {
// ..
"migrate": "ts-node node_modules/.bin/node-pg-migrate.js -j ts", // [!code ++]
},
}
```

### Use custom configuration

If you need some more advanced TS config, you need to register transpiler yourself like in using babel configuration.

```js
const config = {
/* ... your ts config ... */
};
require('ts-node').register(config);
// e.g. require("tsconfig-paths").register(config.compilerOptions);
require('./node_modules/node-pg-migrate/bin/node-pg-migrate.js');
```
22 changes: 12 additions & 10 deletions docs/troubleshooting.md → docs/src/faq/troubleshooting.md
Original file line number Diff line number Diff line change
@@ -2,44 +2,46 @@

## SSL connection

For SSL connection to DB you can set `PGSSLMODE` environment variable to value from [list](https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) other then `disable`.
For SSL connection to DB you can set `PGSSLMODE` environment variable to value from [list](https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNECT-SSLMODE) other than `disable`.
e.g. `PGSSLMODE=require node-pg-migrate up` ([pg](https://github.com/brianc/node-postgres/blob/main/CHANGELOG.md#v260) will take it into account)

Or you can append `?ssl=true` to your `DATABASE_URL`

For setting SSL certificates etc. you will need to use some form of JSON config [see](cli.md)
For setting SSL certificates etc. you will need to use some form of JSON config [see](/cli)
with proper SSL configuration [see](https://node-postgres.com/features/ssl)

With the introduction of pg v8, SSL connection options use node defaults. That means e.g. rejecting self-signed
certificates. To be able to accept self-signed certificates you can use `--no-reject-unauthorized` CLI option
or pass database connection info through JSON configuration [see](cli.md).
or pass database connection info through JSON configuration [see](/cli).
For explanation [see](https://node-postgres.com/announcements#2020-02-25) and [see](https://github.com/brianc/node-postgres/issues/2009).
Do not combine it with `?ssl=true` as it overrides ssl config from `--no-reject-unauthorized`.

## Camel case, Snake case, case sensitivity

In PostgreSQL unquoted identifiers are case-insensitive. Thus `SELECT * FROM hello` and `SELECT * FROM HELLO` are equivalent.
In PostgreSQL, unquoted identifiers are case-insensitive. Thus `SELECT * FROM hello` and `SELECT * FROM HELLO` are equivalent.
However, quoted identifiers are case-sensitive. `SELECT * FROM "hello"`, `SELECT * FROM "HELLO"` and `SELECT * FROM "HeLLo"`
are trying to read from three different tables.
Unquoted identifiers are always folded to lower case.
[see](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)
Unquoted identifiers are always folded to a lower case.
[See](https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS)

`node-pg-migrate` always quotes all identifiers, so make sure you also quote them in your SQL (and so does eventual library you use).
Or always use lower case identifiers to prevent confusion (unquoted identifiers are always folded to lower case - see above).

`node-pg-migrate` also comes with `decamelize` flag which runs `decamelize` package on all table/column/etc. names ([see](cli.md#configuration)). That means that your camel case identifiers will be converted to snake case (lower cased).
`node-pg-migrate` also comes with `decamelize` flag which runs `decamelize` package on all table/column/etc. names ([see](/cli#configuration)). That means that your camel case identifiers will be converted to snake case (lower cased).

## Refused connection issues

- Password to your database may not contain some characters (which have special meaning in url schema) when used in `DATABASE_URL`.
Use other means to provide password or change the password. [see](https://github.com/salsita/node-pg-migrate/issues/439)
- Make sure connection is not stopped by firewalls, security rules, etc.
Try `telnet url port` to try to connect (e.g. `telnet 127.0.0.1 5432`) to postgres server.
If command will not end with error, but will wait for further input from you, server (or some other service running on that port :man_shrugging:) is accessible and waits for correct user/password.
Otherwise server does not run or listen on specified port or there is some other connection problem. You have to investigate...
If command will not end with error, but will wait for further input from you, server (or some other service running on that port :man_shrugging:) is accessible and waits for the correct user/password.
Otherwise, the server does not run or listen on specified port, or there is some other connection problem. You have to investigate...

## Running in transaction

Some DB operations like add type value (`pgm.addTypeValue`) does not work if the type is not created in the same
transaction. E.g. if it is created in previous migration. You need to run specific migration outside transaction
transaction.
E.g., if it is created in previous migration.
You need to run specific migration outside transaction
(`pgm.noTransaction`).
128 changes: 128 additions & 0 deletions docs/src/getting-started.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Getting Started

## Preconditions

- Node.js 18 or higher
- PostgreSQL 12.8 or higher (lower versions may work but are not supported officially)

If you don't already have the [`pg`](https://node-postgres.com/) library installed, you will need to add pg as either a direct or dev dependency

::: code-group

```sh [npm]
$ npm add pg
```

```sh [pnpm]
$ pnpm add pg
```

```sh [yarn]
$ yarn add pg
```

```sh [bun]
$ bun add pg
```

:::

## Installation

::: code-group

```sh [npm]
$ npm add -D node-pg-migrate
```

```sh [pnpm]
$ pnpm add -D node-pg-migrate
```

```sh [yarn]
$ yarn add -D node-pg-migrate
```

```sh [bun]
$ bun add -D node-pg-migrate
```

:::

Installing this module adds a runnable file into your `node_modules/.bin` directory. If installed globally (with the -g option), you can run `node-pg-migrate` and if not, you can run `./node_modules/.bin/node-pg-migrate.js`

## Quick Example

> [!IMPORTANT]
> This example assumes you are using `npm` as your package manager. If you are using another package manager, replace `npm` with the appropriate command.
Add `node-pg-migrate` to `scripts` section of your `package.json` so you are able to quickly run commands.

```jsonc
{
"scripts": {
// ..
"migrate": "node-pg-migrate", // [!code ++]
},
}
```

Run `npm run migrate create my-first-migration`. It will create file `xxx_my-first-migration.js` in `migrations` folder.
Open it and change contents to:

```js
exports.up = (pgm) => {
pgm.createTable('users', {
id: 'id',
name: { type: 'varchar(1000)', notNull: true },
createdAt: {
type: 'timestamp',
notNull: true,
default: pgm.func('current_timestamp'),
},
});
pgm.createTable('posts', {
id: 'id',
userId: {
type: 'integer',
notNull: true,
references: '"users"',
onDelete: 'cascade',
},
body: { type: 'text', notNull: true },
createdAt: {
type: 'timestamp',
notNull: true,
default: pgm.func('current_timestamp'),
},
});
pgm.createIndex('posts', 'userId');
};
```

Save migration file.

Now you should put your DB connection string to `DATABASE_URL` environment variable and run `npm run migrate up`.
(e.g. `DATABASE_URL=postgres://test:test@localhost:5432/test npm run migrate up`)

You should now have two tables in your DB :tada:

If you want to change your schema later, you can e.g. add lead paragraph to posts:

Run `npm run migrate create posts_lead`, edit `xxx_posts_lead.js`:

```js
exports.up = (pgm) => {
pgm.addColumns('posts', {
lead: { type: 'text', notNull: true },
});
};
```

Run `npm run migrate up` and there will be a new column in `posts` table :tada:

## Want to know more?

- [CLI commands](/cli)
- [Programmatic API](/api)
- [Migration files](/migrations/)
29 changes: 29 additions & 0 deletions docs/src/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
# https://vitepress.dev/reference/default-theme-home-page
layout: home

hero:
name: 'node-pg-migrate'
text: 'PostgreSQL database migration management tool'
actions:
- theme: brand
text: What is node-pg-migrate?
link: /introduction
- theme: alt
text: Quickstart
link: /getting-started
- theme: alt
text: GitHub
link: https://github.com/salsita/node-pg-migrate

features:
- title: Migration Made Easy
icon: 🛠️
details: Manage migrations effortlessly with CLI support for up-down migrations, ensuring smooth database transitions.
- title: TypeScript & Programmatic Support
icon: 🚀
details: Integrate seamlessly with TypeScript, and access a programmatic API for advanced customization and automation.
- title: Flexible Schema Manipulation
icon: 💡
details: Effortlessly modify schemas using direct SQL generation, leveraging PostgreSQL's features for enhanced functionality.
---
26 changes: 26 additions & 0 deletions docs/src/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# What is node-pg-migrate?

> [!IMPORTANT]
> The core maintainer of this project moved to [@Shinigami92](https://github.com/Shinigami92) (also core maintainer of FakerJS and core member of Vite).
> The project is and remains under the MIT license.
Node.js database migration management built exclusively for postgres. (But can also be used for other DBs conforming to SQL standard - e.g. [CockroachDB](https://github.com/cockroachdb/cockroach).)
Started by [Theo Ephraim](https://github.com/theoephraim/), then handed over to [Salsita Software](https://www.salsitasoft.com/) and now maintained by [@Shinigami92](https://github.com/Shinigami92).

## Explanation & Goals

### _Why only Postgres?_

By writing this migration tool specifically for postgres instead of accommodating many databases, we can actually provide a full featured tool that is much simpler to use and maintain. I was tired of using crippled database tools just in case one day we switch our database.

### _Async / Sync_

Everything is async in node, and that's great, but a migration tool should really just be a fancy wrapper that generates SQL. Most other migration tools force you to bring in control flow libraries or wrap everything in callbacks as soon as you want to do more than a single operation in a migration. Plus by building up a stack of operations, we can automatically infer down migrations (sometimes) to save even more time.

### _Naming / Raw Sql_

Many tools force you to use their constants to do things like specify data types. Again, this tool should be a fancy wrapper that generates SQL, so whenever possible, it should just pass through user values directly to the SQL. The hard part is remembering the syntax of the specific operation, not remembering how to type "timestamp"!

## License

This project is licensed under [MIT](https://github.com/salsita/node-pg-migrate/blob/main/LICENSE) license.
59 changes: 59 additions & 0 deletions docs/src/migrations/casts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# Cast Operations

## Operation: `createCast`

#### `pgm.createCast( source_type, target_type, opttions )`

> [!IMPORTANT]
> Create a new cast - [postgres docs](https://www.postgresql.org/docs/current/sql-createcast.html)
### Arguments

| Name | Type | Description |
| ------------- | -------- | -------------------------------------------- |
| `source_type` | `string` | The name of the source data type of the cast |
| `target_type` | `string` | The name of the target data type of the cast |
| `options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| --------------- | --------- | -------------------------------------------------- |
| `functionName` | `string` | Name of function to use to do the cast |
| `argumentTypes` | `array` | Array of types of arguments for the function |
| `inout` | `boolean` | Use standard I/O routines for conversion |
| `as` | `string` | Indicate when this may cast may be done implicitly |

##### Tips

- `argumentTypes`: Is an array of strings listing the types of arguments for the conversion function. If this is not
present, it defaults to just the `source_type`.
- `inout`: Setting this to `true` indicates that conversion should be used by using
the standard text output conversion for `source_type` and passing the
result to the input conversion process for `target_type`.

- `as`: This may be either `assignment` or `implicit`. If `implicit` is used, the
cast may be used implicitly in any context; this is not recommended. If
`assignment` is used the cast will only be done implicitly in
assignments.

## Reverse Operation: `dropCast`

#### `pgm.dropCast( source_type, target_type )`

> [!IMPORTANT]
> Drop a cast - [postgres docs](https://www.postgresql.org/docs/current/sql-dropcast.html)
### Arguments

| Name | Type | Description |
| ------------- | -------- | -------------------------------------------- |
| `source_type` | `string` | The name of the source data type of the cast |
| `target_type` | `string` | The name of the target data type of the cast |
| `options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ---------- | --------- | ------------------------------------------------ |
| `ifExists` | `boolean` | Do not throw an error if the cast does not exist |
160 changes: 160 additions & 0 deletions docs/src/migrations/columns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Column Operations

## Column Definitions

The `createTable` and `addColumns` methods both take a `columns` argument that specifies column names and options.
It is an object (key/value) where each key is the name of the column,
and the value is another object that defines the options for the column.

| Option | Type | Description |
| ----------------------------- | ------------------------------------- | -------------------------------------------------------------------------------------------- |
| `type` | `string` | Data type (use normal postgres types) |
| `collation` | `string` | Collation of data type |
| `unique` | `boolean` | Set to true to add a unique constraint on this column |
| `primaryKey` | `boolean` | Set to true to make this column the primary key |
| `notNull` | `boolean` | Set to true to make this column not null |
| `default` | `string` | Adds DEFAULT clause for column. Accepts null, a literal value, or a `pgm.func()` expression. |
| `check` | `string` | SQL for a check constraint for this column |
| `references` | [Name](/migrations/#type) or `string` | A table name that this column is a foreign key to |
| `referencesConstraintName` | `string` | Name of the created constraint |
| `referencesConstraintComment` | `string` | Comment on the created constraint |
| `onDelete` | `string` | Adds ON DELETE constraint for a reference column |
| `onUpdate` | `string` | Adds ON UPDATE constraint for a reference column |
| `match` | `string` | `FULL` or `SIMPLE` |
| `deferrable` | `boolean` | Flag for deferrable column constraint |
| `deferred` | `boolean` | Flag for initially deferred deferrable column constraint |
| `comment` | `string` | Adds comment on column |
| `expressionGenerated` | `string` | Expression to compute column value |
| `sequenceGenerated` | `object` | Creates identity column see [sequence options section](sequences.md#sequence-options) |
| `precedence` | `string` | `ALWAYS` or `BY DEFAULT` |

## Data types & Convenience Shorthand

Data type strings will be passed through directly to postgres, so write types as you would if you were writing the
queries by hand.

**There are some aliases on types to make things more foolproof:** _(int, string, float, double, datetime, bool)_

**There is a shorthand to pass only the type instead of an option object:**

```ts
pgm.addColumns('myTable', { age: 'integer' });
```

Equivalent to:

```ts
pgm.addColumns('myTable', { age: { type: 'integer' } });
```

**There is a shorthand for normal auto-increment IDs:**

```ts
pgm.addColumns('myTable', { id: 'id' });
```

Equivalent to:

```ts
pgm.addColumns('myTable', { id: { type: 'serial', primaryKey: true } });
```

## Methods

### Operation: `addColumns`

#### `pgm.addColumns( tablename, new_columns, options )`

> [!IMPORTANT]
> Add columns to an existing table - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
>
> Alias: `addColumn`
#### Arguments

| Name | Type | Description |
| ------------- | ------------------------- | ------------------------------------------------------------------------------- |
| `tablename` | [Name](/migrations/#type) | Name of the table to alter |
| `new_columns` | `object` | Column names / options -- see [column definitions section](#column-definitions) |
| `options` | `object` | Check below for available options |

##### Options

| Option | Type | Description |
| ------------- | --------- | ------------------------------------- |
| `ifNotExists` | `boolean` | Adds column only if it does not exist |

### Reverse Operation: `dropColumns`

#### `pgm.dropColumns( tablename, columns, options )`

> [!IMPORTANT]
> Drop columns from a table - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
>
> Alias: `dropColumn`
#### Arguments

| Name | Type | Description |
| ----------- | ------------------------------ | ---------------------------------------- |
| `tablename` | [Name](/migrations/#type) | Name of the table to alter |
| `columns` | `array of strings` or `object` | Columns to drop (if objected, uses keys) |
| `options` | `object` | Check below for available options |

##### Options

| Option | Type | Description |
| ---------- | --------- | ------------------------------ |
| `ifExists` | `boolean` | Drops column only if it exists |
| `cascade` | `boolean` | Drop also dependent objects |

### Operation: `renameColumn`

#### `pgm.renameColumn( tablename, old_column_name, new_column_name )`

> [!IMPORTANT]
> Rename a column - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
>
> **Reverse Operation**: same operation in opposite direction
#### Arguments

| Name | Type | Description |
| ----------------- | ------------------------- | ------------------- |
| `tablename` | [Name](/migrations/#type) | Name of the table |
| `old_column_name` | `string` | Current column name |
| `new_column_name` | `string` | New column name |

### Operation: `alterColumn`

#### `pgm.alterColumn( tablename, column_name, column_options )`

> [!IMPORTANT]
> Alter a column (default value, type, allow
> null) - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
#### Arguments

| Name | Type | Description |
| ---------------- | ------------------------- | --------------------------- |
| `tablename` | [Name](/migrations/#type) | Name of the table |
| `column_name` | `string` | Column to alter |
| `column_options` | `object` | Optional new column options |

##### Column Options

| Option | Type | Description |
| ------------------- | ------------------------- | ---------------------------------------------- |
| `default` | `string or null` | null, string |
| `type` | `string` | New datatype |
| `notNull` | `boolean` | Sets NOT NULL if true or NULL if false |
| `allowNull` | `boolean` | Sets NULL if true (alternative to `notNull`) |
| `using` | `string` | Adds USING clause to change values in column |
| `collation` | `string` | Adds COLLATE clause to change values in column |
| `comment` | `string` | Adds comment on column |
| `sequenceGenerated` | `object or null or false` | Sets or drops identity column |

##### `sequenceGenerated` Options

See [sequence options section](sequences.md#sequence-options),
You can also set `precedence` to `ALWAYS` or `BY DEFAULT`.
82 changes: 82 additions & 0 deletions docs/src/migrations/constraints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# Constraint Operations

## Operation: `addConstraint`

#### `pgm.addConstraint( tablename, constraint_name, expression )`

> [!IMPORTANT]
> Add a named column constraint - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
>
> Alias: `createConstraint`
### Arguments

| Name | Type | Description |
| ----------------- | ------------------------- | ------------------------------------------------------------------------------------------------------------ |
| `tablename` | [Name](/migrations/#type) | Name of the table to alter |
| `constraint_name` | `string` | Name for the constraint |
| `expression` | `string` or `object` | Constraint expression (raw sql) or definition -- see [constraint definition section](#constraint-definition) |

#### Constraint Definition

| Option | Type | Description |
| ------------- | -------------------------------------------------------- | ----------------------------------------------------------------------- |
| `check` | `string` or `array` | SQL for a check constraint(s) |
| `unique` | `Name` or `array of Names` or `array of arrays of Names` | Names of unique columns |
| `primaryKey` | `Name` or `array of Names` | Names of primary columns |
| `exclude` | `string` | SQL for an exclude constraint |
| `deferrable` | `boolean` | Flag for deferrable table constraint |
| `deferred` | `boolean` | Flag for initially deferred deferrable table constraint |
| `comment` | `string` | Comment on a singular, named constraint |
| `foreignKeys` | `object` or `array of objects` | Foreign keys specification -- see [foreign keys section](#foreign-keys) |

#### Foreign Keys

| Option | Type | Description |
| ----------------------------- | -------------------------- | ---------------------------------------------------------------------------------- |
| `columns` | `Name` or `array of Names` | Names of columns |
| `references` | `Name` | Names of foreign table and column names |
| `referencesConstraintName` | `string` | Name of the created constraint (only necessary when creating multiple constraints) |
| `referencesConstraintComment` | `string` | Comment on the individual foreign key constraint |
| `onDelete` | `string` | Action to perform on delete |
| `onUpdate` | `string` | Action to perform on update |
| `match` | `string` | `FULL` or `SIMPLE` |

## Reverse Operation: `dropConstraint`

#### `pgm.dropConstraint( tablename, constraint_name, options )`

> [!IMPORTANT]
> Drop a named column constraint - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
### Arguments

| Name | Type | Description |
| ----------------- | ------------------------- | --------------------------------- |
| `tablename` | [Name](/migrations/#type) | Name of the table to alter |
| `constraint_name` | `string` | Name of the constraint |
| `options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ---------- | --------- | ---------------------------------- |
| `ifExists` | `boolean` | Drops constraint only if it exists |
| `cascade` | `boolean` | Drops also dependent objects |

## Operation: `renameConstraint`

#### `pgm.renameConstraint( tablename, old_constraint_name, new_constraint_name )`

> [!IMPORTANT]
> Rename a constraint - [postgres docs](http://www.postgresql.org/docs/current/static/sql-altertable.html)
>
> Reverse Operation: same operation in opposite direction
### Arguments

| Name | Type | Description |
| --------------------- | ------------------------- | -------------------------- |
| `tablename` | [Name](/migrations/#type) | Name of the table to alter |
| `old_constraint_name` | `string` | Current constraint name |
| `new_constraint_name` | `string` | New constraint name |
86 changes: 86 additions & 0 deletions docs/src/migrations/domains.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Domain Operations

## Operation: `createDomain`

#### `pgm.createDomain( domain_name, type, options )`

> [!IMPORTANT]
> Create a new domain - [postgres docs](https://www.postgresql.org/docs/current/static/sql-createdomain.html)
### Arguments

| Name | Type | Description |
| ------------- | ------------------------- | --------------------------------- |
| `domain_name` | [Name](/migrations/#type) | Name of the new domain |
| `type` | `string` | Type of the new domain |
| `options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ---------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `default` | `string` | Default value of domain |
| `collation` | `string` | Collation of data type |
| `notNull` | `boolean` | Sets NOT NULL if true ([not recommended](https://www.postgresql.org/docs/10/static/sql-createdomain.html#idm46428678330368)) |
| `check` | `string` | SQL for a check constraint for this column |
| `constraintName` | `string` | Name for constraint |

### Reverse Operation: `dropDomain`

#### `pgm.dropDomain( domain_name, drop_options )`

> [!IMPORTANT]
> Drop a domain - [postgres docs](http://www.postgresql.org/docs/current/static/sql-dropdomain.html)
### Arguments

| Name | Type | Description |
| -------------- | ------------------------- | --------------------------------- |
| `domain_name` | [Name](/migrations/#type) | Name of the domain to drop |
| `drop_options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ---------- | --------- | ------------------------------ |
| `ifExists` | `boolean` | Drops domain only if it exists |
| `cascade` | `boolean` | Drops also dependent objects |

## Operation: `alterDomain`

#### `pgm.alterDomain( domain_name, type, options )`

> [!IMPORTANT]
> Alter a domain - [postgres docs](https://www.postgresql.org/docs/current/static/sql-alterdomain.html)
### Arguments

| Name | Type | Description |
| ------------- | ------------------------- | --------------------------------- |
| `domain_name` | [Name](/migrations/#type) | Name of the new domain |
| `options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ---------------- | --------- | -------------------------------------------- |
| `default` | `string` | Default value of domain |
| `collation` | `string` | Collation of data type |
| `notNull` | `boolean` | sets NOT NULL if true or NULL if false |
| `allowNull` | `boolean` | sets NULL if true (alternative to `notNull`) |
| `check` | `string` | sql for a check constraint for this column |
| `constraintName` | `string` | name for constraint |

## Operation: `renameDomain`

#### `pgm.renameDomain( old_domain_name, new_domain_name )`

> [!IMPORTANT]
> Rename a domain - [postgres docs](http://www.postgresql.org/docs/current/static/sql-alterdomain.html)
### Arguments

| Name | Type | Description |
| ----------------- | ------------------------- | ---------------------- |
| `old_domain_name` | [Name](/migrations/#type) | Old name of the domain |
| `new_domain_name` | [Name](/migrations/#type) | New name of the domain |
45 changes: 45 additions & 0 deletions docs/src/migrations/extensions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Extension Operations

## Operation: `createExtension`

#### `pgm.createExtension( extension )`

> [!IMPORTANT]
> Install postgres extension(s) - [postgres docs](http://www.postgresql.org/docs/current/static/sql-createextension.html.html)
>
> Alias: `addExtension`
### Arguments

| Name | Type | Description |
| ----------- | --------------------------- | --------------------------------- |
| `extension` | `string` or `array[string]` | Name(s) of extensions to install |
| `options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ------------- | --------- | ------------------------------------------------------------------ |
| `ifNotExists` | `boolean` | Install extension only if it does not exist (default `false`) |
| `schema` | `string` | The name of the schema in which to install the extension's objects |

## Reverse Operation: `dropExtension`

#### `pgm.dropExtension( extension )`

> [!IMPORTANT]
> Un-install postgres extension(s) - [postgres docs](http://www.postgresql.org/docs/current/static/sql-dropextension.html)
### Arguments

| Name | Type | Description |
| -------------- | --------------------------- | --------------------------------- |
| `extension` | `string` or `array[string]` | Name(s) of extensions to install |
| `drop_options` | `object` | Check below for available options |

#### Options

| Option | Type | Description |
| ---------- | --------- | --------------------------------- |
| `ifExists` | `boolean` | Drops extension only if it exists |
| `cascade` | `boolean` | Drops also dependent objects |
8 changes: 4 additions & 4 deletions docs/functions.md → docs/src/migrations/functions.md
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
**Arguments:**

- `function_name` _[[Name](migrations.md#type)]_ - name of the new function
- `function_name` _[[Name](/migrations/#type)]_ - name of the new function
- `function_params` _[array]_ - parameters of the new function

Either array of strings or objects.
@@ -37,7 +37,7 @@
**Arguments:**

- `function_name` _[[Name](migrations.md#type)]_ - name of the function to drop
- `function_name` _[[Name](/migrations/#type)]_ - name of the function to drop
- `function_params` _[array]_ - [see](#pgmcreatefunction-function_name-function_params-function_options-definition-)
- `drop_options` _[object]_ - options:
- `ifExists` _[boolean]_ - drops function only if it exists
@@ -51,6 +51,6 @@
**Arguments:**

- `old_function_name` _[[Name](migrations.md#type)]_ - old name of the function
- `old_function_name` _[[Name](/migrations/#type)]_ - old name of the function
- `function_params` _[array]_ - [see](#pgmcreatefunction-function_name-function_params-function_options-definition-)
- `new_function_name` _[[Name](migrations.md#type)]_ - new name of the function
- `new_function_name` _[[Name](/migrations/#type)]_ - new name of the function
24 changes: 12 additions & 12 deletions docs/grants.md → docs/src/migrations/grants.md
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@
**Arguments:**

- `roles_from` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles_to` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles_from` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `roles_to` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `grant_roles_options` _[object]_ - options:
- `withAdminOption` _[boolean]_ - default false
- `onlyAdminOption` _[boolean]_ - default false
@@ -23,8 +23,8 @@
**Arguments:**

- `roles` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles_from` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `roles_from` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `drop_options` _[object]_ - options:
- `onlyAdminOption` _[boolean]_ - default false
- `cascade` _[boolean]_ - drops also dependent objects
@@ -38,10 +38,10 @@
**Arguments:**

- `grant_options` _[object]_ - options:
- `tables` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)] or [ALL]_ - names of tables
- `tables` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)] or [ALL]_ - names of tables
- `schema` _[string]_ - if tables ALL, then schema name is required
- `privileges` _[array of TablePrivileges] or [ALL]_ - list of privileges
- `roles` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `withGrantOption` _[boolean]_ - default false
- `cascade` _[boolean]_ - default false

@@ -56,10 +56,10 @@
**Arguments:**

- `revoke_options` _[object]_ - options:
- `tables` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)] or [ALL]_ - names of tables
- `tables` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)] or [ALL]_ - names of tables
- `schema` _[string]_ - if tables ALL, then schema name is required
- `privileges` _[array of TablePrivileges] or [ALL]_ - list of privileges
- `roles` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `withGrantOption` _[boolean]_ - default false
- `cascade` _[boolean]_ - drops also dependent objects

@@ -72,9 +72,9 @@
**Arguments:**

- `grant_options` _[object]_ - options:
- `schemas` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)] or [ALL]_ - names of schemas
- `schemas` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)] or [ALL]_ - names of schemas
- `privileges` _[array of SchemaPrivileges] or [ALL]_ - list of privileges
- `roles` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `withGrantOption` _[boolean]_ - default false
- `onlyGrantOption` _[boolean]_ - default false
- `cascade` _[boolean]_ - default false
@@ -90,9 +90,9 @@
**Arguments:**

- `revoke_options` _[object]_ - options:
- `schemas` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)] or [ALL]_ - names of schemas
- `schemas` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)] or [ALL]_ - names of schemas
- `privileges` _[array of SchemaPrivileges] or [ALL]_ - list of privileges
- `roles` _[[Name](migrations.md#type) or array of [Names](migrations.md#type)]_ - names of roles
- `roles` _[[Name](/migrations/#type) or array of [Names](/migrations/#type)]_ - names of roles
- `withGrantOption` _[boolean]_ - default false
- `onlyGrantOption` _[boolean]_ - default false
- `cascade` _[boolean]_ - drops also dependent objects
156 changes: 156 additions & 0 deletions docs/src/migrations/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
---
next:
text: 'Tables'
link: '/migrations/tables'
---

# Defining Migrations

## Running Migrations

When you run `node-pg-migrate create` a new migration file is created that looks like this:

```javascript
exports.shorthands = undefined;

exports.up = function up(pgm) {};

exports.down = function down(pgm) {};
```

`pgm` is a helper object that provides migration operations and `run` is the callback to call when you are done.

`shorthands` is optional for column type shorthands. You can specify custom types which will be expanded to column
definition.

### Example

```js
exports.shorthands = {
id: { type: 'uuid', primaryKey: true },
createdAt: {
type: 'timestamp',
notNull: true,
default: new PgLiteral('current_timestamp'),
},
};
```

It will in `pgm.createTable('test', { id: 'id', createdAt: 'createdAt' });` produce SQL

```sql
CREATE TABLE "test" ("id" uuid PRIMARY KEY, "createdAt" timestamp DEFAULT current_timestamp NOT NULL);
```

These shorthands are inherited from previous migrations. You can override/change value by simply defining a new value
for a given shorthand name
if it is used in current and all following migrations (until changed again).

> [!IMPORTANT]
> Calling the migration functions on `pgm` doesn't migrate your database. These functions just add sql commands to a
> stack that is run.
## Automatic Down Migrations

If `exports.down` is not present in a migration, node-pg-migrate will try to automatically infer the operations that
make up the down migration by reversing the operations of the up migration. Only some operations have automatically
inferrable equivalents (the details below on each operation). Sometimes, migrations are destructive and cannot be rolled
back. In this case, you can set `exports.down = false` to tell node-pg-migrate that the down migration is impossible.

## Async Migrations

In some cases, you may want to perform some async operation during a migration, for example, fetching some information
from an external server, or inserting some data into the database. To make a migration block operate in async mode, add
another callback argument to the function signature. However, be aware that NONE of the pgm operations will be executed
until `run()` is called. Here's an example:

```javascript
exports.up = function up(pgm, run) {
doSomethingAsync(function () {
run();
});
};
```

Another way how to perform some async operation is to return [Promise](https://promisesaplus.com/) from `up` or `down`
function. Example:

```javascript
exports.up = function (pgm) {
return new Promise((resolve) => {
// doSomethingAsync
resolve();
});
};
```

or

```javascript
exports.up = async (pgm) => {
// doSomethingAsync
};
```

## Using schemas

Instead of passing string as name to `pgm` functions, you can pass an object with keys `schema` and `name`. E.g.

```javascript
pgm.createTable(
{ schema: 'my_schema', name: 'my_table_name' },
{ id: 'serial' }
);
```

will generate

```sql
CREATE TABLE "my_schema"."my_table_name" (
"id" serial
);
```

### Type

```ts
type Name = string | { schema: string; name: string };
```

## Locking

`node-pg-migrate` automatically checks if no other migration is running. To do so, it uses an
[advisory lock](https://www.postgresql.org/docs/current/static/explicit-locking.html#id-1.5.12.6.9.2)
(see [#239](https://github.com/salsita/node-pg-migrate/pull/239)).
Lock is held for the duration of DB session, so if migration scripts froze up, you need to kill it,
before running another migration script.

## Migration methods

The `pgm` object that is passed to each up/down block has many different operations available.
Each operation is simply
a function that generates some sql and stores it in the current pgm context.

By default, all migrations will be run in a transaction.
To disable transactions for a specific migration,
call `pgm.noTransaction()`
This is required for some SQL operations that cannot be run within a transaction.
It should be used carefully.

- [Tables](tables.md)
- [Columns](columns.md)
- [Constraints](constraints.md)
- [Indexes](indexes.md)
- [Functions](functions.md)
- [Triggers](triggers.md)
- [Schemas](schemas.md)
- [Sequences](sequences.md)
- [Views](views.md)
- [Materialized Views](mViews.md)
- [Types](types.md)
- [Domains](domains.md)
- [Operators](operators.md)
- [Roles](roles.md)
- [Policies](policies.md)
- [Extensions](extensions.md)
- [Miscellaneous](misc.md)
6 changes: 3 additions & 3 deletions docs/indexes.md → docs/src/migrations/indexes.md
Original file line number Diff line number Diff line change
@@ -6,8 +6,8 @@
**Arguments:**

- `tablename` _[[Name](migrations.md#type)]_ - name of the table to alter
- `columns` _[string or array of (array of) strings]_ - columns to add to the index with optional operator class (_[Name](migrations.md#type)_) and sort (_string_)
- `tablename` _[[Name](/migrations/#type)]_ - name of the table to alter
- `columns` _[string or array of (array of) strings]_ - columns to add to the index with optional operator class (_[Name](/migrations/#type)_) and sort (_string_)

Examples:

@@ -36,7 +36,7 @@
**Arguments:**

- `tablename` _[[Name](migrations.md#type)]_ - name of the table to alter
- `tablename` _[[Name](/migrations/#type)]_ - name of the table to alter
- `columns` _[string or array of strings]_ - column names, used only to infer an index name
- `options` _[index options]_ - optional options:
- `name` _[string]_ - name of the index to drop
14 changes: 7 additions & 7 deletions docs/mViews.md → docs/src/migrations/mViews.md
Original file line number Diff line number Diff line change
@@ -6,7 +6,7 @@
**Arguments:**

- `viewName` _[[Name](migrations.md#type)]_ - name of the new materialized view
- `viewName` _[[Name](/migrations/#type)]_ - name of the new materialized view
- `options` _[object]_ - options:
- `ifNotExists` _[boolean]_ - default false
- `columns` _[string or array]_ - use if you want to name columns differently then inferred from definition
@@ -25,7 +25,7 @@
**Arguments:**

- `viewName` _[[Name](migrations.md#type)]_ - name of the view to delete
- `viewName` _[[Name](/migrations/#type)]_ - name of the view to delete
- `options` _[object]_ - options:
- `ifExists` _[boolean]_ - drops view only if it exists
- `cascade` _[boolean]_ - drops also dependent objects
@@ -38,7 +38,7 @@
**Arguments:**

- `viewName` _[[Name](migrations.md#type)]_ - name of the view to alter
- `viewName` _[[Name](/migrations/#type)]_ - name of the view to alter
- `options` _[object]_ - options:
- `cluster` _[string]_ - optional index name for clustering
- `extension` _[string]_ - optional name of extension view is dependent on
@@ -52,8 +52,8 @@
**Arguments:**

- `viewName` _[[Name](migrations.md#type)]_ - old name of the view
- `newViewName` _[[Name](migrations.md#type)]_ - new name of the view
- `viewName` _[[Name](/migrations/#type)]_ - old name of the view
- `newViewName` _[[Name](/migrations/#type)]_ - new name of the view

---

@@ -63,7 +63,7 @@
**Arguments:**

- `viewName` _[[Name](migrations.md#type)]_ - name of the view to alter
- `viewName` _[[Name](/migrations/#type)]_ - name of the view to alter
- `columnName` _[string]_ - current column name
- `newColumnName` _[string]_ - new column name

@@ -75,7 +75,7 @@
**Arguments:**

- `viewName` _[[Name](migrations.md#type)]_ - old name of the view
- `viewName` _[[Name](/migrations/#type)]_ - old name of the view
- `options` _[object]_ - options:
- `concurrently` _[boolean]_ - default false
- `data` _[boolean]_ - default undefined
Loading

0 comments on commit 357c911

Please sign in to comment.