Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions packages/db/test/helpers/migrated-connection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,36 @@ import type { DbConnection } from "../../src/index.js";

let migratedTemplate: Buffer | null = null;

function getMigratedTemplate(): Buffer {
if (migratedTemplate === null) {
const db = createConnection(":memory:");
try {
migrate(db);
migratedTemplate = db.$client.serialize();
} finally {
db.$client.close();
}
}

return migratedTemplate;
}

/** Build the shared template outside a test's timeout budget. */
export function prepareMigratedConnectionTemplate(): void {
getMigratedTemplate();
}

/**
* A fresh in-memory database with every migration applied, exactly as
* `createConnection(":memory:")` followed by `migrate(db)` leaves it. The
* first call migrates for real and keeps the serialized image; every later
* call opens an independent copy of that image. Replaying the 100+
* migrations costs ~57ms, which the data suites paid once per test.
*
* Suites that exercise `migrate` itself keep calling it directly.
* Tests that exercise the initial migration keep calling `migrate` directly.
* Migration tests may use this only for current-schema setup that they rewind
* before exercising a later `migrate` boundary.
*/
export function createMigratedConnection(): DbConnection {
if (migratedTemplate === null) {
const db = createConnection(":memory:");
migrate(db);
migratedTemplate = db.$client.serialize();
}
return createConnection(migratedTemplate);
return createConnection(getMigratedTemplate());
}
19 changes: 14 additions & 5 deletions packages/db/test/migrate.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest";
import { beforeAll, describe, expect, it, vi } from "vitest";
import { readFileSync } from "node:fs";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
Expand All @@ -17,6 +17,10 @@ import {
type DbConnection,
type MigrationWarningLogger,
} from "../src/index.js";
import {
createMigratedConnection,
prepareMigratedConnectionTemplate,
} from "./helpers/migrated-connection.js";

type InsertMigrationParameters = [string, number];
type DeleteMigrationParameters = [number];
Expand Down Expand Up @@ -1451,6 +1455,13 @@ function deleteDeferredCleanupMigrationRows(db: DbConnection): void {
}

describe("migrate", () => {
beforeAll(() => {
// The large-value replay cases need a current database only as a rewind
// fixture. Build that shared image outside either case's timeout budget;
// each case still exercises the real migrate() boundary after rewinding.
prepareMigratedConnectionTemplate();
});

it("backfills the first checkout commit component for every artifact shape", () => {
const db = createConnection(":memory:");
const commit = "d".repeat(40);
Expand Down Expand Up @@ -4305,10 +4316,9 @@ describe("migrate", () => {
});

it("skips legacy large event value round trip when values are already inline", () => {
const db = createConnection(":memory:");
const db = createMigratedConnection();

try {
migrate(db);
dropRewindAddedTables(db);
seedEventLargeValueBackfillThread(db);
const values = seedEventLargeValueBackfillEvents(db);
Expand Down Expand Up @@ -4359,10 +4369,9 @@ describe("migrate", () => {
});

it("restores legacy large event values to inline payloads", () => {
const db = createConnection(":memory:");
const db = createMigratedConnection();

try {
migrate(db);
dropRewindAddedTables(db);
seedEventLargeValueBackfillThread(db);
const values = seedEventLargeValueBackfillEvents(db);
Expand Down
Loading