feat(postgres): implement the first version of the PostgreSQL plugin
This commit is contained in:
parent
3d34b8ba13
commit
17c4723bb8
16 changed files with 761 additions and 18 deletions
5
.changeset/hip-camels-learn.md
Normal file
5
.changeset/hip-camels-learn.md
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'@emigrate/postgres': minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Implement the first version of the @emigrate/postgres plugin
|
||||||
|
|
@ -117,6 +117,10 @@ export default defineConfig({
|
||||||
label: 'File System',
|
label: 'File System',
|
||||||
link: '/plugins/storage/file-system/',
|
link: '/plugins/storage/file-system/',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'PostgreSQL',
|
||||||
|
link: '/plugins/storage/postgres/',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'MySQL',
|
label: 'MySQL',
|
||||||
link: '/plugins/storage/mysql/',
|
link: '/plugins/storage/mysql/',
|
||||||
|
|
@ -135,6 +139,10 @@ export default defineConfig({
|
||||||
label: 'Default Loader',
|
label: 'Default Loader',
|
||||||
link: '/plugins/loaders/default/',
|
link: '/plugins/loaders/default/',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'PostgreSQL Loader',
|
||||||
|
link: '/plugins/loaders/postgres/',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'MySQL Loader',
|
label: 'MySQL Loader',
|
||||||
link: '/plugins/loaders/mysql/',
|
link: '/plugins/loaders/mysql/',
|
||||||
|
|
@ -171,6 +179,10 @@ export default defineConfig({
|
||||||
label: 'JavaScript Generator',
|
label: 'JavaScript Generator',
|
||||||
link: '/plugins/generators/js/',
|
link: '/plugins/generators/js/',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'PostgreSQL Generator',
|
||||||
|
link: '/plugins/generators/postgres/',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'MySQL Generator',
|
label: 'MySQL Generator',
|
||||||
link: '/plugins/generators/mysql/',
|
link: '/plugins/generators/mysql/',
|
||||||
|
|
|
||||||
|
|
@ -41,22 +41,22 @@ But for now, this is the way to go.
|
||||||
|
|
||||||
Emigrate uses a <Link href="/plugins/storage/">storage plugin</Link> to store the migration history.
|
Emigrate uses a <Link href="/plugins/storage/">storage plugin</Link> to store the migration history.
|
||||||
|
|
||||||
Install the plugin you want to use, for example:
|
Install the plugin you want to use, for example the <Link href="/plugins/storage/postgres/">PostgreSQL Storage</Link>:
|
||||||
|
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabItem label="npm">
|
<TabItem label="npm">
|
||||||
```bash
|
```bash
|
||||||
npm install @emigrate/mysql
|
npm install @emigrate/postgres
|
||||||
```
|
```
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem label="pnpm">
|
<TabItem label="pnpm">
|
||||||
```bash
|
```bash
|
||||||
pnpm add @emigrate/mysql
|
pnpm add @emigrate/postgres
|
||||||
```
|
```
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem label="yarn">
|
<TabItem label="yarn">
|
||||||
```bash
|
```bash
|
||||||
yarn add @emigrate/mysql
|
yarn add @emigrate/postgres
|
||||||
```
|
```
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
@ -66,7 +66,7 @@ Install the plugin you want to use, for example:
|
||||||
Create a new migration file in your project using:
|
Create a new migration file in your project using:
|
||||||
|
|
||||||
```bash title="Create a new migration file"
|
```bash title="Create a new migration file"
|
||||||
npx emigrate new --plugin mysql create users table
|
npx emigrate new --plugin postgres create users table
|
||||||
```
|
```
|
||||||
|
|
||||||
```txt title="Output"
|
```txt title="Output"
|
||||||
|
|
@ -79,12 +79,12 @@ Emigrate new v0.10.0 /your/project/path
|
||||||
```
|
```
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
The `mysql` plugin is used here to generate a migration file with the `.sql` extension.
|
The `postgres` plugin is used here to generate a migration file with the `.sql` extension.
|
||||||
Otherwise the file would have the `.js` extension by default.
|
Otherwise the file would have the `.js` extension by default.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
:::tip[Did you know?]
|
:::tip[Did you know?]
|
||||||
You can avoid typing `--plugin mysql` by configuring Emigrate using an `emigrate.config.js` file.
|
You can avoid typing `--plugin postgres` by configuring Emigrate using an `emigrate.config.js` file.
|
||||||
See <Link href="/reference/configuration/">Configuration</Link> for more information.
|
See <Link href="/reference/configuration/">Configuration</Link> for more information.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
@ -95,10 +95,9 @@ Open the migration file in your editor and fill it with your SQL query:
|
||||||
```sql title="migrations/20231215125421364_create_users_table.sql" {2-7}
|
```sql title="migrations/20231215125421364_create_users_table.sql" {2-7}
|
||||||
-- Migration: create users table
|
-- Migration: create users table
|
||||||
CREATE TABLE users (
|
CREATE TABLE users (
|
||||||
id INT NOT NULL AUTO_INCREMENT,
|
id SERIAL PRIMARY KEY,
|
||||||
name VARCHAR(255) NOT NULL,
|
name VARCHAR(255) NOT NULL,
|
||||||
email VARCHAR(255) NOT NULL,
|
email VARCHAR(255) NOT NULL
|
||||||
PRIMARY KEY (id)
|
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -111,7 +110,7 @@ There's no magic about the first line comment as when using Liquibase, it's just
|
||||||
To show both pending and already applied migrations (or previously failed), use the `list` command:
|
To show both pending and already applied migrations (or previously failed), use the `list` command:
|
||||||
|
|
||||||
```bash title="Show all migrations"
|
```bash title="Show all migrations"
|
||||||
npx emigrate list --storage mysql
|
npx emigrate list --storage postgres
|
||||||
```
|
```
|
||||||
|
|
||||||
```txt title="Example output"
|
```txt title="Example output"
|
||||||
|
|
@ -129,7 +128,7 @@ Emigrate list v0.10.0 /your/project/path
|
||||||
A good way to test your configuration is to run the migrations in dry mode:
|
A good way to test your configuration is to run the migrations in dry mode:
|
||||||
|
|
||||||
```bash title="Show pending migrations"
|
```bash title="Show pending migrations"
|
||||||
npx emigrate up --storage mysql --plugin mysql --dry
|
npx emigrate up --storage postgres --plugin postgres --dry
|
||||||
```
|
```
|
||||||
|
|
||||||
:::note
|
:::note
|
||||||
|
|
@ -142,6 +141,6 @@ Be sure to configure the connection correctly and use the `--dry` flag to test y
|
||||||
:::
|
:::
|
||||||
|
|
||||||
:::tip[Did you know?]
|
:::tip[Did you know?]
|
||||||
In the example above the `@emigrate/mysql` plugin is used twice, once for the `--storage` option as a <Link href="/plugins/storage/">Storage Plugin</Link>
|
In the example above the `@emigrate/postgres` plugin is used twice, once for the `--storage` option as a <Link href="/plugins/storage/">Storage Plugin</Link>
|
||||||
and once for the `--plugin` option as a <Link href="/plugins/loaders/">Loader Plugin</Link> to be able to read `.sql` files.
|
and once for the `--plugin` option as a <Link href="/plugins/loaders/">Loader Plugin</Link> to be able to read `.sql` files.
|
||||||
:::
|
:::
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ The generator is responsible for generating migration files in a specific format
|
||||||
|
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
<LinkCard title="JavaScript generator" href="js/" description="A generator that generates .js migration files (using ESM and default export)" />
|
<LinkCard title="JavaScript generator" href="js/" description="A generator that generates .js migration files (using ESM and default export)" />
|
||||||
|
<LinkCard title="PostgreSQL generator" href="postgres/" description="A generator that generates .sql migration files" />
|
||||||
<LinkCard title="MySQL generator" href="mysql/" description="A generator that generates .sql migration files" />
|
<LinkCard title="MySQL generator" href="mysql/" description="A generator that generates .sql migration files" />
|
||||||
</CardGrid>
|
</CardGrid>
|
||||||
|
|
||||||
|
|
|
||||||
36
docs/src/content/docs/plugins/generators/postgres.mdx
Normal file
36
docs/src/content/docs/plugins/generators/postgres.mdx
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
title: "PostgreSQL Generator"
|
||||||
|
---
|
||||||
|
|
||||||
|
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||||
|
import Link from '@components/Link.astro';
|
||||||
|
|
||||||
|
The PostgreSQL generator creates new migration files with the `.sql` extension. In the same package you can find the <Link href="/plugins/loaders/postgres/">PostgreSQL Loader</Link> and the <Link href="/plugins/storage/postgres/">PostgreSQL Storage</Link>.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem label="npm">
|
||||||
|
```bash
|
||||||
|
npm install @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem label="pnpm">
|
||||||
|
```bash
|
||||||
|
pnpm add @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem label="yarn">
|
||||||
|
```bash
|
||||||
|
yarn add @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```bash
|
||||||
|
emigrate new --plugin postgres create some fancy table
|
||||||
|
```
|
||||||
|
|
||||||
|
For more information see <Link href="/commands/new/">the `new` command</Link>'s documentation.
|
||||||
|
|
@ -21,7 +21,7 @@ Or set it up in your configuration file, see <Link href="/reference/configuratio
|
||||||
|
|
||||||
:::tip[Did you know?]
|
:::tip[Did you know?]
|
||||||
You can specify multiple loader plugins at the same time, which is needed when you mix file types in your migrations folder.
|
You can specify multiple loader plugins at the same time, which is needed when you mix file types in your migrations folder.
|
||||||
For example, you can use the `mysql` loader for `.sql` files and the `typescript` loader for `.ts` files.
|
For example, you can use the `postgres` or `mysql` loader for `.sql` files and the `typescript` loader for `.ts` files.
|
||||||
The <Link href="/plugins/loaders/default/">default loader</Link> will be used for all other file types, and doesn't need to be specified.
|
The <Link href="/plugins/loaders/default/">default loader</Link> will be used for all other file types, and doesn't need to be specified.
|
||||||
:::
|
:::
|
||||||
|
|
||||||
|
|
@ -29,5 +29,6 @@ The <Link href="/plugins/loaders/default/">default loader</Link> will be used fo
|
||||||
|
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
<LinkCard title="Default Loader" href="default/" description="The loader responsible for loading .js, .cjs and .mjs files" />
|
<LinkCard title="Default Loader" href="default/" description="The loader responsible for loading .js, .cjs and .mjs files" />
|
||||||
|
<LinkCard title="PostgreSQL Loader" href="postgres/" description="Can load and execute .sql files against a PostgreSQL database" />
|
||||||
<LinkCard title="MySQL Loader" href="mysql/" description="Can load and execute .sql files against a MySQL database" />
|
<LinkCard title="MySQL Loader" href="mysql/" description="Can load and execute .sql files against a MySQL database" />
|
||||||
</CardGrid>
|
</CardGrid>
|
||||||
|
|
|
||||||
86
docs/src/content/docs/plugins/loaders/postgres.mdx
Normal file
86
docs/src/content/docs/plugins/loaders/postgres.mdx
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
---
|
||||||
|
title: PostgreSQL Loader Plugin
|
||||||
|
---
|
||||||
|
|
||||||
|
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||||
|
import Link from '@components/Link.astro';
|
||||||
|
|
||||||
|
The PostgreSQL loader plugin transforms `.sql` files into JavaScript functions that Emigrate can use to execute the migrations. In the same package you can find the <Link href="/plugins/generators/postgres/">PostgreSQL Generator</Link> and the <Link href="/plugins/storage/postgres/">PostgreSQL Storage</Link>.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem label="npm">
|
||||||
|
```bash
|
||||||
|
npm install @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem label="pnpm">
|
||||||
|
```bash
|
||||||
|
pnpm add @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem label="yarn">
|
||||||
|
```bash
|
||||||
|
yarn add @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The PostgreSQL loader plugin can be configured either using environment variables or by configuring the plugin directly in the <Link href="/reference/configuration/">`emigrate.config.js` file</Link>.
|
||||||
|
|
||||||
|
### Configuration file
|
||||||
|
|
||||||
|
```js title="emigrate.config.js" {1,4-8}
|
||||||
|
import { createPostgresLoader } from '@emigrate/postgres';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
plugins: [
|
||||||
|
createPostgresLoader({
|
||||||
|
connection: { ... },
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
##### `connection` (required)
|
||||||
|
|
||||||
|
**type:** `object | string`
|
||||||
|
|
||||||
|
The connection options to use for connecting to the PostgreSQL database when the SQL statements from the migration files are executed. This can either be a connection URI or an object with connection options.
|
||||||
|
For a list of supported connection options, see the [postgres documentation](https://github.com/porsager/postgres#connection).
|
||||||
|
|
||||||
|
### Environment variables
|
||||||
|
|
||||||
|
The following environment variables are supported:
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
| ------------------- | ----------------------------------------------------------------------------------------------------------- | ------------- |
|
||||||
|
| `POSTGRES_URL` | The full URI for connecting to a PostgreSQL database, e.g: `"postgres://user:pass@127.0.0.1:3306/database"` | |
|
||||||
|
| `POSTGRES_HOST` | The host on which the PostgreSQL server instance is running | `"localhost"` |
|
||||||
|
| `POSTGRES_USER` | The PostgreSQL user account to use for the authentication | |
|
||||||
|
| `POSTGRES_PASSWORD` | The PostgreSQL user password to use for the authentication | |
|
||||||
|
| `POSTGRES_PORT` | The network port on which the PostgreSQL server is listening | `5432` |
|
||||||
|
| `POSTGRES_DB` | The PostgreSQL database to use for the connection | |
|
||||||
|
|
||||||
|
:::note
|
||||||
|
The `POSTGRES_URL` environment variable takes precedence over the other environment variables. If `POSTGRES_URL` is set, the other environment variables are ignored.
|
||||||
|
:::
|
||||||
|
|
||||||
|
The environment variables are used when the plugin is used using the `--plugin` command line option:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx emigrate list --plugin postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
Or when specifying the plugin in the <Link href="/reference/configuration/">`emigrate.config.js` file</Link> as a string:
|
||||||
|
|
||||||
|
```js title="emigrate.config.js" {2}
|
||||||
|
export default {
|
||||||
|
plugins: ['postgres'],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
@ -13,7 +13,7 @@ Usually you'll want to store the migration history in the same database as the o
|
||||||
You can specify a storage plugin via the `--storage` (or `-s` for short) option:
|
You can specify a storage plugin via the `--storage` (or `-s` for short) option:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npx emigrate list --storage mysql
|
npx emigrate list --storage postgres
|
||||||
```
|
```
|
||||||
|
|
||||||
Or set it up in your configuration file, see <Link href="/reference/configuration/#storage">Storage configuration</Link> for more information.
|
Or set it up in your configuration file, see <Link href="/reference/configuration/#storage">Storage configuration</Link> for more information.
|
||||||
|
|
@ -22,6 +22,7 @@ Or set it up in your configuration file, see <Link href="/reference/configuratio
|
||||||
|
|
||||||
<CardGrid>
|
<CardGrid>
|
||||||
<LinkCard title="File System" href="file-system/" description="The most basic storage plugin - for simple setups" />
|
<LinkCard title="File System" href="file-system/" description="The most basic storage plugin - for simple setups" />
|
||||||
|
<LinkCard title="PostgreSQL" href="postgres/" description="A storage plugin that uses a PostgreSQL database for storing the migration history state" />
|
||||||
<LinkCard title="MySQL" href="mysql/" description="A storage plugin that uses a MySQL database for storing the migration history state" />
|
<LinkCard title="MySQL" href="mysql/" description="A storage plugin that uses a MySQL database for storing the migration history state" />
|
||||||
</CardGrid>
|
</CardGrid>
|
||||||
|
|
||||||
|
|
|
||||||
93
docs/src/content/docs/plugins/storage/postgres.mdx
Normal file
93
docs/src/content/docs/plugins/storage/postgres.mdx
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
---
|
||||||
|
title: PostgreSQL Storage
|
||||||
|
---
|
||||||
|
|
||||||
|
import { Tabs, TabItem } from '@astrojs/starlight/components';
|
||||||
|
import Link from '@components/Link.astro';
|
||||||
|
|
||||||
|
The PostgreSQL storage plugin uses a PostgreSQL database to store the migration history (*duh*). In the same package you can find the <Link href="/plugins/loaders/postgres/">PostgreSQL Loader</Link> and the <Link href="/plugins/generators/postgres/">PostgreSQL Generator</Link>.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
<Tabs>
|
||||||
|
<TabItem label="npm">
|
||||||
|
```bash
|
||||||
|
npm install @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem label="pnpm">
|
||||||
|
```bash
|
||||||
|
pnpm add @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
<TabItem label="yarn">
|
||||||
|
```bash
|
||||||
|
yarn add @emigrate/postgres
|
||||||
|
```
|
||||||
|
</TabItem>
|
||||||
|
</Tabs>
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
The PostgreSQL storage can be configured either using environment variables or by configuring the plugin directly in the <Link href="/reference/configuration/">`emigrate.config.js` file</Link>.
|
||||||
|
|
||||||
|
### Configuration file
|
||||||
|
|
||||||
|
```js title="emigrate.config.js" {1,4-7}
|
||||||
|
import { createPostgresStorage } from '@emigrate/postgres';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
storage: createPostgresStorage({
|
||||||
|
table: 'migrations',
|
||||||
|
connection: { ... },
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Options
|
||||||
|
|
||||||
|
##### `table`
|
||||||
|
|
||||||
|
**type:** `string`
|
||||||
|
**default:** `"migrations"`
|
||||||
|
|
||||||
|
The name of the table to use for storing the migrations.
|
||||||
|
|
||||||
|
##### `connection` (required)
|
||||||
|
|
||||||
|
**type:** `object | string`
|
||||||
|
|
||||||
|
The connection options to use for connecting to the PostgreSQL database. This can either be a connection URI or an object with connection options.
|
||||||
|
For a list of supported connection options, see the [postgres documentation](https://github.com/porsager/postgres#connection).
|
||||||
|
|
||||||
|
### Environment variables
|
||||||
|
|
||||||
|
The following environment variables are supported:
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
| ------------------- | ----------------------------------------------------------------------------------------------------------- | -------------- |
|
||||||
|
| `POSTGRES_TABLE` | The name of the table to use for storing the migrations | `"migrations"` |
|
||||||
|
| `POSTGRES_URL` | The full URI for connecting to a PostgreSQL database, e.g: `"postgres://user:pass@127.0.0.1:3306/database"` | |
|
||||||
|
| `POSTGRES_HOST` | The host on which the PostgreSQL server instance is running | `"localhost"` |
|
||||||
|
| `POSTGRES_USER` | The PostgreSQL user account to use for the authentication | |
|
||||||
|
| `POSTGRES_PASSWORD` | The PostgreSQL user password to use for the authentication | |
|
||||||
|
| `POSTGRES_PORT` | The network port on which the PostgreSQL server is listening | `5432` |
|
||||||
|
| `POSTGRES_DB` | The PostgreSQL database to use for the connection | |
|
||||||
|
|
||||||
|
:::note
|
||||||
|
The `POSTGRES_URL` environment variable takes precedence over the other environment variables. If `POSTGRES_URL` is set, the other environment variables are ignored, except for `POSTGRES_TABLE`.
|
||||||
|
:::
|
||||||
|
|
||||||
|
The environment variables are used when the storage plugin is used using the `--storage` command line option:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx emigrate list --storage postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
Or when specifying the storage in the <Link href="/reference/configuration/">`emigrate.config.js` file</Link> as a string:
|
||||||
|
|
||||||
|
```js title="emigrate.config.js" {2}
|
||||||
|
export default {
|
||||||
|
storage: 'postgres',
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
@ -56,7 +56,7 @@ Options:
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
emigrate up --directory src/migrations -s fs
|
emigrate up --directory src/migrations -s fs
|
||||||
emigrate up -d ./migrations --storage @emigrate/storage-mysql
|
emigrate up -d ./migrations --storage @emigrate/mysql
|
||||||
emigrate up -d src/migrations -s postgres -r json --dry
|
emigrate up -d src/migrations -s postgres -r json --dry
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# @emigrate/storage-mysql
|
# @emigrate/mysql
|
||||||
|
|
||||||
A MySQL plugin for Emigrate. Uses a MySQL database for storing migration history. Can load and generate .sql migration files.
|
A MySQL plugin for Emigrate. Uses a MySQL database for storing the migration history. Can load and generate .sql migration files.
|
||||||
|
|
||||||
The table used for storing the migration history is compatible with the [immigration-mysql](https://github.com/joakimbeng/immigration-mysql) package, so you can use this together with the [@emigrate/cli](../cli) as a drop-in replacement for that package.
|
The table used for storing the migration history is compatible with the [immigration-mysql](https://github.com/joakimbeng/immigration-mysql) package, so you can use this together with the [@emigrate/cli](../cli) as a drop-in replacement for that package.
|
||||||
|
|
||||||
|
|
|
||||||
177
packages/postgres/README.md
Normal file
177
packages/postgres/README.md
Normal file
|
|
@ -0,0 +1,177 @@
|
||||||
|
# @emigrate/postgres
|
||||||
|
|
||||||
|
A PostgreSQL plugin for Emigrate. Uses a PostgreSQL database for storing the migration history. Can load and generate .sql migration files.
|
||||||
|
|
||||||
|
The table used for storing the migration history is compatible with the [immigration-postgres](https://github.com/aboviq/immigration-postgres) package, so you can use this together with the [@emigrate/cli](../cli) as a drop-in replacement for that package.
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
This plugin is actually three different Emigrate plugins in one:
|
||||||
|
|
||||||
|
1. A [storage plugin](#using-the-storage-plugin) for storing the migration history in a PostgreSQL database.
|
||||||
|
2. A [loader plugin](#using-the-loader-plugin) for loading .sql migration files and be able to execute them as part of the migration process.
|
||||||
|
3. A [generator plugin](#using-the-generator-plugin) for generating .sql migration files.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Install the plugin in your project, alongside the Emigrate CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm install --save-dev @emigrate/cli @emigrate/postgres
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Using the storage plugin
|
||||||
|
|
||||||
|
See [Options](#options) below for the default values and how to configure the plugin using environment variables.
|
||||||
|
|
||||||
|
Configure the storage in your `emigrate.config.js` file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
storage: 'postgres', // the @emigrate/ prefix is optional
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use the CLI options `--storage` (or `-s`)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
emigrate up --storage postgres # the @emigrate/ prefix is optional
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Storage plugin with custom options
|
||||||
|
|
||||||
|
Configure the storage in your `emigrate.config.js` file by importing the `createPostgresStorage` function (see [Options](#options) for available options).
|
||||||
|
|
||||||
|
In this mode the plugin will _not_ use any of the environment variables for configuration.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createPostgresStorage } from '@emigrate/postgres';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
storage: createPostgresStorage({ table: 'migrations', connection: { ... } }), // All connection options are passed to postgres()
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Or use the CLI option `--storage` (or `-s`) and use environment variables (see [Options](#options) for available variables).
|
||||||
|
|
||||||
|
```bash
|
||||||
|
POSTGRES_URL=postgres://user:pass@host/db emigrate up --storage postgres # the @emigrate/ prefix is optional
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the loader plugin
|
||||||
|
|
||||||
|
The loader plugin is used to transform .sql migration files into JavaScript functions that can be executed by the "up" command.
|
||||||
|
|
||||||
|
See [Options](#options) below for the default values and how to configure the plugin using environment variables.
|
||||||
|
|
||||||
|
Configure the loader in your `emigrate.config.js` file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
plugins: ['postgres'], // the @emigrate/ prefix is optional
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Or by importing the default export from the plugin:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import postgresPlugin from '@emigrate/postgres';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
plugins: [postgresPlugin],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**NOTE:** Using the root level `plugins` option will load the plugin for all commands, which means the [generator plugin](#using-the-generator-plugin) will be used by default for the "new" command as well. If you only want to use the loader plugin, use the `up.plugins` option instead:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
up: {
|
||||||
|
plugins: ['postgres'], // the @emigrate/ prefix is optional
|
||||||
|
// or:
|
||||||
|
plugins: [import('@emigrate/postgres')],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The loader plugin can also be loaded using the CLI option `--plugin` (or `-p`) together with the "up" command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
emigrate up --plugin postgres # the @emigrate/ prefix is optional
|
||||||
|
```
|
||||||
|
|
||||||
|
### Using the generator plugin
|
||||||
|
|
||||||
|
The generator plugin is used to generate skeleton .sql migration files inside your migration directory.
|
||||||
|
|
||||||
|
Configure the generator in your `emigrate.config.js` file:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
plugins: ['postgres'], // the @emigrate/ prefix is optional
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
Or by importing the default export from the plugin:
|
||||||
|
|
||||||
|
```js
|
||||||
|
import postgresPlugin from '@emigrate/postgres';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
plugins: [postgresPlugin],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**NOTE:** Using the root level `plugins` option will load the plugin for all commands, which means the [loader plugin](#using-the-loader-plugin) will be used by default for the "up" command as well. If you only want to use the generator plugin, use the `new.plugins` option instead:
|
||||||
|
|
||||||
|
```js
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
new: {
|
||||||
|
plugins: ['postgres'], // the @emigrate/ prefix is optional
|
||||||
|
// or:
|
||||||
|
plugins: [import('@emigrate/postgres')],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
The generator plugin can also be loaded using the CLI option `--plugin` (or `-p`) together with the "new" command:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
emigrate new --plugin postgres My new migration file # the @emigrate/ prefix is optional
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Loader plugin with custom options
|
||||||
|
|
||||||
|
Configure the loader in your `emigrate.config.js` file by importing the `createPostgresLoader` function (see [Options](#options) for available options).
|
||||||
|
|
||||||
|
In this mode the plugin will _not_ use any of the environment variables for configuration.
|
||||||
|
|
||||||
|
```js
|
||||||
|
import { createPostgresLoader } from '@emigrate/postgres';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
directory: 'migrations',
|
||||||
|
plugins: [
|
||||||
|
createPostgresLoader({ connection: { ... } }), // All connection options are passed to postgres()
|
||||||
|
],
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
The storage plugin accepts the following options:
|
||||||
|
|
||||||
|
| Option | Applies to | Description | Default | Environment variable |
|
||||||
|
| ------------ | -------------------------- | -------------------------------------------------------------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------- |
|
||||||
|
| `table` | storage plugin | The name of the table to use for storing the migrations. | `migrations` | `POSTGRES_TABLE` |
|
||||||
|
| `connection` | storage and loader plugins | The connection options to pass to [`postgres()`](https://github.com/porsager/postgres#connection). | `{}` | `POSTGRES_URL` or `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_USER`, `POSTGRES_PASSWORD` and `POSTGRES_DB` |
|
||||||
51
packages/postgres/package.json
Normal file
51
packages/postgres/package.json
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
{
|
||||||
|
"name": "@emigrate/postgres",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"publishConfig": {
|
||||||
|
"access": "public"
|
||||||
|
},
|
||||||
|
"description": "A PostgreSQL plugin for Emigrate. Uses a PostgreSQL database for storing migration history. Can load and generate .sql migration files.",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/index.d.js",
|
||||||
|
"type": "module",
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/index.js",
|
||||||
|
"types": "./dist/index.d.ts"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsc --pretty",
|
||||||
|
"build:watch": "tsc --pretty --watch",
|
||||||
|
"lint": "xo --cwd=../.. $(pwd)"
|
||||||
|
},
|
||||||
|
"keywords": [
|
||||||
|
"emigrate",
|
||||||
|
"emigrate-storage",
|
||||||
|
"emigrate-loader",
|
||||||
|
"emigrate-plugin",
|
||||||
|
"emigrate-generator",
|
||||||
|
"migrations",
|
||||||
|
"postgres",
|
||||||
|
"postgresql"
|
||||||
|
],
|
||||||
|
"author": "Aboviq AB <dev@aboviq.com> (https://www.aboviq.com)",
|
||||||
|
"homepage": "https://github.com/aboviq/emigrate/tree/main/packages/postgres#readme",
|
||||||
|
"repository": "https://github.com/aboviq/emigrate/tree/main/packages/postgres",
|
||||||
|
"bugs": "https://github.com/aboviq/emigrate/issues",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@emigrate/plugin-tools": "workspace:*",
|
||||||
|
"@emigrate/types": "workspace:*",
|
||||||
|
"postgres": "3.4.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@emigrate/tsconfig": "workspace:*"
|
||||||
|
},
|
||||||
|
"volta": {
|
||||||
|
"extends": "../../package.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
252
packages/postgres/src/index.ts
Normal file
252
packages/postgres/src/index.ts
Normal file
|
|
@ -0,0 +1,252 @@
|
||||||
|
import process from 'node:process';
|
||||||
|
import postgres, { type Options, type PostgresType, type Sql } from 'postgres';
|
||||||
|
import { getTimestampPrefix, sanitizeMigrationName } from '@emigrate/plugin-tools';
|
||||||
|
import {
|
||||||
|
type MigrationMetadata,
|
||||||
|
type EmigrateStorage,
|
||||||
|
type LoaderPlugin,
|
||||||
|
type Storage,
|
||||||
|
type MigrationMetadataFinished,
|
||||||
|
type GenerateMigrationFunction,
|
||||||
|
type GeneratorPlugin,
|
||||||
|
type SerializedError,
|
||||||
|
type MigrationHistoryEntry,
|
||||||
|
} from '@emigrate/types';
|
||||||
|
|
||||||
|
const defaultTable = 'migrations';
|
||||||
|
|
||||||
|
type ConnectionOptions = Options<Record<string, PostgresType>>;
|
||||||
|
|
||||||
|
export type PostgresStorageOptions = {
|
||||||
|
table?: string;
|
||||||
|
/**
|
||||||
|
* @see https://github.com/porsager/postgres#connection
|
||||||
|
*/
|
||||||
|
connection: ConnectionOptions | string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type PostgresLoaderOptions = {
|
||||||
|
/**
|
||||||
|
* @see https://github.com/porsager/postgres#connection
|
||||||
|
*/
|
||||||
|
connection: ConnectionOptions | string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPool = (connection: ConnectionOptions | string) => {
|
||||||
|
if (typeof connection === 'string') {
|
||||||
|
return postgres(connection);
|
||||||
|
}
|
||||||
|
|
||||||
|
return postgres(connection);
|
||||||
|
};
|
||||||
|
|
||||||
|
const lockMigration = async (sql: Sql, table: string, migration: MigrationMetadata) => {
|
||||||
|
const result = await sql`
|
||||||
|
INSERT INTO ${sql(table)} (name, status, date)
|
||||||
|
VALUES (${migration.name}, ${'locked'}, NOW())
|
||||||
|
ON CONFLICT (name) DO NOTHING
|
||||||
|
`;
|
||||||
|
|
||||||
|
return result.count === 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const unlockMigration = async (sql: Sql, table: string, migration: MigrationMetadata) => {
|
||||||
|
const result = await sql`
|
||||||
|
DELETE FROM ${sql(table)}
|
||||||
|
WHERE
|
||||||
|
name = ${migration.name}
|
||||||
|
AND status = ${'locked'}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return result.count === 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const finishMigration = async (
|
||||||
|
sql: Sql,
|
||||||
|
table: string,
|
||||||
|
migration: MigrationMetadataFinished,
|
||||||
|
_error?: SerializedError,
|
||||||
|
) => {
|
||||||
|
const result = await sql`
|
||||||
|
UPDATE
|
||||||
|
${sql(table)}
|
||||||
|
SET
|
||||||
|
status = ${migration.status},
|
||||||
|
date = NOW()
|
||||||
|
WHERE
|
||||||
|
name = ${migration.name}
|
||||||
|
AND status = ${'locked'}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return result.count === 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deleteMigration = async (sql: Sql, table: string, migration: MigrationMetadata) => {
|
||||||
|
const result = await sql`
|
||||||
|
DELETE FROM ${sql(table)}
|
||||||
|
WHERE
|
||||||
|
name = ${migration.name}
|
||||||
|
AND status <> ${'locked'}
|
||||||
|
`;
|
||||||
|
|
||||||
|
return result.count === 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const initializeTable = async (sql: Sql, table: string) => {
|
||||||
|
const [row] = await sql<Array<{ exists: 1 }>>`
|
||||||
|
SELECT 1 as exists
|
||||||
|
FROM
|
||||||
|
information_schema.tables
|
||||||
|
WHERE
|
||||||
|
table_schema = 'public'
|
||||||
|
AND table_name = ${table}
|
||||||
|
`;
|
||||||
|
|
||||||
|
if (row?.exists) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This table definition is compatible with the one used by the immigration-postgres package
|
||||||
|
await sql`
|
||||||
|
CREATE TABLE ${sql(table)} (
|
||||||
|
name varchar(255) not null primary key,
|
||||||
|
status varchar(32),
|
||||||
|
date timestamptz not null
|
||||||
|
);
|
||||||
|
`;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const createPostgresStorage = ({
|
||||||
|
table = defaultTable,
|
||||||
|
connection,
|
||||||
|
}: PostgresStorageOptions): EmigrateStorage => {
|
||||||
|
return {
|
||||||
|
async initializeStorage() {
|
||||||
|
const sql = getPool(connection);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await initializeTable(sql, table);
|
||||||
|
} catch (error) {
|
||||||
|
await sql.end();
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
const storage: Storage = {
|
||||||
|
async lock(migrations) {
|
||||||
|
const lockedMigrations: MigrationMetadata[] = [];
|
||||||
|
|
||||||
|
for await (const migration of migrations) {
|
||||||
|
if (await lockMigration(sql, table, migration)) {
|
||||||
|
lockedMigrations.push(migration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return lockedMigrations;
|
||||||
|
},
|
||||||
|
async unlock(migrations) {
|
||||||
|
for await (const migration of migrations) {
|
||||||
|
await unlockMigration(sql, table, migration);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async remove(migration) {
|
||||||
|
await deleteMigration(sql, table, migration);
|
||||||
|
},
|
||||||
|
async *getHistory() {
|
||||||
|
const query = sql<Array<Exclude<MigrationHistoryEntry, 'error'>>>`
|
||||||
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
${sql(table)}
|
||||||
|
WHERE
|
||||||
|
status <> ${'locked'}
|
||||||
|
ORDER BY
|
||||||
|
date ASC
|
||||||
|
`.cursor();
|
||||||
|
|
||||||
|
for await (const [row] of query) {
|
||||||
|
if (!row) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (row.status === 'failed') {
|
||||||
|
yield {
|
||||||
|
...row,
|
||||||
|
error: { name: 'Error', message: 'Unknown error' },
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
yield row;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async onSuccess(migration) {
|
||||||
|
await finishMigration(sql, table, migration);
|
||||||
|
},
|
||||||
|
async onError(migration, error) {
|
||||||
|
await finishMigration(sql, table, migration, error);
|
||||||
|
},
|
||||||
|
async end() {
|
||||||
|
await sql.end();
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
return storage;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const { initializeStorage } = createPostgresStorage({
|
||||||
|
table: process.env['POSTGRES_TABLE'],
|
||||||
|
connection: process.env['POSTGRES_URL'] ?? {
|
||||||
|
host: process.env['POSTGRES_HOST'],
|
||||||
|
port: process.env['POSTGRES_PORT'] ? Number.parseInt(process.env['POSTGRES_PORT'], 10) : undefined,
|
||||||
|
user: process.env['POSTGRES_USER'],
|
||||||
|
password: process.env['POSTGRES_PASSWORD'],
|
||||||
|
database: process.env['POSTGRES_DB'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createPostgresLoader = ({ connection }: PostgresLoaderOptions): LoaderPlugin => {
|
||||||
|
return {
|
||||||
|
loadableExtensions: ['.sql'],
|
||||||
|
async loadMigration(migration) {
|
||||||
|
return async () => {
|
||||||
|
const sql = getPool(connection);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// @ts-expect-error The "simple" option is not documented, but it exists
|
||||||
|
await sql.file(migration.filePath, { simple: true });
|
||||||
|
} finally {
|
||||||
|
await sql.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
},
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const { loadableExtensions, loadMigration } = createPostgresLoader({
|
||||||
|
connection: process.env['POSTGRES_URL'] ?? {
|
||||||
|
host: process.env['POSTGRES_HOST'],
|
||||||
|
port: process.env['POSTGRES_PORT'] ? Number.parseInt(process.env['POSTGRES_PORT'], 10) : undefined,
|
||||||
|
user: process.env['POSTGRES_USER'],
|
||||||
|
password: process.env['POSTGRES_PASSWORD'],
|
||||||
|
database: process.env['POSTGRES_DB'],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export const generateMigration: GenerateMigrationFunction = async (name) => {
|
||||||
|
return {
|
||||||
|
filename: `${getTimestampPrefix()}_${sanitizeMigrationName(name)}.sql`,
|
||||||
|
content: `-- Migration: ${name}
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const defaultExport: EmigrateStorage & LoaderPlugin & GeneratorPlugin = {
|
||||||
|
initializeStorage,
|
||||||
|
loadableExtensions,
|
||||||
|
loadMigration,
|
||||||
|
generateMigration,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default defaultExport;
|
||||||
8
packages/postgres/tsconfig.json
Normal file
8
packages/postgres/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"extends": "@emigrate/tsconfig/build.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "dist"
|
||||||
|
},
|
||||||
|
"include": ["src"],
|
||||||
|
"exclude": ["node_modules", "dist"]
|
||||||
|
}
|
||||||
21
pnpm-lock.yaml
generated
21
pnpm-lock.yaml
generated
|
|
@ -148,6 +148,22 @@ importers:
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../tsconfig
|
version: link:../tsconfig
|
||||||
|
|
||||||
|
packages/postgres:
|
||||||
|
dependencies:
|
||||||
|
'@emigrate/plugin-tools':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../plugin-tools
|
||||||
|
'@emigrate/types':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../types
|
||||||
|
postgres:
|
||||||
|
specifier: 3.4.3
|
||||||
|
version: 3.4.3
|
||||||
|
devDependencies:
|
||||||
|
'@emigrate/tsconfig':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../tsconfig
|
||||||
|
|
||||||
packages/reporter-pino:
|
packages/reporter-pino:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@emigrate/types':
|
'@emigrate/types':
|
||||||
|
|
@ -7030,6 +7046,11 @@ packages:
|
||||||
source-map-js: 1.0.2
|
source-map-js: 1.0.2
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/postgres@3.4.3:
|
||||||
|
resolution: {integrity: sha512-iHJn4+M9vbTdHSdDzNkC0crHq+1CUdFhx+YqCE+SqWxPjm+Zu63jq7yZborOBF64c8pc58O5uMudyL1FQcHacA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/prebuild-install@7.1.1:
|
/prebuild-install@7.1.1:
|
||||||
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
||||||
engines: {node: '>=10'}
|
engines: {node: '>=10'}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue