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
9 changes: 8 additions & 1 deletion apps/ensindexer/src/lib/ensdb-client/ensdb-client.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,12 @@ describe("EnsDbClient", () => {
const onConflictDoUpdateMock = vi.fn(async () => undefined);
const valuesMock = vi.fn(() => ({ onConflictDoUpdate: onConflictDoUpdateMock }));
const insertMock = vi.fn(() => ({ values: valuesMock }));
const dbMock = { select: selectMock, insert: insertMock };
const executeMock = vi.fn(async () => undefined);
const txMock = { insert: insertMock, execute: executeMock };
const transactionMock = vi.fn(async (callback: (tx: typeof txMock) => Promise<void>) =>
callback(txMock),
);
const dbMock = { select: selectMock, insert: insertMock, transaction: transactionMock };
Comment on lines +30 to +35
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new workaround is executed via db.transaction() and tx.execute(...), but the existing upsert tests only assert the insert/value/upsert chain. Add assertions that transactionMock is called and that executeMock is invoked with the expected SQL so the test suite actually covers (and will catch regressions in) the new temp-table creation behavior.

Copilot uses AI. Check for mistakes.

beforeEach(() => {
selectResult.current = [];
Expand All @@ -37,6 +42,8 @@ describe("EnsDbClient", () => {
onConflictDoUpdateMock.mockClear();
valuesMock.mockClear();
insertMock.mockClear();
executeMock.mockClear();
transactionMock.mockClear();
vi.mocked(makeDrizzle).mockReturnValue(dbMock as unknown as ReturnType<typeof makeDrizzle>);
});

Expand Down
32 changes: 21 additions & 11 deletions apps/ensindexer/src/lib/ensdb-client/ensdb-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
import { eq } from "drizzle-orm/sql";
import { eq, sql } from "drizzle-orm/sql";

import { ensNodeMetadata } from "@ensnode/ensnode-schema";
import {
Expand Down Expand Up @@ -176,15 +176,25 @@ export class EnsDbClient implements EnsDbClientQuery, EnsDbClientMutation {
private async upsertEnsNodeMetadata<
EnsNodeMetadataType extends SerializedEnsNodeMetadata = SerializedEnsNodeMetadata,
>(metadata: EnsNodeMetadataType): Promise<void> {
await this.db
.insert(ensNodeMetadata)
.values({
key: metadata.key,
value: metadata.value,
})
.onConflictDoUpdate({
target: ensNodeMetadata.key,
set: { value: metadata.value },
});
await this.db.transaction(async (tx) => {
// Ponder live-query triggers insert into live_query_tables.
// Because this worker writes outside the Ponder runtime connection pool,
// the temp table must be ensured to exist on this connection. Without this,
// the upsert would fail with "relation 'live_query_tables' does not exist" error.
await tx.execute(
sql`CREATE TEMP TABLE IF NOT EXISTS live_query_tables (table_name TEXT PRIMARY KEY)`,
);

await tx
.insert(ensNodeMetadata)
.values({
key: metadata.key,
value: metadata.value,
})
.onConflictDoUpdate({
target: ensNodeMetadata.key,
set: { value: metadata.value },
});
});
}
}