@dbos-inc/drizzle-datasource 5.2.8-preview → 5.2.9-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.mts +10 -3
- package/dist/index.d.ts +10 -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 +40 -30
- package/package.json +1 -1
- package/tests/datasource.test.ts +46 -0
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Client, ClientConfig, Pool, PoolClient, PoolConfig } from 'pg';
|
|
2
2
|
import { FunctionName } from '@dbos-inc/dbos-sdk';
|
|
3
|
-
import { DBOSDataSource } from '@dbos-inc/dbos-sdk/datasource';
|
|
3
|
+
import { DBOSDataSource, DataSourceMigrationOptions } from '@dbos-inc/dbos-sdk/datasource';
|
|
4
4
|
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
5
5
|
import { PgTransactionConfig } from 'drizzle-orm/pg-core';
|
|
6
6
|
export type TransactionConfig = Pick<PgTransactionConfig, 'isolationLevel' | 'accessMode'> & {
|
|
@@ -21,10 +21,17 @@ export declare class DrizzleDataSource<CT = NodePgDatabase<{
|
|
|
21
21
|
[key: string]: object;
|
|
22
22
|
}>;
|
|
23
23
|
get client(): CT;
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
26
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
27
|
+
* A provided client runs the statements in its current transaction, if any; a config gets a fresh transaction.
|
|
28
|
+
*/
|
|
29
|
+
static initializeDBOSSchema(configOrClient: ClientConfig | Client | PoolClient, schemaName?: string, options?: {
|
|
30
|
+
applicationRole?: string;
|
|
31
|
+
}): Promise<void>;
|
|
25
32
|
constructor(name: string, configOrPool: PoolConfig | Pool, entities?: {
|
|
26
33
|
[key: string]: object;
|
|
27
|
-
}, schemaName?: string);
|
|
34
|
+
}, schemaName?: string, options?: DataSourceMigrationOptions);
|
|
28
35
|
runTransaction<T>(func: () => Promise<T>, config?: TransactionConfig): Promise<T>;
|
|
29
36
|
registerTransaction<This, Args extends unknown[], Return>(func: (this: This, ...args: Args) => Promise<Return>, config?: TransactionConfig & FunctionName): (this: This, ...args: Args) => Promise<Return>;
|
|
30
37
|
transaction(config?: TransactionConfig): <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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Client, ClientConfig, Pool, PoolClient, PoolConfig } from 'pg';
|
|
2
2
|
import { FunctionName } from '@dbos-inc/dbos-sdk';
|
|
3
|
-
import { DBOSDataSource } from '@dbos-inc/dbos-sdk/datasource';
|
|
3
|
+
import { DBOSDataSource, DataSourceMigrationOptions } from '@dbos-inc/dbos-sdk/datasource';
|
|
4
4
|
import { NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
5
5
|
import { PgTransactionConfig } from 'drizzle-orm/pg-core';
|
|
6
6
|
export type TransactionConfig = Pick<PgTransactionConfig, 'isolationLevel' | 'accessMode'> & {
|
|
@@ -21,10 +21,17 @@ export declare class DrizzleDataSource<CT = NodePgDatabase<{
|
|
|
21
21
|
[key: string]: object;
|
|
22
22
|
}>;
|
|
23
23
|
get client(): CT;
|
|
24
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
26
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
27
|
+
* A provided client runs the statements in its current transaction, if any; a config gets a fresh transaction.
|
|
28
|
+
*/
|
|
29
|
+
static initializeDBOSSchema(configOrClient: ClientConfig | Client | PoolClient, schemaName?: string, options?: {
|
|
30
|
+
applicationRole?: string;
|
|
31
|
+
}): Promise<void>;
|
|
25
32
|
constructor(name: string, configOrPool: PoolConfig | Pool, entities?: {
|
|
26
33
|
[key: string]: object;
|
|
27
|
-
}, schemaName?: string);
|
|
34
|
+
}, schemaName?: string, options?: DataSourceMigrationOptions);
|
|
28
35
|
runTransaction<T>(func: () => Promise<T>, config?: TransactionConfig): Promise<T>;
|
|
29
36
|
registerTransaction<This, Args extends unknown[], Return>(func: (this: This, ...args: Args) => Promise<Return>, config?: TransactionConfig & FunctionName): (this: This, ...args: Args) => Promise<Return>;
|
|
30
37
|
transaction(config?: TransactionConfig): <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":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAQ,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,IAAI,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,IAAI,CAAC;AACxE,OAAO,EAAQ,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAUL,cAAc,EAEd,0BAA0B,EAK3B,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAW,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAQ1D,MAAM,MAAM,iBAAiB,GAAG,IAAI,CAAC,mBAAmB,EAAE,gBAAgB,GAAG,YAAY,CAAC,GAAG;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAY/G,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB;AAyND,qBAAa,iBAAiB,CAAC,EAAE,GAAG,cAAc,CAAC;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CAAC,CAC3E,YAAW,cAAc,CAAC,iBAAiB,CAAC;;IA0D1C,QAAQ,CAAC,IAAI,EAAE,MAAM;IAzCvB,MAAM,KAAK,MAAM;;OAEhB;IAED,IAAI,MAAM,OAET;IAED;;;;OAIG;WACU,oBAAoB,CAC/B,cAAc,EAAE,YAAY,GAAG,MAAM,GAAG,UAAU,EAClD,UAAU,GAAE,MAAe,EAC3B,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAO,GACzC,OAAO,CAAC,IAAI,CAAC;gBAwBL,IAAI,EAAE,MAAM,EACrB,YAAY,EAAE,UAAU,GAAG,IAAI,EAC/B,QAAQ,GAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAO,EACxC,UAAU,GAAE,MAAe,EAC3B,OAAO,GAAE,0BAA+B;IAMpC,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,EAAE,iBAAiB;IAI1E,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,iBAAiB,GAAG,YAAY,GACxC,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,MAAM,CAAC;IAKjD,WAAW,CAAC,MAAM,CAAC,EAAE,iBAAiB,kDAI1B,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
|
@@ -9,17 +9,25 @@ const async_hooks_1 = require("async_hooks");
|
|
|
9
9
|
const superjson_1 = require("superjson");
|
|
10
10
|
const drizzle_orm_1 = require("drizzle-orm");
|
|
11
11
|
const asyncLocalCtx = new async_hooks_1.AsyncLocalStorage();
|
|
12
|
+
function drizzleExecutor(db) {
|
|
13
|
+
return async (text) => (await db.execute(drizzle_orm_1.sql.raw(text))).rows;
|
|
14
|
+
}
|
|
15
|
+
function clientExecutor(client) {
|
|
16
|
+
return async (text) => (await client.query(text)).rows;
|
|
17
|
+
}
|
|
12
18
|
class DrizzleTransactionHandler {
|
|
13
19
|
name;
|
|
14
20
|
configOrPool;
|
|
15
21
|
entities;
|
|
22
|
+
options;
|
|
16
23
|
#connection;
|
|
17
24
|
schemaName;
|
|
18
25
|
#userProvidedPool;
|
|
19
|
-
constructor(name, configOrPool, entities = {}, schemaName = 'dbos') {
|
|
26
|
+
constructor(name, configOrPool, entities = {}, schemaName = 'dbos', options = {}) {
|
|
20
27
|
this.name = name;
|
|
21
28
|
this.configOrPool = configOrPool;
|
|
22
29
|
this.entities = entities;
|
|
30
|
+
this.options = options;
|
|
23
31
|
this.schemaName = schemaName;
|
|
24
32
|
this.#userProvidedPool = configOrPool instanceof pg_1.Pool;
|
|
25
33
|
}
|
|
@@ -29,27 +37,16 @@ class DrizzleTransactionHandler {
|
|
|
29
37
|
const db = (0, node_postgres_1.drizzle)({ client: driver, schema: this.entities });
|
|
30
38
|
this.#connection = { db, end: this.#userProvidedPool ? async () => { } : () => driver.end() };
|
|
31
39
|
await conn?.end();
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const row = Array.isArray(res)
|
|
36
|
-
? res[0]
|
|
37
|
-
: (res.rows?.[0] ??
|
|
38
|
-
res[0]);
|
|
39
|
-
installed = !!row?.schema_exists && !!row?.table_exists;
|
|
40
|
+
if (this.options.runMigrations === false) {
|
|
41
|
+
await (0, datasource_1.verifyDataSourcePG)(drizzleExecutor(db), this.schemaName, this.name);
|
|
42
|
+
return;
|
|
40
43
|
}
|
|
41
|
-
|
|
42
|
-
|
|
44
|
+
try {
|
|
45
|
+
await db.transaction((tx) => (0, datasource_1.migrateDataSourcePG)(drizzleExecutor(tx), this.schemaName));
|
|
43
46
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
await db.execute(drizzle_orm_1.sql.raw((0, datasource_1.createTransactionCompletionSchemaPG)(this.schemaName)));
|
|
47
|
-
await db.execute(drizzle_orm_1.sql.raw((0, datasource_1.createTransactionCompletionTablePG)(this.schemaName)));
|
|
48
|
-
}
|
|
49
|
-
catch (err) {
|
|
50
|
-
throw new Error(`In initialization of 'DrizzleDataSource' ${this.name}: The '${this.schemaName}.transaction_completion' table does not exist, and could not be created. This should be added to your database migrations.
|
|
47
|
+
catch (err) {
|
|
48
|
+
throw new Error(`In initialization of 'DrizzleDataSource' ${this.name}: The '${this.schemaName}' transaction schema could not be migrated: ${err.message}. This should be added to your database migrations.
|
|
51
49
|
See: https://docs.dbos.dev/typescript/tutorials/transaction-tutorial#installing-the-dbos-schema`);
|
|
52
|
-
}
|
|
53
50
|
}
|
|
54
51
|
}
|
|
55
52
|
async destroy() {
|
|
@@ -202,17 +199,28 @@ class DrizzleDataSource {
|
|
|
202
199
|
get client() {
|
|
203
200
|
return DrizzleDataSource.#getClient(this.#provider);
|
|
204
201
|
}
|
|
205
|
-
|
|
202
|
+
/**
|
|
203
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
204
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
205
|
+
* A provided client runs the statements in its current transaction, if any; a config gets a fresh transaction.
|
|
206
|
+
*/
|
|
207
|
+
static async initializeDBOSSchema(configOrClient, schemaName = 'dbos', options = {}) {
|
|
206
208
|
if (typeof configOrClient === 'object' && 'query' in configOrClient) {
|
|
207
|
-
await
|
|
208
|
-
await configOrClient.query((0, datasource_1.createTransactionCompletionTablePG)(schemaName));
|
|
209
|
+
await (0, datasource_1.initializeDataSourceSchemaPG)(clientExecutor(configOrClient), schemaName, options.applicationRole);
|
|
209
210
|
}
|
|
210
211
|
else {
|
|
211
212
|
const client = new pg_1.Client(configOrClient);
|
|
212
213
|
try {
|
|
213
214
|
await client.connect();
|
|
214
|
-
await client.query(
|
|
215
|
-
|
|
215
|
+
await client.query('BEGIN');
|
|
216
|
+
try {
|
|
217
|
+
await (0, datasource_1.initializeDataSourceSchemaPG)(clientExecutor(client), schemaName, options.applicationRole);
|
|
218
|
+
await client.query('COMMIT');
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
await client.query('ROLLBACK');
|
|
222
|
+
throw err;
|
|
223
|
+
}
|
|
216
224
|
}
|
|
217
225
|
finally {
|
|
218
226
|
await client.end();
|
|
@@ -220,9 +228,9 @@ class DrizzleDataSource {
|
|
|
220
228
|
}
|
|
221
229
|
}
|
|
222
230
|
#provider;
|
|
223
|
-
constructor(name, configOrPool, entities = {}, schemaName = 'dbos') {
|
|
231
|
+
constructor(name, configOrPool, entities = {}, schemaName = 'dbos', options = {}) {
|
|
224
232
|
this.name = name;
|
|
225
|
-
this.#provider = new DrizzleTransactionHandler(name, configOrPool, entities, schemaName);
|
|
233
|
+
this.#provider = new DrizzleTransactionHandler(name, configOrPool, entities, schemaName, options);
|
|
226
234
|
(0, datasource_1.registerDataSource)(this.#provider);
|
|
227
235
|
}
|
|
228
236
|
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,2BAAwE;AACxE,iDAAwD;AACxD,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
|
package/index.ts
CHANGED
|
@@ -2,8 +2,6 @@ import { Client, ClientConfig, Pool, PoolClient, PoolConfig } from 'pg';
|
|
|
2
2
|
import { DBOS, FunctionName } from '@dbos-inc/dbos-sdk';
|
|
3
3
|
import {
|
|
4
4
|
type DataSourceTransactionHandler,
|
|
5
|
-
createTransactionCompletionSchemaPG,
|
|
6
|
-
createTransactionCompletionTablePG,
|
|
7
5
|
isPGRetriableTransactionError,
|
|
8
6
|
DBOSError,
|
|
9
7
|
DBOSStepAlreadyRecordedError,
|
|
@@ -14,8 +12,11 @@ import {
|
|
|
14
12
|
runTransaction,
|
|
15
13
|
DBOSDataSource,
|
|
16
14
|
registerDataSource,
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
DataSourceMigrationOptions,
|
|
16
|
+
DataSourceSQLExecutor,
|
|
17
|
+
initializeDataSourceSchemaPG,
|
|
18
|
+
migrateDataSourcePG,
|
|
19
|
+
verifyDataSourcePG,
|
|
19
20
|
} from '@dbos-inc/dbos-sdk/datasource';
|
|
20
21
|
import { drizzle, NodePgDatabase } from 'drizzle-orm/node-postgres';
|
|
21
22
|
import { AsyncLocalStorage } from 'async_hooks';
|
|
@@ -32,6 +33,14 @@ export type TransactionConfig = Pick<PgTransactionConfig, 'isolationLevel' | 'ac
|
|
|
32
33
|
|
|
33
34
|
const asyncLocalCtx = new AsyncLocalStorage<DrizzleLocalCtx>();
|
|
34
35
|
|
|
36
|
+
function drizzleExecutor(db: Pick<NodePgDatabase<{ [key: string]: object }>, 'execute'>): DataSourceSQLExecutor {
|
|
37
|
+
return async (text) => (await db.execute<Record<string, unknown>>(sql.raw(text))).rows;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function clientExecutor(client: Pick<Client, 'query'>): DataSourceSQLExecutor {
|
|
41
|
+
return async (text) => (await client.query<Record<string, unknown>>(text)).rows;
|
|
42
|
+
}
|
|
43
|
+
|
|
35
44
|
export interface transaction_completion {
|
|
36
45
|
workflow_id: string;
|
|
37
46
|
function_num: number;
|
|
@@ -54,6 +63,7 @@ class DrizzleTransactionHandler implements DataSourceTransactionHandler {
|
|
|
54
63
|
private readonly configOrPool: PoolConfig | Pool,
|
|
55
64
|
private readonly entities: { [key: string]: object } = {},
|
|
56
65
|
schemaName: string = 'dbos',
|
|
66
|
+
private readonly options: DataSourceMigrationOptions = {},
|
|
57
67
|
) {
|
|
58
68
|
this.schemaName = schemaName;
|
|
59
69
|
this.#userProvidedPool = configOrPool instanceof Pool;
|
|
@@ -67,30 +77,18 @@ class DrizzleTransactionHandler implements DataSourceTransactionHandler {
|
|
|
67
77
|
this.#connection = { db, end: this.#userProvidedPool ? async () => {} : () => driver.end() };
|
|
68
78
|
await conn?.end();
|
|
69
79
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const row = Array.isArray(res)
|
|
74
|
-
? (res as CheckSchemaInstallationReturn[])[0]
|
|
75
|
-
: ((res as { rows?: CheckSchemaInstallationReturn[] }).rows?.[0] ??
|
|
76
|
-
(res as CheckSchemaInstallationReturn[])[0]);
|
|
77
|
-
installed = !!row?.schema_exists && !!row?.table_exists;
|
|
78
|
-
} catch (e) {
|
|
79
|
-
throw new Error(
|
|
80
|
-
`In initialization of 'DrizzleDataSource' ${this.name}: Database could not be queried: ${(e as Error).message}`,
|
|
81
|
-
);
|
|
80
|
+
if (this.options.runMigrations === false) {
|
|
81
|
+
await verifyDataSourcePG(drizzleExecutor(db), this.schemaName, this.name);
|
|
82
|
+
return;
|
|
82
83
|
}
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
throw new Error(
|
|
90
|
-
`In initialization of 'DrizzleDataSource' ${this.name}: The '${this.schemaName}.transaction_completion' table does not exist, and could not be created. This should be added to your database migrations.
|
|
85
|
+
try {
|
|
86
|
+
await db.transaction((tx) => migrateDataSourcePG(drizzleExecutor(tx), this.schemaName));
|
|
87
|
+
} catch (err) {
|
|
88
|
+
throw new Error(
|
|
89
|
+
`In initialization of 'DrizzleDataSource' ${this.name}: The '${this.schemaName}' transaction schema could not be migrated: ${(err as Error).message}. This should be added to your database migrations.
|
|
91
90
|
See: https://docs.dbos.dev/typescript/tutorials/transaction-tutorial#installing-the-dbos-schema`,
|
|
92
|
-
|
|
93
|
-
}
|
|
91
|
+
);
|
|
94
92
|
}
|
|
95
93
|
}
|
|
96
94
|
|
|
@@ -291,19 +289,30 @@ export class DrizzleDataSource<CT = NodePgDatabase<{ [key: string]: object }>>
|
|
|
291
289
|
return DrizzleDataSource.#getClient(this.#provider) as CT;
|
|
292
290
|
}
|
|
293
291
|
|
|
292
|
+
/**
|
|
293
|
+
* Create or migrate the DBOS transaction schema, typically with a privileged role,
|
|
294
|
+
* optionally granting `applicationRole` the minimal permissions to use it.
|
|
295
|
+
* A provided client runs the statements in its current transaction, if any; a config gets a fresh transaction.
|
|
296
|
+
*/
|
|
294
297
|
static async initializeDBOSSchema(
|
|
295
298
|
configOrClient: ClientConfig | Client | PoolClient,
|
|
296
299
|
schemaName: string = 'dbos',
|
|
300
|
+
options: { applicationRole?: string } = {},
|
|
297
301
|
): Promise<void> {
|
|
298
302
|
if (typeof configOrClient === 'object' && 'query' in configOrClient) {
|
|
299
|
-
await
|
|
300
|
-
await configOrClient.query(createTransactionCompletionTablePG(schemaName));
|
|
303
|
+
await initializeDataSourceSchemaPG(clientExecutor(configOrClient), schemaName, options.applicationRole);
|
|
301
304
|
} else {
|
|
302
305
|
const client = new Client(configOrClient);
|
|
303
306
|
try {
|
|
304
307
|
await client.connect();
|
|
305
|
-
await client.query(
|
|
306
|
-
|
|
308
|
+
await client.query('BEGIN');
|
|
309
|
+
try {
|
|
310
|
+
await initializeDataSourceSchemaPG(clientExecutor(client), schemaName, options.applicationRole);
|
|
311
|
+
await client.query('COMMIT');
|
|
312
|
+
} catch (err) {
|
|
313
|
+
await client.query('ROLLBACK');
|
|
314
|
+
throw err;
|
|
315
|
+
}
|
|
307
316
|
} finally {
|
|
308
317
|
await client.end();
|
|
309
318
|
}
|
|
@@ -317,8 +326,9 @@ export class DrizzleDataSource<CT = NodePgDatabase<{ [key: string]: object }>>
|
|
|
317
326
|
configOrPool: PoolConfig | Pool,
|
|
318
327
|
entities: { [key: string]: object } = {},
|
|
319
328
|
schemaName: string = 'dbos',
|
|
329
|
+
options: DataSourceMigrationOptions = {},
|
|
320
330
|
) {
|
|
321
|
-
this.#provider = new DrizzleTransactionHandler(name, configOrPool, entities, schemaName);
|
|
331
|
+
this.#provider = new DrizzleTransactionHandler(name, configOrPool, entities, schemaName, options);
|
|
322
332
|
registerDataSource(this.#provider);
|
|
323
333
|
}
|
|
324
334
|
|
package/package.json
CHANGED
package/tests/datasource.test.ts
CHANGED
|
@@ -706,3 +706,49 @@ describe('DrizzleDataSourceCreateTxC', () => {
|
|
|
706
706
|
expect(rows).toHaveLength(0);
|
|
707
707
|
});
|
|
708
708
|
});
|
|
709
|
+
|
|
710
|
+
describe('DrizzleDataSource migrations', () => {
|
|
711
|
+
const userDB = new Pool(config);
|
|
712
|
+
|
|
713
|
+
afterAll(async () => {
|
|
714
|
+
await userDB.end();
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
afterEach(async () => {
|
|
718
|
+
await DBOS.shutdown();
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
test('verify-only initialization requires the schema to be migrated out of band', async () => {
|
|
722
|
+
const suffix = randomUUID().replace(/-/g, '').slice(0, 8);
|
|
723
|
+
const schemaName = `ds_mig_${suffix}`;
|
|
724
|
+
const role = `ds_app_${suffix}`;
|
|
725
|
+
const admin = new Client({ ...config, database: 'postgres' });
|
|
726
|
+
await admin.connect();
|
|
727
|
+
try {
|
|
728
|
+
await ensureDB(admin, config.database);
|
|
729
|
+
} finally {
|
|
730
|
+
await admin.end();
|
|
731
|
+
}
|
|
732
|
+
await userDB.query(`CREATE ROLE "${role}"`);
|
|
733
|
+
try {
|
|
734
|
+
new DrizzleDataSource(`verify-only-${suffix}`, config, {}, schemaName, { runMigrations: false });
|
|
735
|
+
DBOS.setConfig({ name: 'drizzle-ds-test' });
|
|
736
|
+
await expect(DBOS.launch()).rejects.toThrow(/is at transaction schema version 0/);
|
|
737
|
+
await DBOS.shutdown();
|
|
738
|
+
const { rowCount } = await userDB.query('SELECT 1 FROM pg_namespace WHERE nspname = $1', [schemaName]);
|
|
739
|
+
expect(rowCount).toBe(0);
|
|
740
|
+
|
|
741
|
+
await DrizzleDataSource.initializeDBOSSchema(config, schemaName, { applicationRole: role });
|
|
742
|
+
await DBOS.launch();
|
|
743
|
+
const { rows } = await userDB.query<{ allowed: boolean }>(
|
|
744
|
+
`SELECT has_table_privilege($1, $2, 'INSERT') AS allowed`,
|
|
745
|
+
[role, `"${schemaName}".transaction_completion`],
|
|
746
|
+
);
|
|
747
|
+
expect(rows).toEqual([{ allowed: true }]);
|
|
748
|
+
} finally {
|
|
749
|
+
await userDB.query(`DROP SCHEMA IF EXISTS "${schemaName}" CASCADE`);
|
|
750
|
+
await userDB.query(`DROP OWNED BY "${role}"`);
|
|
751
|
+
await userDB.query(`DROP ROLE "${role}"`);
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
});
|