pg-boss 12.30.0 → 12.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/README.md +5 -5
  2. package/dist/adapters/bun.d.ts +33 -0
  3. package/dist/adapters/bun.d.ts.map +1 -0
  4. package/dist/adapters/bun.js +86 -0
  5. package/dist/adapters/drizzle.d.ts.map +1 -1
  6. package/dist/adapters/drizzle.js +44 -7
  7. package/dist/adapters/index.d.ts +2 -0
  8. package/dist/adapters/index.d.ts.map +1 -1
  9. package/dist/adapters/index.js +1 -0
  10. package/dist/adapters/placeholders.d.ts +15 -0
  11. package/dist/adapters/placeholders.d.ts.map +1 -1
  12. package/dist/adapters/placeholders.js +28 -0
  13. package/dist/attorney.d.ts +2 -1
  14. package/dist/attorney.d.ts.map +1 -1
  15. package/dist/attorney.js +6 -1
  16. package/dist/cli.js +61 -15
  17. package/dist/contractor.d.ts +3 -7
  18. package/dist/contractor.d.ts.map +1 -1
  19. package/dist/contractor.js +35 -6
  20. package/dist/index.d.ts +15 -8
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +18 -5
  23. package/dist/manager.d.ts +3 -1
  24. package/dist/manager.d.ts.map +1 -1
  25. package/dist/manager.js +14 -3
  26. package/dist/migrationStore.d.ts +3 -2
  27. package/dist/migrationStore.d.ts.map +1 -1
  28. package/dist/migrationStore.js +77 -3
  29. package/dist/plans.d.ts +52 -1
  30. package/dist/plans.d.ts.map +1 -1
  31. package/dist/plans.js +163 -23
  32. package/dist/rrule.d.ts +85 -0
  33. package/dist/rrule.d.ts.map +1 -0
  34. package/dist/rrule.js +384 -0
  35. package/dist/schema.json +39 -3
  36. package/dist/timekeeper.d.ts +103 -2
  37. package/dist/timekeeper.d.ts.map +1 -1
  38. package/dist/timekeeper.js +499 -44
  39. package/dist/timezone.d.ts +18 -0
  40. package/dist/timezone.d.ts.map +1 -0
  41. package/dist/timezone.js +34 -0
  42. package/dist/types.d.ts +88 -1
  43. package/dist/types.d.ts.map +1 -1
  44. package/package.json +6 -3
package/README.md CHANGED
@@ -46,7 +46,7 @@ This will likely cater the most to teams already familiar with the simplicity of
46
46
  * Create jobs in an existing db transaction, including adapters for popular ORMs such as Drizzle, Knex, Kysely, Prisma
47
47
  * Backpressure-compatible polling workers, including support for LISTEN/NOTIFY low latency delivery
48
48
  * Job dependency workflow orchestration
49
- * Cron scheduling, job deferral
49
+ * Cron and RRULE scheduling, job deferral
50
50
  * Queue storage policies to support a variety of rate limiting, debouncing, and concurrency use cases
51
51
  * Priority queues, dead letter queues with redrive, automatic retries with exponential backoff
52
52
  * Pub/sub API for fan-out queue relationships
@@ -85,10 +85,10 @@ pg-boss is MIT licensed and always will be. It is maintained by one person, and
85
85
 
86
86
  <!-- sponsors:start The logos below are generated from GitHub Sponsors by scripts/sync-sponsors.js. Do not edit them directly. -->
87
87
  <div style="display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; margin: 1.5rem 0;">
88
- <a href="https://superpower.com/" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/114334709?s=200&amp;v=4" alt="Superpower" title="Superpower" width="96" height="96" style="border-radius: 8px;"></a>
89
- <a href="https://altruistiq.com/" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/88195975?s=200&amp;v=4" alt="Altruistiq" title="Altruistiq" width="64" height="64" style="border-radius: 8px;"></a>
90
- <a href="https://wasp.sh/" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/55102317?s=200&amp;v=4" alt="wasp-lang" title="wasp-lang" width="64" height="64" style="border-radius: 8px;"></a>
91
- <a href="https://github.com/Ferry-Health" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/158637456?s=200&amp;v=4" alt="Ferry Health" title="Ferry Health" width="64" height="64" style="border-radius: 8px;"></a>
88
+ <a href="https://superpower.com/" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/114334709?s=256&amp;v=4" alt="Superpower" title="Superpower" width="96" height="96" style="border-radius: 8px;"></a>
89
+ <a href="https://altruistiq.com/" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/88195975?s=256&amp;v=4" alt="Altruistiq" title="Altruistiq" width="64" height="64" style="border-radius: 8px;"></a>
90
+ <a href="https://wasp.sh/" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/55102317?s=256&amp;v=4" alt="wasp-lang" title="wasp-lang" width="64" height="64" style="border-radius: 8px;"></a>
91
+ <a href="https://github.com/Ferry-Health" target="_blank" rel="noopener"><img src="https://avatars.githubusercontent.com/u/158637456?s=256&amp;v=4" alt="Ferry Health" title="Ferry Health" width="64" height="64" style="border-radius: 8px;"></a>
92
92
  </div>
93
93
  <!-- sponsors:end -->
94
94
 
