@dbos-inc/node-pg-datasource 5.2.8-preview → 5.2.10-preview
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.
- package/dist/index.d.ts +9 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +34 -26
- package/dist/index.js.map +1 -1
- package/index.ts +43 -32
- package/package.json +1 -1
- package/tests/datasource.test.ts +46 -0
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { FunctionName } from '@dbos-inc/dbos-sdk';
|
|
2
|
-
import { PGTransactionConfig, DBOSDataSource } from '@dbos-inc/dbos-sdk/datasource';
|
|
2
|
+
import { PGTransactionConfig, DBOSDataSource, DataSourceMigrationOptions } from '@dbos-inc/dbos-sdk/datasource';
|
|
3
3
|
import { type ClientBase, type ClientConfig, type PoolConfig } from 'pg';
|
|
4
4
|
interface NodePostgresTransactionOptions extends PGTransactionConfig {
|
|
5
5
|
name?: string;
|
|
@@ -10,8 +10,14 @@ export declare class NodePostgresDataSource implements DBOSDataSource<NodePostgr
|
|
|
10
10
|
readonly name: string;
|
|
11
11
|
static get client(): ClientBase;
|
|
12
12
|
get client(): ClientBase;
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
15
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
16
|
+
*/
|
|
17
|
+
static initializeDBOSSchema(config: ClientConfig, schemaName?: string, options?: {
|
|
18
|
+
applicationRole?: string;
|
|
19
|
+
}): Promise<void>;
|
|
20
|
+
constructor(name: string, config: PoolConfig, schemaName?: string, options?: DataSourceMigrationOptions);
|
|
15
21
|
runTransaction<T>(func: () => Promise<T>, config?: NodePostgresTransactionOptions): Promise<T>;
|
|
16
22
|
registerTransaction<This, Args extends unknown[], Return>(func: (this: This, ...args: Args) => Promise<Return>, config?: NodePostgresTransactionOptions & FunctionName): (this: This, ...args: Args) => Promise<Return>;
|
|
17
23
|
transaction(config?: NodePostgresTransactionOptions): <This, Args extends unknown[], Return>(target: object, propertyKey: PropertyKey, descriptor: TypedPropertyDescriptor<(this: This, ...args: Args) => Promise<Return>>) => TypedPropertyDescriptor<(this: This, ...args: Args) => Promise<Return>>;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAQ,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAUL,mBAAmB,EACnB,cAAc,EAEd,0BAA0B,EAK3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAU,KAAK,UAAU,EAAE,KAAK,YAAY,EAAQ,KAAK,UAAU,EAAE,MAAM,IAAI,CAAC;AASvF,UAAU,8BAA+B,SAAQ,mBAAmB;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,OAAO,EAAE,8BAA8B,EAAE,CAAC;AA8O1C,qBAAa,sBAAuB,YAAW,cAAc,CAAC,8BAA8B,CAAC;;IAmDzF,QAAQ,CAAC,IAAI,EAAE,MAAM;IApCvB,MAAM,KAAK,MAAM,eAEhB;IAED,IAAI,MAAM,eAET;IAED;;;OAGG;WACU,oBAAoB,CAC/B,MAAM,EAAE,YAAY,EACpB,UAAU,GAAE,MAAe,EAC3B,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAO,GACzC,OAAO,CAAC,IAAI,CAAC;gBAoBL,IAAI,EAAE,MAAM,EACrB,MAAM,EAAE,UAAU,EAClB,UAAU,GAAE,MAAe,EAC3B,OAAO,GAAE,0BAA+B;IAMpC,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,8BAA8B;IAIvF,mBAAmB,CAAC,IAAI,EAAE,IAAI,SAAS,OAAO,EAAE,EAAE,MAAM,EACtD,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC,EACpD,MAAM,CAAC,EAAE,8BAA8B,GAAG,YAAY,GACrD,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC;IAIjD,WAAW,CAAC,MAAM,CAAC,EAAE,8BAA8B,kDAIvC,MAAM,eACD,WAAW,cACZ,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,QAAQ,MAAM,CAAC,CAAC,oCAAxC,IAAI,WAAW,IAAI,KAAK,QAAQ,MAAM,CAAC;CAevF"}
|
package/dist/index.js
CHANGED
|
@@ -8,44 +8,41 @@ const pg_1 = require("pg");
|
|
|
8
8
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
9
9
|
const superjson_1 = require("superjson");
|
|
10
10
|
const asyncLocalCtx = new node_async_hooks_1.AsyncLocalStorage();
|
|
11
|
+
function clientExecutor(client) {
|
|
12
|
+
return async (sql) => (await client.query(sql)).rows;
|
|
13
|
+
}
|
|
11
14
|
class NodePostgresTransactionHandler {
|
|
12
15
|
name;
|
|
13
16
|
config;
|
|
17
|
+
options;
|
|
14
18
|
#poolField;
|
|
15
19
|
schemaName;
|
|
16
|
-
constructor(name, config, schemaName = 'dbos') {
|
|
20
|
+
constructor(name, config, schemaName = 'dbos', options = {}) {
|
|
17
21
|
this.name = name;
|
|
18
22
|
this.config = config;
|
|
23
|
+
this.options = options;
|
|
19
24
|
this.schemaName = schemaName;
|
|
20
25
|
}
|
|
21
26
|
async initialize() {
|
|
22
27
|
const pool = this.#poolField;
|
|
23
28
|
this.#poolField = new pg_1.Pool(this.config);
|
|
24
29
|
await pool?.end();
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let installed = false;
|
|
30
|
+
if (this.options.runMigrations === false) {
|
|
31
|
+
const client = await this.#poolField.connect();
|
|
28
32
|
try {
|
|
29
|
-
|
|
30
|
-
installed = !!res.rows[0].schema_exists && !!res.rows[0].table_exists;
|
|
31
|
-
}
|
|
32
|
-
catch (e) {
|
|
33
|
-
throw new Error(`In initialization of 'NodePostgresDataSource' ${this.name}: Database could not be queried: ${e.message}`);
|
|
33
|
+
await (0, datasource_1.verifyDataSourcePG)(clientExecutor(client), this.schemaName, this.name);
|
|
34
34
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
try {
|
|
38
|
-
await client.query((0, datasource_1.createTransactionCompletionSchemaPG)(this.schemaName));
|
|
39
|
-
await client.query((0, datasource_1.createTransactionCompletionTablePG)(this.schemaName));
|
|
40
|
-
}
|
|
41
|
-
catch (err) {
|
|
42
|
-
throw new Error(`In initialization of 'NodePostgresDataSource' ${this.name}: The '${this.schemaName}.transaction_completion' table does not exist, and could not be created. This should be added to your database migrations.
|
|
43
|
-
See: https://docs.dbos.dev/typescript/tutorials/transaction-tutorial#installing-the-dbos-schema`);
|
|
44
|
-
}
|
|
35
|
+
finally {
|
|
36
|
+
client.release();
|
|
45
37
|
}
|
|
38
|
+
return;
|
|
46
39
|
}
|
|
47
|
-
|
|
48
|
-
client.
|
|
40
|
+
try {
|
|
41
|
+
await this.#transaction((client) => (0, datasource_1.migrateDataSourcePG)(clientExecutor(client), this.schemaName));
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
throw new Error(`In initialization of 'NodePostgresDataSource' ${this.name}: The '${this.schemaName}' transaction schema could not be migrated: ${err.message}. This should be added to your database migrations.
|
|
45
|
+
See: https://docs.dbos.dev/typescript/tutorials/transaction-tutorial#installing-the-dbos-schema`);
|
|
49
46
|
}
|
|
50
47
|
}
|
|
51
48
|
async destroy() {
|
|
@@ -215,21 +212,32 @@ class NodePostgresDataSource {
|
|
|
215
212
|
get client() {
|
|
216
213
|
return NodePostgresDataSource.#getClient(this.#provider);
|
|
217
214
|
}
|
|
218
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
217
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
218
|
+
*/
|
|
219
|
+
static async initializeDBOSSchema(config, schemaName = 'dbos', options = {}) {
|
|
219
220
|
const client = new pg_1.Client(config);
|
|
220
221
|
try {
|
|
221
222
|
await client.connect();
|
|
222
|
-
await client.query(
|
|
223
|
-
|
|
223
|
+
await client.query('BEGIN');
|
|
224
|
+
try {
|
|
225
|
+
await (0, datasource_1.initializeDataSourceSchemaPG)(clientExecutor(client), schemaName, options.applicationRole);
|
|
226
|
+
await client.query('COMMIT');
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
await client.query('ROLLBACK');
|
|
230
|
+
throw err;
|
|
231
|
+
}
|
|
224
232
|
}
|
|
225
233
|
finally {
|
|
226
234
|
await client.end();
|
|
227
235
|
}
|
|
228
236
|
}
|
|
229
237
|
#provider;
|
|
230
|
-
constructor(name, config, schemaName = 'dbos') {
|
|
238
|
+
constructor(name, config, schemaName = 'dbos', options = {}) {
|
|
231
239
|
this.name = name;
|
|
232
|
-
this.#provider = new NodePostgresTransactionHandler(name, config, schemaName);
|
|
240
|
+
this.#provider = new NodePostgresTransactionHandler(name, config, schemaName, options);
|
|
233
241
|
(0, datasource_1.registerDataSource)(this.#provider);
|
|
234
242
|
}
|
|
235
243
|
async runTransaction(func, config) {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":";AAAA,gDAAgD;;;AAEhD,iDAAwD;AACxD,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/index.ts
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
import { DBOS, FunctionName } from '@dbos-inc/dbos-sdk';
|
|
4
4
|
import {
|
|
5
5
|
type DataSourceTransactionHandler,
|
|
6
|
-
createTransactionCompletionSchemaPG,
|
|
7
|
-
createTransactionCompletionTablePG,
|
|
8
6
|
isPGRetriableTransactionError,
|
|
9
7
|
DBOSError,
|
|
10
8
|
DBOSStepAlreadyRecordedError,
|
|
@@ -16,8 +14,11 @@ import {
|
|
|
16
14
|
PGTransactionConfig,
|
|
17
15
|
DBOSDataSource,
|
|
18
16
|
registerDataSource,
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
DataSourceMigrationOptions,
|
|
18
|
+
DataSourceSQLExecutor,
|
|
19
|
+
initializeDataSourceSchemaPG,
|
|
20
|
+
migrateDataSourcePG,
|
|
21
|
+
verifyDataSourcePG,
|
|
21
22
|
} from '@dbos-inc/dbos-sdk/datasource';
|
|
22
23
|
import { Client, type ClientBase, type ClientConfig, Pool, type PoolConfig } from 'pg';
|
|
23
24
|
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
@@ -36,6 +37,10 @@ export { NodePostgresTransactionOptions };
|
|
|
36
37
|
|
|
37
38
|
const asyncLocalCtx = new AsyncLocalStorage<NodePostgresDataSourceContext>();
|
|
38
39
|
|
|
40
|
+
function clientExecutor(client: ClientBase): DataSourceSQLExecutor {
|
|
41
|
+
return async (sql) => (await client.query<Record<string, unknown>>(sql)).rows;
|
|
42
|
+
}
|
|
43
|
+
|
|
39
44
|
class NodePostgresTransactionHandler implements DataSourceTransactionHandler {
|
|
40
45
|
#poolField: Pool | undefined;
|
|
41
46
|
readonly schemaName: string;
|
|
@@ -44,6 +49,7 @@ class NodePostgresTransactionHandler implements DataSourceTransactionHandler {
|
|
|
44
49
|
readonly name: string,
|
|
45
50
|
private readonly config: PoolConfig,
|
|
46
51
|
schemaName: string = 'dbos',
|
|
52
|
+
private readonly options: DataSourceMigrationOptions = {},
|
|
47
53
|
) {
|
|
48
54
|
this.schemaName = schemaName;
|
|
49
55
|
}
|
|
@@ -53,33 +59,23 @@ class NodePostgresTransactionHandler implements DataSourceTransactionHandler {
|
|
|
53
59
|
this.#poolField = new Pool(this.config);
|
|
54
60
|
await pool?.end();
|
|
55
61
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
try {
|
|
59
|
-
let installed = false;
|
|
62
|
+
if (this.options.runMigrations === false) {
|
|
63
|
+
const client = await this.#poolField.connect();
|
|
60
64
|
try {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
throw new Error(
|
|
65
|
-
`In initialization of 'NodePostgresDataSource' ${this.name}: Database could not be queried: ${(e as Error).message}`,
|
|
66
|
-
);
|
|
65
|
+
await verifyDataSourcePG(clientExecutor(client), this.schemaName, this.name);
|
|
66
|
+
} finally {
|
|
67
|
+
client.release();
|
|
67
68
|
}
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
`In initialization of 'NodePostgresDataSource' ${this.name}: The '${this.schemaName}.transaction_completion' table does not exist, and could not be created. This should be added to your database migrations.
|
|
77
|
-
See: https://docs.dbos.dev/typescript/tutorials/transaction-tutorial#installing-the-dbos-schema`,
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
} finally {
|
|
82
|
-
client.release();
|
|
72
|
+
try {
|
|
73
|
+
await this.#transaction((client) => migrateDataSourcePG(clientExecutor(client), this.schemaName));
|
|
74
|
+
} catch (err) {
|
|
75
|
+
throw new Error(
|
|
76
|
+
`In initialization of 'NodePostgresDataSource' ${this.name}: The '${this.schemaName}' transaction schema could not be migrated: ${(err as Error).message}. This should be added to your database migrations.
|
|
77
|
+
See: https://docs.dbos.dev/typescript/tutorials/transaction-tutorial#installing-the-dbos-schema`,
|
|
78
|
+
);
|
|
83
79
|
}
|
|
84
80
|
}
|
|
85
81
|
|
|
@@ -298,12 +294,26 @@ export class NodePostgresDataSource implements DBOSDataSource<NodePostgresTransa
|
|
|
298
294
|
return NodePostgresDataSource.#getClient(this.#provider);
|
|
299
295
|
}
|
|
300
296
|
|
|
301
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
299
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
300
|
+
*/
|
|
301
|
+
static async initializeDBOSSchema(
|
|
302
|
+
config: ClientConfig,
|
|
303
|
+
schemaName: string = 'dbos',
|
|
304
|
+
options: { applicationRole?: string } = {},
|
|
305
|
+
): Promise<void> {
|
|
302
306
|
const client = new Client(config);
|
|
303
307
|
try {
|
|
304
308
|
await client.connect();
|
|
305
|
-
await client.query(
|
|
306
|
-
|
|
309
|
+
await client.query('BEGIN');
|
|
310
|
+
try {
|
|
311
|
+
await initializeDataSourceSchemaPG(clientExecutor(client), schemaName, options.applicationRole);
|
|
312
|
+
await client.query('COMMIT');
|
|
313
|
+
} catch (err) {
|
|
314
|
+
await client.query('ROLLBACK');
|
|
315
|
+
throw err;
|
|
316
|
+
}
|
|
307
317
|
} finally {
|
|
308
318
|
await client.end();
|
|
309
319
|
}
|
|
@@ -315,8 +325,9 @@ export class NodePostgresDataSource implements DBOSDataSource<NodePostgresTransa
|
|
|
315
325
|
readonly name: string,
|
|
316
326
|
config: PoolConfig,
|
|
317
327
|
schemaName: string = 'dbos',
|
|
328
|
+
options: DataSourceMigrationOptions = {},
|
|
318
329
|
) {
|
|
319
|
-
this.#provider = new NodePostgresTransactionHandler(name, config, schemaName);
|
|
330
|
+
this.#provider = new NodePostgresTransactionHandler(name, config, schemaName, options);
|
|
320
331
|
registerDataSource(this.#provider);
|
|
321
332
|
}
|
|
322
333
|
|
package/package.json
CHANGED
package/tests/datasource.test.ts
CHANGED
|
@@ -765,3 +765,49 @@ describe('NodePostgresDataSourceCreateTxC', () => {
|
|
|
765
765
|
expect(rows).toHaveLength(0);
|
|
766
766
|
});
|
|
767
767
|
});
|
|
768
|
+
|
|
769
|
+
describe('NodePostgresDataSource migrations', () => {
|
|
770
|
+
const userDB = new Pool(config);
|
|
771
|
+
|
|
772
|
+
afterAll(async () => {
|
|
773
|
+
await userDB.end();
|
|
774
|
+
});
|
|
775
|
+
|
|
776
|
+
afterEach(async () => {
|
|
777
|
+
await DBOS.shutdown();
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
test('verify-only initialization requires the schema to be migrated out of band', async () => {
|
|
781
|
+
const suffix = randomUUID().replace(/-/g, '').slice(0, 8);
|
|
782
|
+
const schemaName = `ds_mig_${suffix}`;
|
|
783
|
+
const role = `ds_app_${suffix}`;
|
|
784
|
+
const admin = new Client({ ...config, database: 'postgres' });
|
|
785
|
+
await admin.connect();
|
|
786
|
+
try {
|
|
787
|
+
await ensureDB(admin, config.database);
|
|
788
|
+
} finally {
|
|
789
|
+
await admin.end();
|
|
790
|
+
}
|
|
791
|
+
await userDB.query(`CREATE ROLE "${role}"`);
|
|
792
|
+
try {
|
|
793
|
+
new NodePostgresDataSource(`verify-only-${suffix}`, config, schemaName, { runMigrations: false });
|
|
794
|
+
DBOS.setConfig({ name: 'node-pg-ds-test' });
|
|
795
|
+
await expect(DBOS.launch()).rejects.toThrow(/is at transaction schema version 0/);
|
|
796
|
+
await DBOS.shutdown();
|
|
797
|
+
const { rowCount } = await userDB.query('SELECT 1 FROM pg_namespace WHERE nspname = $1', [schemaName]);
|
|
798
|
+
expect(rowCount).toBe(0);
|
|
799
|
+
|
|
800
|
+
await NodePostgresDataSource.initializeDBOSSchema(config, schemaName, { applicationRole: role });
|
|
801
|
+
await DBOS.launch();
|
|
802
|
+
const { rows } = await userDB.query<{ allowed: boolean }>(
|
|
803
|
+
`SELECT has_table_privilege($1, $2, 'INSERT') AS allowed`,
|
|
804
|
+
[role, `"${schemaName}".transaction_completion`],
|
|
805
|
+
);
|
|
806
|
+
expect(rows).toEqual([{ allowed: true }]);
|
|
807
|
+
} finally {
|
|
808
|
+
await userDB.query(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`);
|
|
809
|
+
await userDB.query(`DROP OWNED BY "${role}"`);
|
|
810
|
+
await userDB.query(`DROP ROLE "${role}"`);
|
|
811
|
+
}
|
|
812
|
+
});
|
|
813
|
+
});
|