Skip to content

Commit bd6f900

Browse files
committed
Add --force flag; update README
1 parent 6710ffa commit bd6f900

File tree

8 files changed

+61
-48
lines changed

8 files changed

+61
-48
lines changed

README.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -264,12 +264,12 @@ UPDATE my_table SET some=:'var1';
264264
265265
### Use Environment Variables
266266
267-
If you assign e.g. `process.env.HOSTS = "{a,b,c}"` in your `pg-mig.config.ts` file, you can use that value in all of the version files using the standard `psql` feature:
267+
If you assign e.g. `process.env.VAR = "a,b,c"` (or return it) in your `pg-mig.config.ts` file, you can use that value in all of the version files using the standard `psql` feature:
268268
269269
```sql
270270
-- mig/20231017204837.initial.public.up.sql
271-
\set HOSTS `echo "$HOSTS"`
272-
SELECT my_function(:'HOSTS');
271+
\set HOSTS `echo "$VAR"`
272+
SELECT my_function(:'VAR');
273273
```
274274
275275
### More Meta-Commands
@@ -319,37 +319,41 @@ Here is the complete list of `-- $` pseudo comments that pg-mig supports in the
319319
* `$parallelism_per_host=N`: as mentioned above, this option forces the parallel migrations for schemas on the same host to wait for each other, not allowing to run more than N of then at the same time.
320320
* `$parallelism_global=N`: limits parallelism of this particular version _within the same schema prefix_ across all hosts.
321321
* `$delay=M`: introduces a delay (in ms) between each migration. You can use it with `$parallelism_global` to reduce load on the database even further.
322-
* `$run_alone=1`: if set to 1, no other migrations, _including other schema prefixes_, will run on any other host while this one is running. I.e. it introduces global ordering of the migration files application across schemas. This option is useful when you want to e.g. install a PostgreSQL extension used in other schemas, so you want all other schemas to wait until the installation finishes.
322+
* `$run_alone=1`: if set to 1, no other migrations, _including other schema prefixes_, will run on any other host while this one is running. I.e. it introduces a global ordering of the migration files application across schemas. This option is useful when you want to e.g. install a PostgreSQL extension used in other schemas, so you want all other schemas to wait until the installation finishes.
323323
324324
## Advanced: Use With pg-microsharding Library
325325
326326
Overall, there are many popular alternatives to pg-mig when it comes to managing a single database with no sharding. But when it comes to migrating the entire cluster with multiple nodes, or working with microsharding, pg-mig starts shining.
327327
328-
The recommended library to manage the microshards schemas is [pg-microsharding](https://www.npmjs.com/package/@clickup/pg-microsharding). To couple it with pg-mig, create the following files:
328+
The recommended library to manage the microshards schemas is [pg-microsharding](https://www.npmjs.com/package/@clickup/pg-microsharding). To couple it with pg-mig, create the following before/after scripts:
329329
330330
```sql
331-
-- mig/YYYYMMDDhhmmss.add_microsharding.public.up.sql
332-
CREATE SCHEMA microsharding;
331+
-- mig/before.sql
332+
CREATE SCHEMA IF NOT EXISTS microsharding;
333333
SET search_path TO microsharding;
334334
\ir ../pg-microsharding/sql/pg-microsharding-up.sql
335-
```
336-
337-
```sql
338-
-- mig/YYYYMMDDhhmmss.add_microsharding.public.dn.sql
339-
DROP SCHEMA microsharding;
340-
```
341-
342-
Also, define before/after scripts:
343-
344-
```sql
345-
-- mig/before.sql
346335
SELECT microsharding.microsharding_migration_before();
347336
```
348337
349338
```sql
350339
-- mig/after.sql
351340
\set HOSTS `echo "$HOSTS"`
352-
SELECT microsharding.microsharding_migration_after(:'HOSTS');
341+
SELECT microsharding.microsharding_migration_after(:'PGHOST');
342+
```
343+
344+
Make sure that you also define `PGHOST` environment variable as a comma-separated list of cluster hosts in your `pg-mig.config.ts` :
345+
346+
```typescript
347+
export default async function(action: "apply" | "undo" | string) {
348+
...
349+
return {
350+
PGHOST: islands
351+
.map((island) => island.nodes.map(({ host }) => host)
352+
.flat()
353+
.join(","),
354+
...
355+
};
356+
}
353357
```
354358
355359
### Microsharding Debug Views
@@ -494,7 +498,7 @@ To help with this check, pg-mig exposes the concept called "version digest". It'
494498
495499
Digest is a string, and by comparing 2 digests lexicographically, you may make a decision, which one is "better" (or, if you don't want "better/worse" comparison, you can also compare them for strict equality). If the database's digest is **greater or equal to** the application code's digest, then the code is compatible to the currently existing cluster schema, so the code can be deployed ("your database is ahead of the code").
496500
497-
* Run `pg-mig --list=digest` to print the digest of the current migration files on disk (i.e. "code digest"), like `20250114061047.1552475c743aac017bf0252d540eb033859c6e`.
501+
* Run `pg-mig --list=digest` to print the digest of the current migration files on disk (i.e. "code digest"), like `20250114061047.1552475c743aac01`.
498502
* Use `loadDBDigest()` function exported by pg-mig Node library to extract the digest from the current databases used by the app (i.e. "database digest"). E.g. you can call it from your app's `/health` endpoint to allow querying the current database version digest from a deployment script or pipeline.
499503
500504
Every time the whole migration process succeeds, the digest is saved to _all database nodes_, so it can be later retrieved with `loadDBDigest()`. If you have multiple nodes managed by pg-mig, and they happen to appear out of sync, then this function will take care of choosing the most "sane" digest from those nodes, to let you compare it with the "code digest", with no single point of failure.

docs/README.md

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -268,12 +268,12 @@ UPDATE my_table SET some=:'var1';
268268

269269
### Use Environment Variables
270270

271-
If you assign e.g. `process.env.HOSTS = "{a,b,c}"` in your `pg-mig.config.ts` file, you can use that value in all of the version files using the standard `psql` feature:
271+
If you assign e.g. `process.env.VAR = "a,b,c"` (or return it) in your `pg-mig.config.ts` file, you can use that value in all of the version files using the standard `psql` feature:
272272

273273
```sql
274274
-- mig/20231017204837.initial.public.up.sql
275-
\set HOSTS `echo "$HOSTS"`
276-
SELECT my_function(:'HOSTS');
275+
\set HOSTS `echo "$VAR"`
276+
SELECT my_function(:'VAR');
277277
```
278278

279279
### More Meta-Commands
@@ -323,37 +323,41 @@ Here is the complete list of `-- $` pseudo comments that pg-mig supports in the
323323
* `$parallelism_per_host=N`: as mentioned above, this option forces the parallel migrations for schemas on the same host to wait for each other, not allowing to run more than N of then at the same time.
324324
* `$parallelism_global=N`: limits parallelism of this particular version _within the same schema prefix_ across all hosts.
325325
* `$delay=M`: introduces a delay (in ms) between each migration. You can use it with `$parallelism_global` to reduce load on the database even further.
326-
* `$run_alone=1`: if set to 1, no other migrations, _including other schema prefixes_, will run on any other host while this one is running. I.e. it introduces global ordering of the migration files application across schemas. This option is useful when you want to e.g. install a PostgreSQL extension used in other schemas, so you want all other schemas to wait until the installation finishes.
326+
* `$run_alone=1`: if set to 1, no other migrations, _including other schema prefixes_, will run on any other host while this one is running. I.e. it introduces a global ordering of the migration files application across schemas. This option is useful when you want to e.g. install a PostgreSQL extension used in other schemas, so you want all other schemas to wait until the installation finishes.
327327

328328
## Advanced: Use With pg-microsharding Library
329329

330330
Overall, there are many popular alternatives to pg-mig when it comes to managing a single database with no sharding. But when it comes to migrating the entire cluster with multiple nodes, or working with microsharding, pg-mig starts shining.
331331

332-
The recommended library to manage the microshards schemas is [pg-microsharding](https://www.npmjs.com/package/@clickup/pg-microsharding). To couple it with pg-mig, create the following files:
332+
The recommended library to manage the microshards schemas is [pg-microsharding](https://www.npmjs.com/package/@clickup/pg-microsharding). To couple it with pg-mig, create the following before/after scripts:
333333

334334
```sql
335-
-- mig/YYYYMMDDhhmmss.add_microsharding.public.up.sql
336-
CREATE SCHEMA microsharding;
335+
-- mig/before.sql
336+
CREATE SCHEMA IF NOT EXISTS microsharding;
337337
SET search_path TO microsharding;
338338
\ir ../pg-microsharding/sql/pg-microsharding-up.sql
339-
```
340-
341-
```sql
342-
-- mig/YYYYMMDDhhmmss.add_microsharding.public.dn.sql
343-
DROP SCHEMA microsharding;
344-
```
345-
346-
Also, define before/after scripts:
347-
348-
```sql
349-
-- mig/before.sql
350339
SELECT microsharding.microsharding_migration_before();
351340
```
352341

353342
```sql
354343
-- mig/after.sql
355344
\set HOSTS `echo "$HOSTS"`
356-
SELECT microsharding.microsharding_migration_after(:'HOSTS');
345+
SELECT microsharding.microsharding_migration_after(:'PGHOST');
346+
```
347+
348+
Make sure that you also define `PGHOST` environment variable as a comma-separated list of cluster hosts in your `pg-mig.config.ts` :
349+
350+
```typescript
351+
export default async function(action: "apply" | "undo" | string) {
352+
...
353+
return {
354+
PGHOST: islands
355+
.map((island) => island.nodes.map(({ host }) => host)
356+
.flat()
357+
.join(","),
358+
...
359+
};
360+
}
357361
```
358362

359363
### Microsharding Debug Views
@@ -498,7 +502,7 @@ To help with this check, pg-mig exposes the concept called "version digest". It'
498502

499503
Digest is a string, and by comparing 2 digests lexicographically, you may make a decision, which one is "better" (or, if you don't want "better/worse" comparison, you can also compare them for strict equality). If the database's digest is **greater or equal to** the application code's digest, then the code is compatible to the currently existing cluster schema, so the code can be deployed ("your database is ahead of the code").
500504

501-
* Run `pg-mig --list=digest` to print the digest of the current migration files on disk (i.e. "code digest"), like `20250114061047.1552475c743aac017bf0252d540eb033859c6e`.
505+
* Run `pg-mig --list=digest` to print the digest of the current migration files on disk (i.e. "code digest"), like `20250114061047.1552475c743aac01`.
502506
* Use `loadDBDigest()` function exported by pg-mig Node library to extract the digest from the current databases used by the app (i.e. "database digest"). E.g. you can call it from your app's `/health` endpoint to allow querying the current database version digest from a deployment script or pipeline.
503507

504508
Every time the whole migration process succeeds, the digest is saved to _all database nodes_, so it can be later retrieved with `loadDBDigest()`. If you have multiple nodes managed by pg-mig, and they happen to appear out of sync, then this function will take care of choosing the most "sane" digest from those nodes, to let you compare it with the "code digest", with no single point of failure.

docs/functions/cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
> **cli**(): `void`
1010
11-
Defined in: [src/cli.ts:441](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L441)
11+
Defined in: [src/cli.ts:445](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L445)
1212

1313
A wrapper around main() to call it from a bin script.
1414

docs/functions/loadDBDigest.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
> **loadDBDigest**\<`TDest`\>(`dests`, `sqlRunner`): `Promise`\<`string`\>
1010
11-
Defined in: [src/cli.ts:201](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L201)
11+
Defined in: [src/cli.ts:204](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L204)
1212

1313
Loads the digest strings from the provided databases and chooses the one
1414
which reflects the database schema status the best.

docs/functions/main.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
> **main**(`argsIn`): `Promise`\<`boolean`\>
1010
11-
Defined in: [src/cli.ts:84](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L84)
11+
Defined in: [src/cli.ts:86](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L86)
1212

1313
CLI tool entry point. This function is run when `pg-mig` is called from the
1414
command line. Accepts parameters from process.argv. See `migrate()` for

docs/functions/migrate.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
> **migrate**(`options`): `Promise`\<`boolean`\>
1010
11-
Defined in: [src/cli.ts:160](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L160)
11+
Defined in: [src/cli.ts:163](https://github.com/clickup/pg-mig/blob/master/src/cli.ts#L163)
1212

1313
Similar to main(), but accepts options explicitly, not from process.argv.
1414
This function is meant to be called from other tools.

docs/interfaces/MigrateOptions.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ Options for the migrate() function.
2323
| <a id="createdb"></a> `createDB?` | `boolean` | If true, tries to create the given database. This is helpful when running the tool on a developer's machine. |
2424
| <a id="parallelism"></a> `parallelism?` | `number` | How many schemas to process in parallel (defaults to 10). |
2525
| <a id="dry"></a> `dry?` | `boolean` | If true, prints what it plans to do, but doesn't change anything. |
26+
| <a id="force"></a> `force?` | `boolean` | If true, runs before/after files on apply even if nothing is changed. |
2627
| <a id="action"></a> `action` | \{ `type`: `"make"`; `name`: `string`; \} \| \{ `type`: `"list"`; \} \| \{ `type`: `"digest"`; \} \| \{ `type`: `"undo"`; `version`: `string`; \} \| \{ `type`: `"apply"`; `after`: () => `void` \| `Promise`\<`void`\>[]; \} | What to do. |

src/cli.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ export interface MigrateOptions {
5252
parallelism?: number;
5353
/** If true, prints what it plans to do, but doesn't change anything. */
5454
dry?: boolean;
55+
/** If true, runs before/after files on apply even if nothing is changed. */
56+
force?: boolean;
5557
/** What to do. */
5658
action:
5759
| { type: "make"; name: string }
@@ -98,7 +100,7 @@ export async function main(argsIn: string[]): Promise<boolean> {
98100
"list",
99101
"parallelism",
100102
],
101-
["dry", "createdb"],
103+
["dry", "createdb", "force"],
102104
);
103105

104106
const action: MigrateOptions["action"] =
@@ -149,6 +151,7 @@ export async function main(argsIn: string[]): Promise<boolean> {
149151
),
150152
parallelism: parseInt(args.get("parallelism", "0")) || undefined,
151153
dry: args.flag("dry"),
154+
force: args.flag("force"),
152155
action,
153156
});
154157
}
@@ -337,7 +340,8 @@ async function actionUndoOrApply(
337340

338341
if (
339342
chains.length === 0 &&
340-
(await Dest.checkRerunFingerprint(hostDests, beforeAfterFiles))
343+
(await Dest.checkRerunFingerprint(hostDests, beforeAfterFiles)) &&
344+
!options.force
341345
) {
342346
// If we have nothing to apply, save the digest in case it was not saved
343347
// previously, to keep the invariant.
@@ -356,10 +360,10 @@ async function actionUndoOrApply(
356360
printText(renderPatchSummary(chains, beforeAfterFiles));
357361
printSuccess("Dry-run mode.");
358362
return { success: true, hasMoreWork: false };
359-
} else {
360-
printText(renderPatchSummary(chains, beforeAfterFiles));
361363
}
362364

365+
printText(renderPatchSummary(chains, beforeAfterFiles));
366+
363367
// Remember that if we crash below (e.g. in after.sql), we'll need to run
364368
// before.sql+after.sql on retry even if there are no new migration versions
365369
await Dest.saveRerunFingerprint(hostDests, beforeAfterFiles, "reset");

0 commit comments

Comments
 (0)