@@ -0,0 +1,33 @@
1
+ import type { IDatabase } from '../types.ts';
2
+ export interface BunSqlLike {
3
+ unsafe(text: string, values?: unknown[]): Promise<unknown>;
4
+ reserve(): Promise<BunReservedSqlLike>;
5
+ listen?(channel: string, onNotification: (payload: string) => void, onSubscribe?: () => void): Promise<BunSubscriptionLike>;
6
+ }
7
+ export interface BunSubscriptionLike {
8
+ unlisten(): Promise<void> | void;
9
+ }
10
+ export interface BunReservedSqlLike {
11
+ unsafe(text: string, values?: unknown[]): Promise<unknown>;
12
+ release(): void;
13
+ }
14
+ /**
15
+ * Adapts a `Bun.SQL` client to pg-boss's IDatabase, for running pg-boss on Bun's built-in
16
+ * PostgreSQL driver instead of the bundled `pg` pool.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { SQL } from 'bun'
21
+ * import { PgBoss, fromBunSql } from 'pg-boss'
22
+ *
23
+ * const boss = new PgBoss({ db: fromBunSql(new SQL(connectionString)) })
24
+ * await boss.start()
25
+ * ```
26
+ *
27
+ * The caller owns the client's lifecycle: pg-boss never calls `end()` on it.
28
+ *
29
+ * `useListenNotify` needs `sql.listen()`, which Bun added in 1.4.0. On an older runtime the adapter
30
+ * exposes no `listen` and pg-boss falls back to polling.
31
+ */
32
+ export declare function fromBunSql(client: BunSqlLike): IDatabase;
33
+ //# sourceMappingURL=bun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/adapters/bun.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAM5C,MAAM,WAAW,UAAU;IACzB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,OAAO,IAAI,OAAO,CAAC,kBAAkB,CAAC,CAAA;IAEtC,MAAM,CAAC,CACL,OAAO,EAAE,MAAM,EACf,cAAc,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,EACzC,WAAW,CAAC,EAAE,MAAM,IAAI,GACvB,OAAO,CAAC,mBAAmB,CAAC,CAAA;CAChC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACjC;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC1D,OAAO,IAAI,IAAI,CAAA;CAChB;AAeD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,UAAU,CAAE,MAAM,EAAE,UAAU,GAAG,SAAS,CAiCzD"}
@@ -0,0 +1,86 @@
1
+ import { expandArrayParams } from "./placeholders.js";
2
+ // pg-boss ships schema installation, migration and maintenance as `BEGIN; ... COMMIT;` scripts
3
+ // (plans.transaction / plans.locked). Bun rejects those on a pooled connection with `Only use
4
+ // sql.begin, sql.reserved or max: 1`, because the pool is free to hand the next statement to a
5
+ // different connection. A reserved connection is pinned for its lifetime and takes them as-is.
6
+ const STARTS_TRANSACTION = /^\s*BEGIN\b/i;
7
+ // Bun reports every server error as ERR_POSTGRES_SERVER_ERROR and puts the SQLSTATE in `errno`,
8
+ // where node-postgres puts it in `code`. pg-boss reads `code` to recognise a handful of states it
9
+ // treats as control flow rather than failure - 23505 from a lost fetch race, 22012 from the
10
+ // in-SQL insert guard, 25001 from REINDEX inside a transaction - so an unmapped error turns a
11
+ // tolerated race into a thrown one.
12
+ const BUN_SERVER_ERROR = 'ERR_POSTGRES_SERVER_ERROR';
13
+ /**
14
+ * Adapts a `Bun.SQL` client to pg-boss's IDatabase, for running pg-boss on Bun's built-in
15
+ * PostgreSQL driver instead of the bundled `pg` pool.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * import { SQL } from 'bun'
20
+ * import { PgBoss, fromBunSql } from 'pg-boss'
21
+ *
22
+ * const boss = new PgBoss({ db: fromBunSql(new SQL(connectionString)) })
23
+ * await boss.start()
24
+ * ```
25
+ *
26
+ * The caller owns the client's lifecycle: pg-boss never calls `end()` on it.
27
+ *
28
+ * `useListenNotify` needs `sql.listen()`, which Bun added in 1.4.0. On an older runtime the adapter
29
+ * exposes no `listen` and pg-boss falls back to polling.
30
+ */
31
+ export function fromBunSql(client) {
32
+ const db = {
33
+ async executeSql(text, values) {
34
+ const query = expandArrayParams(text, values);
35
+ // A parameterless call goes through the simple protocol, which is what lets a multi-statement
36
+ // script run at all; pg-boss only ever concatenates statements when there is nothing to bind.
37
+ const run = (target) => query.values.length
38
+ ? target.unsafe(query.text, query.values)
39
+ : target.unsafe(query.text);
40
+ try {
41
+ return unwrapBunResult(await (STARTS_TRANSACTION.test(text) ? runReserved(client, run) : run(client)));
42
+ }
43
+ catch (err) {
44
+ throw withSqlState(err);
45
+ }
46
+ }
47
+ };
48
+ // Bun's third argument fires on the initial subscribe and again after each reconnect - it
49
+ // re-establishes the connection and re-subscribes every channel on its own - which is exactly
50
+ // what pg-boss's onReconnect is for: a notification sent while the listener was down is gone,
51
+ // so the gap has to be closed by a fetch. Only expose `listen` when the client actually has it
52
+ // (Bun < 1.4.0, or a mock), so the notifier cleanly falls back to polling otherwise.
53
+ if (typeof client.listen === 'function') {
54
+ db.listen = async (channel, onNotification, onReconnect) => {
55
+ const subscription = await client.listen(channel, onNotification, onReconnect);
56
+ return { close: async () => { await subscription.unlisten(); } };
57
+ };
58
+ }
59
+ return db;
60
+ }
61
+ async function runReserved(client, run) {
62
+ const reserved = await client.reserve();
63
+ try {
64
+ return await run(reserved);
65
+ }
66
+ finally {
67
+ reserved.release();
68
+ }
69
+ }
70
+ // Bun returns the rows of a single statement as a flat array, and one such array per statement for
71
+ // a multi-statement script. Flatten the latter so a RETURNING in the middle of a transaction block
72
+ // is not lost behind the trailing COMMIT's empty result - the same unwrapping the PGlite adapter
73
+ // does for exec() and pg-boss does for node-postgres (see unwrapSQLResult).
74
+ function unwrapBunResult(result) {
75
+ if (!Array.isArray(result)) {
76
+ return { rows: [] };
77
+ }
78
+ return { rows: result.some(Array.isArray) ? result.flat() : result };
79
+ }
80
+ function withSqlState(err) {
81
+ const error = err;
82
+ if (error?.code === BUN_SERVER_ERROR && error.errno) {
83
+ error.code = error.errno;
84
+ }
85
+ return err;
86
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../src/adapters/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAI5C,MAAM,WAAW,sBAAsB;IAGrC,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAA;CAC9E;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAC9D,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAE,EAAE,EAAE,sBAAsB,EAAE,GAAG,EAAE,iBAAiB,GAAG,SAAS,CAa1F"}
1
+ {"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../src/adapters/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAI5C,MAAM,WAAW,sBAAsB;IAGrC,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE,GAAG;QAAE,IAAI,EAAE,GAAG,EAAE,CAAA;KAAE,EAAE,GAAG,GAAG,EAAE,CAAC,CAAA;CAC9E;AAED,MAAM,WAAW,iBAAiB;IAChC,CAAC,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAA;IAC9D,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAA;CAC/B;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAE,EAAE,EAAE,sBAAsB,EAAE,GAAG,EAAE,iBAAiB,GAAG,SAAS,CAQ1F"}
@@ -1,4 +1,4 @@
1
- import { parsePlaceholders } from "./placeholders.js";
1
+ import { ARRAY_CAST, parsePlaceholders } from "./placeholders.js";
2
2
  import { unwrapSQLResult } from "../tools.js";
3
3
  /**
4
4
  * Wraps a drizzle-orm transaction as an {@link IDatabase}.
@@ -21,13 +21,50 @@ export function fromDrizzle(tx, sql) {
21
21
  return {
22
22
  async executeSql(text, values) {
23
23
  const { parts, reordered } = parsePlaceholders(text, values);
24
- const strings = Object.assign([...parts], { raw: [...parts] });
25
- // Bind each value through sql.param so drizzle emits exactly one placeholder
26
- // per value. A bare array would otherwise be expanded into a parameter list
27
- // ($2, $3, ...) instead of a single array-typed parameter, breaking any query
28
- // with `= ANY($N::uuid[])` (deleteJob/complete/fail/cancel/resume/retry).
29
- const params = reordered.map(value => sql.param(value));
24
+ const { strings, params } = buildQuery(parts, reordered, sql);
30
25
  return unwrapSQLResult(await tx.execute(sql(strings, ...params)));
31
26
  }
32
27
  };
33
28
  }
29
+ // A parameter cast to an array type (`$N::uuid[]`) is expanded into an inline
30
+ // ARRAY[...] constructor of scalar parameters rather than bound whole.
31
+ //
32
+ // Binding the array whole (sql.param([a, b])) is what postgres wants, and it is
33
+ // what node-postgres and postgres-js do, but Bun's SQL client cannot encode a JS
34
+ // array: it stringifies it to `a,b`, and every `= ANY($N::uuid[])` in pg-boss then
35
+ // fails with `malformed array literal` (oven-sh/bun#18775). Letting drizzle expand
36
+ // the array on its own is no better - it emits a bare `$2, $3` list, which is not
37
+ // valid where the statement expects one array expression.
38
+ //
39
+ // ARRAY[$2, $3] is valid everywhere a single array parameter was, keeps every
40
+ // element a real bind parameter (so no value is ever escaped into SQL text), and
41
+ // carries no driver-specific knowledge.
42
+ //
43
+ // The array cast is what makes the rewrite safe to apply, so it is required rather
44
+ // than assumed (see ARRAY_CAST).
45
+ function buildQuery(parts, values, sql) {
46
+ const literals = [];
47
+ const params = [];
48
+ let pending = parts[0];
49
+ for (let i = 0; i < values.length; i++) {
50
+ const value = values[i];
51
+ if (Array.isArray(value) && ARRAY_CAST.test(parts[i + 1])) {
52
+ // ARRAY[] alone has no element type; the cast that qualified this parameter
53
+ // for the rewrite is what resolves it.
54
+ pending += 'ARRAY[';
55
+ for (let element = 0; element < value.length; element++) {
56
+ literals.push(pending);
57
+ params.push(sql.param(value[element]));
58
+ pending = element === value.length - 1 ? '' : ',';
59
+ }
60
+ pending += ']' + parts[i + 1];
61
+ continue;
62
+ }
63
+ literals.push(pending);
64
+ params.push(sql.param(value));
65
+ pending = parts[i + 1];
66
+ }
67
+ literals.push(pending);
68
+ const strings = Object.assign(literals, { raw: [...literals] });
69
+ return { strings, params };
70
+ }
@@ -3,9 +3,11 @@ export { fromKysely } from './kysely.ts';
3
3
  export { fromDrizzle } from './drizzle.ts';
4
4
  export { fromPrisma } from './prisma.ts';
5
5
  export { fromPglite } from './pglite.ts';
6
+ export { fromBunSql } from './bun.ts';
6
7
  export type { KnexTransactionLike } from './knex.ts';
7
8
  export type { KyselyTransactionLike } from './kysely.ts';
8
9
  export type { DrizzleTransactionLike, DrizzleSqlTagLike } from './drizzle.ts';
9
10
  export type { PrismaTransactionLike } from './prisma.ts';
10
11
  export type { PGliteLike } from './pglite.ts';
12
+ export type { BunSqlLike, BunReservedSqlLike } from './bun.ts';
11
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAExC,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/adapters/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AAErC,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AACpD,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,YAAY,EAAE,sBAAsB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAA;AAC7E,YAAY,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAA;AACxD,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAA;AAC7C,YAAY,EAAE,UAAU,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA"}
@@ -3,3 +3,4 @@ export { fromKysely } from "./kysely.js";
3
3
  export { fromDrizzle } from "./drizzle.js";
4
4
  export { fromPrisma } from "./prisma.js";
5
5
  export { fromPglite } from "./pglite.js";
6
+ export { fromBunSql } from "./bun.js";
@@ -11,4 +11,19 @@ export declare function parsePlaceholders(text: string, values?: readonly unknow
11
11
  parts: string[];
12
12
  reordered: unknown[];
13
13
  };
14
+ export declare const ARRAY_CAST: RegExp;
15
+ /**
16
+ * Rewrites `$N` placeholders into a fresh sequential list, expanding any array-cast parameter
17
+ * into an inline `ARRAY[...]` constructor of scalar parameters.
18
+ *
19
+ * Postgres wants an array bound whole, and node-postgres, postgres-js and PGlite all encode one.
20
+ * Bun's SQL client cannot: it stringifies the array, so `= ANY($N::uuid[])` reaches the server as
21
+ * `a,b` and fails with `malformed array literal` (oven-sh/bun#18775). `ARRAY[$2,$3]` is valid
22
+ * everywhere a single array parameter was, and every element stays a bind parameter, so no value
23
+ * is ever escaped into SQL text.
24
+ */
25
+ export declare function expandArrayParams(text: string, values?: readonly unknown[]): {
26
+ text: string;
27
+ values: unknown[];
28
+ };
14
29
  //# sourceMappingURL=placeholders.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"placeholders.d.ts","sourceRoot":"","sources":["../../src/adapters/placeholders.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG;IAC7E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,OAAO,EAAE,CAAA;CACrB,CAcA"}
1
+ {"version":3,"file":"placeholders.d.ts","sourceRoot":"","sources":["../../src/adapters/placeholders.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG;IAC7E,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,SAAS,EAAE,OAAO,EAAE,CAAA;CACrB,CAcA;AAMD,eAAO,MAAM,UAAU,QAA6B,CAAA;AAEpD;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,GAAG;IAC7E,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,OAAO,EAAE,CAAA;CAClB,CAgBA"}
@@ -22,3 +22,31 @@ export function parsePlaceholders(text, values) {
22
22
  parts.push(text.slice(lastIndex));
23
23
  return { parts, reordered };
24
24
  }
25
+ // A parameter cast to an array type, as in `$2::uuid[]`. pg-boss binds job ids and queue names
26
+ // this way, and the cast is what tells an adapter the value is a postgres array rather than a
27
+ // JSON one - a JS array bound to a json column is a JSON array, and rewriting that would change
28
+ // what gets stored.
29
+ export const ARRAY_CAST = /^::[a-z_][a-z0-9_]*\[\]/i;
30
+ /**
31
+ * Rewrites `$N` placeholders into a fresh sequential list, expanding any array-cast parameter
32
+ * into an inline `ARRAY[...]` constructor of scalar parameters.
33
+ *
34
+ * Postgres wants an array bound whole, and node-postgres, postgres-js and PGlite all encode one.
35
+ * Bun's SQL client cannot: it stringifies the array, so `= ANY($N::uuid[])` reaches the server as
36
+ * `a,b` and fails with `malformed array literal` (oven-sh/bun#18775). `ARRAY[$2,$3]` is valid
37
+ * everywhere a single array parameter was, and every element stays a bind parameter, so no value
38
+ * is ever escaped into SQL text.
39
+ */
40
+ export function expandArrayParams(text, values) {
41
+ const { parts, reordered } = parsePlaceholders(text, values);
42
+ const expanded = [];
43
+ let rewritten = parts[0];
44
+ for (let i = 0; i < reordered.length; i++) {
45
+ const value = reordered[i];
46
+ rewritten += Array.isArray(value) && ARRAY_CAST.test(parts[i + 1])
47
+ ? `ARRAY[${value.map(element => `$${expanded.push(element)}`).join(',')}]`
48
+ : `$${expanded.push(value)}`;
49
+ rewritten += parts[i + 1];
50
+ }
51
+ return { text: rewritten, values: expanded };
52
+ }
@@ -4,6 +4,7 @@ declare const POLICY: {
4
4
  MIN_POLLING_INTERVAL_MS: number;
5
5
  MAX_RETENTION_DAYS: number;
6
6
  };
7
+ declare const COMPATIBILITY_FLAGS: readonly ["noSkipLocked", "noMultiMutationCte", "noTablePartitioning", "noDeferrableConstraints", "noAdvisoryLocks", "noCoveringIndexes", "noAddColumnBackfill", "noListenNotify", "noIndexProgressView", "noReindex", "noMonitorVacuum"];
7
8
  declare function validateQueueArgs(config?: any): void;
8
9
  declare function pinZonelessDateTime(value: string): string;
9
10
  declare function checkSendArgs(args: any): types.Request;
@@ -21,5 +22,5 @@ declare function getConfig(value: string | types.ConstructorOptions): types.Reso
21
22
  declare function assertPostgresObjectName(name: string): void;
22
23
  declare function assertQueueName(name: string): void;
23
24
  declare function assertKey(key: string): void;
24
- export { assertKey, assertPostgresObjectName, assertQueueName, checkFetchArgs, checkSendArgs, checkUpdateArgs, checkWorkArgs, getConfig, pinZonelessDateTime, POLICY, validateFlowJobs, validateGroupConfig, validateQueueArgs };
25
+ export { assertKey, COMPATIBILITY_FLAGS, assertPostgresObjectName, assertQueueName, checkFetchArgs, checkSendArgs, checkUpdateArgs, checkWorkArgs, getConfig, pinZonelessDateTime, POLICY, validateFlowJobs, validateGroupConfig, validateQueueArgs };
25
26
  //# sourceMappingURL=attorney.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"attorney.d.ts","sourceRoot":"","sources":["../src/attorney.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC,QAAA,MAAM,MAAM;;;;CAIX,CAAA;AAkFD,iBAAS,iBAAiB,CAAE,MAAM,GAAE,GAAQ,QAc3C;AAgBD,iBAAS,mBAAmB,CAAE,KAAK,EAAE,MAAM,UAE1C;AAED,iBAAS,aAAa,CAAE,IAAI,EAAE,GAAG,GAAG,KAAK,CAAC,OAAO,CAgDhD;AAOD,iBAAS,eAAe,CAAE,IAAI,EAAE,GAAG,EAAE,EAAE,MAAc,EAAE;;CAAK,GAAG,KAAK,CAAC,OAAO,CA4D3E;AAED,iBAAS,mBAAmB,CAAE,MAAM,EAAE,GAAG,QAOxC;AAED,iBAAS,gBAAgB,CAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,QA2D/C;AA2GD,iBAAS,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IAClD,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAA;IAClC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;CACjC,CA8BA;AAED,iBAAS,cAAc,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAQlD;AAED,iBAAS,SAAS,CAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,0BAA0B,CAyB9F;AA4FD,iBAAS,wBAAwB,CAAE,IAAI,EAAE,MAAM,QAiC9C;AAED,iBAAS,eAAe,CAAE,IAAI,EAAE,MAAM,QAIrC;AAED,iBAAS,SAAS,CAAE,GAAG,EAAE,MAAM,QAI9B;AA+LD,OAAO,EACL,SAAS,EACT,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,mBAAmB,EACnB,MAAM,EACN,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EAClB,CAAA"}
1
+ {"version":3,"file":"attorney.d.ts","sourceRoot":"","sources":["../src/attorney.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC,QAAA,MAAM,MAAM;;;;CAIX,CAAA;AAKD,QAAA,MAAM,mBAAmB,2OAYf,CAAA;AAsEV,iBAAS,iBAAiB,CAAE,MAAM,GAAE,GAAQ,QAc3C;AAgBD,iBAAS,mBAAmB,CAAE,KAAK,EAAE,MAAM,UAE1C;AAED,iBAAS,aAAa,CAAE,IAAI,EAAE,GAAG,GAAG,KAAK,CAAC,OAAO,CAgDhD;AAOD,iBAAS,eAAe,CAAE,IAAI,EAAE,GAAG,EAAE,EAAE,MAAc,EAAE;;CAAK,GAAG,KAAK,CAAC,OAAO,CA4D3E;AAED,iBAAS,mBAAmB,CAAE,MAAM,EAAE,GAAG,QAOxC;AAED,iBAAS,gBAAgB,CAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,QA2D/C;AA2GD,iBAAS,aAAa,CAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG;IAClD,OAAO,EAAE,KAAK,CAAC,mBAAmB,CAAA;IAClC,QAAQ,EAAE,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;CACjC,CA8BA;AAED,iBAAS,cAAc,CAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAQlD;AAED,iBAAS,SAAS,CAAE,KAAK,EAAE,MAAM,GAAG,KAAK,CAAC,kBAAkB,GAAG,KAAK,CAAC,0BAA0B,CAyB9F;AA4FD,iBAAS,wBAAwB,CAAE,IAAI,EAAE,MAAM,QAiC9C;AAED,iBAAS,eAAe,CAAE,IAAI,EAAE,MAAM,QAIrC;AAED,iBAAS,SAAS,CAAE,GAAG,EAAE,MAAM,QAI9B;AA+LD,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,aAAa,EACb,eAAe,EACf,aAAa,EACb,SAAS,EACT,mBAAmB,EACnB,MAAM,EACN,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EAClB,CAAA"}
package/dist/attorney.js CHANGED
@@ -15,6 +15,7 @@ const COMPATIBILITY_FLAGS = [
15
15
  'noDeferrableConstraints',
16
16
  'noAdvisoryLocks',
17
17
  'noCoveringIndexes',
18
+ 'noAddColumnBackfill',
18
19
  'noListenNotify',
19
20
  'noIndexProgressView',
20
21
  'noReindex',
@@ -32,6 +33,10 @@ const BACKEND_PROFILES = {
32
33
  noDeferrableConstraints: true,
33
34
  noAdvisoryLocks: true,
34
35
  noCoveringIndexes: true,
36
+ // ADD COLUMN runs as a schema-change job, so a transaction cannot write the column it just
37
+ // added: the UPDATE fails with "column is being backfilled". A migration that seeds a new
38
+ // column leaves the seeding statement out here.
39
+ noAddColumnBackfill: true,
35
40
  noListenNotify: true,
36
41
  // Online DDL runs as a schema-change job, not the PG CONCURRENTLY path, and
37
42
  // pg_stat_progress_create_index isn't available — so BAM can't use liveness-based reclaim.
@@ -617,4 +622,4 @@ function applyFlowConfig(config) {
617
622
  assert(!('flowIntervalSeconds' in config) || config.flowIntervalSeconds >= minInterval, `configuration assert: flowIntervalSeconds must be at least ${minInterval} seconds`);
618
623
  config.flowIntervalSeconds = config.flowIntervalSeconds || 5;
619
624
  }
620
- export { assertKey, assertPostgresObjectName, assertQueueName, checkFetchArgs, checkSendArgs, checkUpdateArgs, checkWorkArgs, getConfig, pinZonelessDateTime, POLICY, validateFlowJobs, validateGroupConfig, validateQueueArgs };
625
+ export { assertKey, COMPATIBILITY_FLAGS, assertPostgresObjectName, assertQueueName, checkFetchArgs, checkSendArgs, checkUpdateArgs, checkWorkArgs, getConfig, pinZonelessDateTime, POLICY, validateFlowJobs, validateGroupConfig, validateQueueArgs };
package/dist/cli.js CHANGED
@@ -6,6 +6,7 @@ import Db from "./db.js";
6
6
  import * as plans from "./plans.js";
7
7
  import Contractor from "./contractor.js";
8
8
  import * as migrationStore from "./migrationStore.js";
9
+ import * as attorney from "./attorney.js";
9
10
  import packageJson from '../package.json' with { type: 'json' };
10
11
  const schemaVersion = packageJson.pgboss.schema;
11
12
  function printHelp() {
@@ -34,6 +35,8 @@ Options:
34
35
  --password, -p <pass> Database password
35
36
  --connection-string Full connection string (overrides other connection options)
36
37
  --ssl Enable SSL connection
38
+ --backend <profile> Database backend: postgres (default), cockroachdb, yugabytedb, citus.
39
+ Non-postgres backends need this to emit schema they accept.
37
40
  --dry-run Output SQL without executing (for plans and reindex commands)
38
41
  --force Rebuild every job index, not just the bloated ones (reindex)
39
42
 
@@ -45,6 +48,7 @@ Environment Variables:
45
48
  PGBOSS_USER Database user
46
49
  PGBOSS_PASSWORD Database password
47
50
  PGBOSS_SCHEMA Schema name (default: pgboss)
51
+ PGBOSS_BACKEND Database backend profile (default: postgres)
48
52
 
49
53
  Config File (pgboss.json):
50
54
  {
@@ -54,7 +58,8 @@ Config File (pgboss.json):
54
58
  "user": "postgres",
55
59
  "password": "secret",
56
60
  "schema": "pgboss",
57
- "ssl": false
61
+ "ssl": false,
62
+ "backend": "postgres"
58
63
  }
59
64
 
60
65
  Examples:
@@ -62,6 +67,7 @@ Examples:
62
67
  pg-boss migrate --schema my_schema
63
68
  pg-boss create --connection-string postgres://user:pass@localhost/db
64
69
  pg-boss plans migrate --dry-run
70
+ pg-boss migrate --backend cockroachdb --connection-string postgres://root@localhost:26257/db
65
71
  pg-boss version
66
72
  PGBOSS_DATABASE_URL=postgres://localhost/mydb pg-boss migrate
67
73
  `);
@@ -90,6 +96,13 @@ function loadConfigFile(configPath) {
90
96
  }
91
97
  return {};
92
98
  }
99
+ // Resolves the connection AND the backend compatibility flags, because every command that writes
100
+ // schema needs both. Without the flags a CockroachDB target is handed stock-PostgreSQL DDL - table
101
+ // partitioning, advisory locks, covering indexes, a backfill of a column added in the same
102
+ // transaction - and the command fails partway through a migration rather than up front. The flags
103
+ // are derived from --backend / PGBOSS_BACKEND / the config file by the same attorney.getConfig() the
104
+ // library constructor uses, so the CLI and a running boss cannot disagree about what a backend
105
+ // supports.
93
106
  function getConnectionConfig(args) {
94
107
  const fileConfig = loadConfigFile(args.config);
95
108
  const config = {
@@ -110,7 +123,28 @@ function getConnectionConfig(args) {
110
123
  console.error('Run "pg-boss --help" for more information.');
111
124
  process.exit(1);
112
125
  }
113
- return config;
126
+ return resolveBackendConfig(config, args, fileConfig);
127
+ }
128
+ // Runs a config through the library's own resolver so the compatibility flags come from one place.
129
+ // Split out of getConnectionConfig because `plans` has to answer offline, where there is a backend
130
+ // to honour but no connection to read.
131
+ function resolveBackendConfig(config, args, fileConfig) {
132
+ const backend = args.backend || process.env.PGBOSS_BACKEND || fileConfig.backend;
133
+ if (backend) {
134
+ // pglite is in-process and has no connection string, so it can only be driven from library code.
135
+ if (backend === 'pglite') {
136
+ console.error('Error: the pglite backend is in-process and cannot be used from the CLI.');
137
+ process.exit(1);
138
+ }
139
+ config.backend = backend;
140
+ }
141
+ try {
142
+ return attorney.getConfig(config);
143
+ }
144
+ catch (err) {
145
+ console.error(`Error: ${err.message}`);
146
+ process.exit(1);
147
+ }
114
148
  }
115
149
  function parseCliArgs() {
116
150
  const { values, positionals } = parseArgs({
@@ -125,6 +159,7 @@ function parseCliArgs() {
125
159
  password: { type: 'string', short: 'p' },
126
160
  'connection-string': { type: 'string' },
127
161
  ssl: { type: 'boolean' },
162
+ backend: { type: 'string' },
128
163
  'dry-run': { type: 'boolean' },
129
164
  force: { type: 'boolean' }
130
165
  },
@@ -141,6 +176,7 @@ function parseCliArgs() {
141
176
  password: values.password,
142
177
  connectionString: values['connection-string'],
143
178
  ssl: values.ssl,
179
+ backend: values.backend,
144
180
  dryRun: values['dry-run'],
145
181
  force: values.force,
146
182
  command: positionals[0],
@@ -214,7 +250,7 @@ async function cmdCreate(args) {
214
250
  const config = getConnectionConfig(args);
215
251
  const schema = config.schema || plans.DEFAULT_SCHEMA;
216
252
  if (args.dryRun) {
217
- const sql = plans.create(schema, schemaVersion, { createSchema: true });
253
+ const sql = plans.create(schema, schemaVersion, { ...config, createSchema: true });
218
254
  console.log('-- SQL to create pg-boss schema:');
219
255
  console.log(sql);
220
256
  return;
@@ -227,7 +263,7 @@ async function cmdCreate(args) {
227
263
  return;
228
264
  }
229
265
  console.log(`Creating pg-boss schema "${schema}"...`);
230
- const sql = plans.create(schema, schemaVersion, { createSchema: true });
266
+ const sql = plans.create(schema, schemaVersion, { ...config, createSchema: true });
231
267
  await db.executeSql(sql);
232
268
  console.log(`Successfully created pg-boss schema "${schema}" at version ${schemaVersion}`);
233
269
  }
@@ -265,7 +301,7 @@ async function cmdMigrate(args) {
265
301
  // Offline (or not yet installed) we can't know it, so fall back to the oldest supported starting
266
302
  // version — the full chain — instead of a bogus "from 0" that fails on non-idempotent steps.
267
303
  const fromVersion = version ?? migrationStore.getMinVersion(schema);
268
- const sql = migrationStore.migrate(schema, fromVersion, undefined, undefined, { inlineAsync: true, partitionTables });
304
+ const sql = migrationStore.migrate(schema, fromVersion, migrationStore.getAllForConfig(config), config.noAdvisoryLocks, { inlineAsync: true, partitionTables });
269
305
  console.log(`-- SQL to migrate pg-boss from version ${fromVersion} to ${schemaVersion}:`);
270
306
  console.log(sql);
271
307
  return;
@@ -275,7 +311,7 @@ async function cmdMigrate(args) {
275
311
  const version = await getSchemaVersion(db, schema);
276
312
  if (version === null) {
277
313
  console.log(`pg-boss is not installed. Creating schema "${schema}"...`);
278
- const sql = plans.create(schema, schemaVersion, { createSchema: true });
314
+ const sql = plans.create(schema, schemaVersion, { ...config, createSchema: true });
279
315
  await db.executeSql(sql);
280
316
  console.log(`Successfully created pg-boss schema "${schema}" at version ${schemaVersion}`);
281
317
  return;
@@ -288,7 +324,7 @@ async function cmdMigrate(args) {
288
324
  // Inline the async index builds rather than enqueuing BAM rows that nothing will run
289
325
  // (the CLI exits without a worker); enumerate partitions so they are covered too.
290
326
  const partitionTables = await getPartitionTables(db, schema);
291
- const { sql, concurrent } = migrationStore.migrateCommands(schema, version, undefined, undefined, { inlineAsync: true, partitionTables });
327
+ const { sql, concurrent } = migrationStore.migrateCommands(schema, version, migrationStore.getAllForConfig(config), config.noAdvisoryLocks, { inlineAsync: true, partitionTables });
292
328
  await db.executeSql(sql);
293
329
  // CONCURRENTLY index builds must run outside the migration transaction, one at a time.
294
330
  for (const statement of concurrent) {
@@ -315,13 +351,13 @@ async function cmdRollback(args) {
315
351
  return;
316
352
  }
317
353
  if (args.dryRun) {
318
- const sql = migrationStore.rollback(schema, version);
354
+ const sql = migrationStore.rollback(schema, version, migrationStore.getAllForConfig(config), config.noAdvisoryLocks);
319
355
  console.log(`-- SQL to rollback pg-boss from version ${version} to ${version - 1}:`);
320
356
  console.log(sql);
321
357
  return;
322
358
  }
323
359
  console.log(`Rolling back pg-boss schema "${schema}" from version ${version} to ${version - 1}...`);
324
- const sql = migrationStore.rollback(schema, version);
360
+ const sql = migrationStore.rollback(schema, version, migrationStore.getAllForConfig(config), config.noAdvisoryLocks);
325
361
  await db.executeSql(sql);
326
362
  console.log(`Successfully rolled back pg-boss schema "${schema}" to version ${version - 1}`);
327
363
  }
@@ -489,6 +525,14 @@ async function cmdReindex(args) {
489
525
  process.exitCode = 1;
490
526
  return;
491
527
  }
528
+ // A declared backend answers this without a round trip: REINDEX is rejected outright on
529
+ // CockroachDB and unimplemented on YugabyteDB, and neither can measure bloat in the first place.
530
+ if (config.noReindex) {
531
+ console.error(`Reindexing is not supported on the ${config.backend} backend.`);
532
+ console.error('Index maintenance there is handled by the storage engine, and the bloat check cannot run: pg_class.relpages and pg_relation_size() are unavailable or always zero.');
533
+ process.exitCode = 1;
534
+ return;
535
+ }
492
536
  const sql = args.force ? plans.getJobIndexes(schema) : plans.getBloatedIndexes(schema);
493
537
  let rows;
494
538
  try {
@@ -497,9 +541,8 @@ async function cmdReindex(args) {
497
541
  catch (err) {
498
542
  // The check reads pg_class.relpages and pg_relation_size(). CockroachDB has neither (it
499
543
  // rejects `reltuples / relpages` as an unsupported binary operator) and YugabyteDB reports
500
- // zeroes for every relation. The CLI takes a connection string, not a backend profile, so
501
- // there is nothing to gate on ahead of time — say what happened instead of surfacing a raw
502
- // catalog error.
544
+ // zeroes for every relation. --backend catches those up front (above); this stays for a target
545
+ // that was not declared — say what happened instead of surfacing a raw catalog error.
503
546
  console.error(`Could not read index statistics from schema "${schema}": ${err.message}`);
504
547
  console.error('The bloat check reads pg_class.relpages and pg_relation_size(), which CockroachDB and YugabyteDB do not provide.');
505
548
  process.exitCode = 1;
@@ -569,11 +612,14 @@ async function cmdPlans(args) {
569
612
  const fileConfig = loadConfigFile(args.config);
570
613
  const schema = args.schema || process.env.PGBOSS_SCHEMA || fileConfig.schema || plans.DEFAULT_SCHEMA;
571
614
  const subCommand = args.subCommand || 'migrate';
615
+ // A connection is optional here, but the backend is not: printed SQL is meant to be run, so it has
616
+ // to be the SQL that backend accepts.
617
+ const config = resolveBackendConfig({ schema }, args, fileConfig);
572
618
  switch (subCommand) {
573
619
  case 'create':
574
620
  case 'construct':
575
621
  console.log('-- SQL to create pg-boss schema:');
576
- console.log(plans.create(schema, schemaVersion, { createSchema: true }));
622
+ console.log(plans.create(schema, schemaVersion, { ...config, createSchema: true }));
577
623
  break;
578
624
  case 'migrate': {
579
625
  // Inline the async index builds (no BAM worker runs an exported script). A connection
@@ -600,12 +646,12 @@ async function cmdPlans(args) {
600
646
  console.log('-- note: no database connection provided; partitioned queue tables were not enumerated.');
601
647
  console.log('-- Run with a connection (e.g. --connection-string) to include per-partition index builds.');
602
648
  }
603
- console.log(migrationStore.migrate(schema, 0, undefined, undefined, { inlineAsync: true, partitionTables }));
649
+ console.log(migrationStore.migrate(schema, 0, migrationStore.getAllForConfig(config), config.noAdvisoryLocks, { inlineAsync: true, partitionTables }));
604
650
  break;
605
651
  }
606
652
  case 'rollback':
607
653
  console.log(`-- SQL to rollback pg-boss from version ${schemaVersion} to ${schemaVersion - 1}:`);
608
- console.log(migrationStore.rollback(schema, schemaVersion));
654
+ console.log(migrationStore.rollback(schema, schemaVersion, migrationStore.getAllForConfig(config), config.noAdvisoryLocks));
609
655
  break;
610
656
  default:
611
657
  console.error(`Unknown plans subcommand: ${subCommand}`);
@@ -1,12 +1,8 @@
1
1
  import type * as types from './types.ts';
2
2
  declare class Contractor {
3
- static constructionPlans(schema?: string, options?: {
4
- createSchema: boolean;
5
- }): string;
6
- static migrationPlans(schema?: string, version?: number, options?: {
7
- partitionTables?: types.MigrationPartition[];
8
- }): string;
9
- static rollbackPlans(schema?: string, version?: number): string;
3
+ static constructionPlans(schema?: string, options?: types.ConstructionPlanOptions): string;
4
+ static migrationPlans(schema?: string, version?: number, options?: types.MigrationPlanOptions): string;
5
+ static rollbackPlans(schema?: string, version?: number, options?: types.PlanOptions): string;
10
6
  private config;
11
7
  private db;
12
8
  private migrations;
@@ -1 +1 @@
1
- {"version":3,"file":"contractor.d.ts","sourceRoot":"","sources":["../src/contractor.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAOxC,cAAM,UAAU;IACd,MAAM,CAAC,iBAAiB,CAAE,MAAM,SAAuB,EAAE,OAAO;;KAAyB;IAIzF,MAAM,CAAC,cAAc,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAoB,EAAE,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,KAAK,CAAC,kBAAkB,EAAE,CAAA;KAAO;IAOjJ,MAAM,CAAC,aAAa,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAgB;IAI5E,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAmB;gBAExB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,0BAA0B;IAMpE,aAAa;IAKb,WAAW;IAKX,KAAK;YAsBG,yBAAyB;IAkCjC,WAAW,IAAK,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC;IA4GhD,KAAK;IAcL,MAAM;IASN,OAAO,CAAE,OAAO,EAAE,MAAM;IASxB,IAAI,CAAE,OAAO,EAAE,MAAM;IAKrB,QAAQ,CAAE,OAAO,EAAE,MAAM;CAIhC;AAED,eAAe,UAAU,CAAA"}
1
+ {"version":3,"file":"contractor.d.ts","sourceRoot":"","sources":["../src/contractor.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAkBxC,cAAM,UAAU;IACd,MAAM,CAAC,iBAAiB,CAAE,MAAM,SAAuB,EAAE,OAAO,GAAE,KAAK,CAAC,uBAA4B;IAapG,MAAM,CAAC,cAAc,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAoB,EAAE,OAAO,GAAE,KAAK,CAAC,oBAAyB;IAS3H,MAAM,CAAC,aAAa,CAAE,MAAM,SAAuB,EAAE,OAAO,SAAgB,EAAE,OAAO,GAAE,KAAK,CAAC,WAAgB;IAM7G,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,EAAE,CAAiB;IAC3B,OAAO,CAAC,UAAU,CAAmB;gBAExB,EAAE,EAAE,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,0BAA0B;IAgBpE,aAAa;IAKb,WAAW;IAKX,KAAK;YAsBG,yBAAyB;IAkCjC,WAAW,IAAK,OAAO,CAAC,KAAK,CAAC,iBAAiB,CAAC;IA4GhD,KAAK;IAcL,MAAM;IASN,OAAO,CAAE,OAAO,EAAE,MAAM;IASxB,IAAI,CAAE,OAAO,EAAE,MAAM;IAKrB,QAAQ,CAAE,OAAO,EAAE,MAAM;CAIhC;AAED,eAAe,UAAU,CAAA"}