Skip to content

Commit

Permalink
Fix Debug Mode TypeORM Init (#226)
Browse files Browse the repository at this point in the history
This PR fixes a bug where TypeORM datasource wasn't initialized under
debug mode.
Also add a test for TypeORM in debug mode.
  • Loading branch information
qianl15 authored Dec 18, 2023
1 parent 6dcbe08 commit 23e3e43
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 15 deletions.
2 changes: 1 addition & 1 deletion src/dbos-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -275,9 +275,9 @@ export class DBOSExecutor {
}

// Debug mode doesn't need to initialize the DBs. Everything should appear to be read-only.
await this.userDatabase.init(this.debugMode);
if (!this.debugMode) {
await this.systemDatabase.init();
await this.userDatabase.init(); // Skip user DB init because we're using the proxy.
await this.recoverPendingWorkflows();
}
} catch (err) {
Expand Down
36 changes: 22 additions & 14 deletions src/user_database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { ValuesOf } from "./utils";
import { Knex } from "knex";

export interface UserDatabase {
init(): Promise<void>;
init(debugMode?: boolean): Promise<void>;
destroy(): Promise<void>;
getName(): UserDatabaseName;

Expand Down Expand Up @@ -54,9 +54,11 @@ export class PGNodeUserDatabase implements UserDatabase {
this.pool = new Pool(poolConfig);
}

async init(): Promise<void> {
await this.pool.query(createUserDBSchema);
await this.pool.query(userDBSchema);
async init(debugMode: boolean = false): Promise<void> {
if (!debugMode) {
await this.pool.query(createUserDBSchema);
await this.pool.query(userDBSchema);
}
}

async destroy(): Promise<void> {
Expand Down Expand Up @@ -169,9 +171,11 @@ const PrismaIsolationLevel = {
export class PrismaUserDatabase implements UserDatabase {
constructor(readonly prisma: PrismaClient) { }

async init(): Promise<void> {
await this.prisma.$queryRawUnsafe(createUserDBSchema);
await this.prisma.$queryRawUnsafe(userDBSchema);
async init(debugMode: boolean = false): Promise<void> {
if (!debugMode) {
await this.prisma.$queryRawUnsafe(createUserDBSchema);
await this.prisma.$queryRawUnsafe(userDBSchema);
}
}

async destroy(): Promise<void> {
Expand Down Expand Up @@ -273,13 +277,15 @@ export class TypeORMDatabase implements UserDatabase {
this.dataSource = ds;
}

async init(): Promise<void> {
async init(debugMode: boolean = false): Promise<void> {
if (!this.dataSource.isInitialized) {
await this.dataSource.initialize();
await this.dataSource.initialize(); // Need to initialize datasource even in debug mode.
}

await this.dataSource.query(createUserDBSchema);
await this.dataSource.query(userDBSchema);
if (!debugMode) {
await this.dataSource.query(createUserDBSchema);
await this.dataSource.query(userDBSchema);
}
}

async destroy(): Promise<void> {
Expand Down Expand Up @@ -354,9 +360,11 @@ export class KnexUserDatabase implements UserDatabase {

constructor(readonly knex: Knex) { }

async init(): Promise<void> {
await this.knex.raw(createUserDBSchema);
await this.knex.raw(userDBSchema);
async init(debugMode: boolean = false): Promise<void> {
if (!debugMode) {
await this.knex.raw(createUserDBSchema);
await this.knex.raw(userDBSchema);
}
}

async destroy(): Promise<void> {
Expand Down
70 changes: 70 additions & 0 deletions tests/testing/debug_typeorm.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { TransactionContext, Transaction, OrmEntities } from "../../src/";
import { generateDBOSTestConfig, setUpDBOSTestDb } from "../helpers";
import { v1 as uuidv1 } from "uuid";
import { DBOSConfig } from "../../src/dbos-executor";
import { TestingRuntime, TestingRuntimeImpl, createInternalTestRuntime } from "../../src/testing/testing_runtime";
import { Column, Entity, EntityManager, PrimaryColumn } from "typeorm";
import { UserDatabaseName } from "../../src/user_database";

type TestTransactionContext = TransactionContext<EntityManager>;

describe("typeorm-debugger-test", () => {
let config: DBOSConfig;
let debugConfig: DBOSConfig;
let testRuntime: TestingRuntime;
let debugRuntime: TestingRuntime;

beforeAll(async () => {
config = generateDBOSTestConfig(UserDatabaseName.TYPEORM);
debugConfig = generateDBOSTestConfig(UserDatabaseName.TYPEORM, "http://127.0.0.1:5432");
await setUpDBOSTestDb(config);
});

beforeEach(async () => {
// TODO: connect to the real proxy.
debugRuntime = await createInternalTestRuntime([KVController], debugConfig);
testRuntime = await createInternalTestRuntime([KVController], config);
await testRuntime.dropUserSchema();
await testRuntime.createUserSchema();
});

afterEach(async () => {
await debugRuntime.destroy();
await testRuntime.destroy();
});

// Test TypeORM
@Entity()
class KV {
@PrimaryColumn()
id: string = "t";

@Column()
value: string = "v";
}

@OrmEntities([KV])
class KVController {
@Transaction()
static async testTxn(txnCtxt: TestTransactionContext, id: string, value: string) {
const kv: KV = new KV();
kv.id = id;
kv.value = value;
const res = await txnCtxt.client.save(kv);
return res.id;
}
}

test("debug-typeorm-transaction", async () => {
const wfUUID = uuidv1();
// Execute the workflow and destroy the runtime
await expect(testRuntime.invoke(KVController, wfUUID).testTxn("test", "value")).resolves.toBe("test");
await testRuntime.destroy();

// Execute again in debug mode.
await expect(debugRuntime.invoke(KVController, wfUUID).testTxn("test", "value")).resolves.toBe("test");

// Execute again with the provided UUID.
await expect((debugRuntime as TestingRuntimeImpl).getDBOSExec().executeWorkflowUUID(wfUUID).then((x) => x.getResult())).resolves.toBe("test");
});
});

0 comments on commit 23e3e43

Please sign in to comment.