diff --git a/src/infrastructure/drizzle/DrizzleDiscordAccountRepository.ts b/src/infrastructure/drizzle/DrizzleDiscordAccountRepository.ts index df80da4..c2fabf8 100644 --- a/src/infrastructure/drizzle/DrizzleDiscordAccountRepository.ts +++ b/src/infrastructure/drizzle/DrizzleDiscordAccountRepository.ts @@ -8,7 +8,7 @@ import { discordId, memberId, } from "#domain"; -import { getClient } from "./client"; +import { getClient, runInTransaction } from "./client"; import { discordAccountDomainEvents, discordAccounts } from "./schema"; import { serializeDiscordAccountEventPayload } from "./serializeDiscordAccountEvent"; @@ -37,18 +37,18 @@ export class DrizzleDiscordAccountRepository implements DiscordAccountRepository } async findAll(): Promise { - const db = getDb(); + const db = getClient(); const rows = await db.query.discordAccounts.findMany(); return rows.map(toDomain); } async save(account: DiscordAccount): Promise { - const db = getClient(); const now = new Date().toISOString(); const events = account.getDomainEvents(); - await db.transaction(async (tx) => { - await tx + await runInTransaction(async () => { + const client = getClient(); + await client .insert(discordAccounts) .values({ discordId: account.discordId as string, @@ -65,7 +65,7 @@ export class DrizzleDiscordAccountRepository implements DiscordAccountRepository }); if (events.length > 0) { - await tx.insert(discordAccountDomainEvents).values( + await client.insert(discordAccountDomainEvents).values( events.map((event) => ({ id: uuid(), discordId: event.discordId as string, diff --git a/src/infrastructure/drizzle/DrizzleEventRepository.ts b/src/infrastructure/drizzle/DrizzleEventRepository.ts index 432c098..b15e1e1 100644 --- a/src/infrastructure/drizzle/DrizzleEventRepository.ts +++ b/src/infrastructure/drizzle/DrizzleEventRepository.ts @@ -14,7 +14,7 @@ import { exhibitId, memberId, } from "#domain"; -import { type DrizzleClient, getClient } from "./client"; +import { type DrizzleClient, getClient, runInTransaction } from "./client"; import { events, exhibits, lightningTalks, memberEvents, memberExhibits } from "./schema"; // ============================================================================ @@ -101,45 +101,47 @@ export class DrizzleEventRepository implements EventRepository { // ========================================================================== private async persistEvent(event: Event): Promise { - const db = getClient(); - const snapshot = event.toSnapshot(); - const now = new Date().toISOString(); - const dateStr = snapshot.date instanceof Date ? snapshot.date.toISOString() : snapshot.date; - - // 1) Event upsert - await db - .insert(events) - .values({ - id: snapshot.id, - name: snapshot.name, - date: dateStr, - updatedAt: now, - }) - .onConflictDoUpdate({ - target: events.id, - set: { + await runInTransaction(async () => { + const client = getClient(); + const snapshot = event.toSnapshot(); + const now = new Date().toISOString(); + const dateStr = snapshot.date instanceof Date ? snapshot.date.toISOString() : snapshot.date; + + // 1) Event upsert + await client + .insert(events) + .values({ + id: snapshot.id, name: snapshot.name, date: dateStr, updatedAt: now, - }, - }); + }) + .onConflictDoUpdate({ + target: events.id, + set: { + name: snapshot.name, + date: dateStr, + updatedAt: now, + }, + }); - // 2) Find obsolete exhibits and clean up - const snapshotExhibitIds = snapshot.exhibits.map((ex) => ex.id); - await this.deleteObsoleteExhibits(db, snapshot.id, snapshotExhibitIds); + // 2) Find obsolete exhibits and clean up + const snapshotExhibitIds = snapshot.exhibits.map((ex) => ex.id); + await this.deleteObsoleteExhibits(client, snapshot.id, snapshotExhibitIds); - // 3) Upsert exhibits - for (const ex of snapshot.exhibits) { - await this.upsertExhibit(db, snapshot.id, ex); - } + // 3) Upsert exhibits + for (const ex of snapshot.exhibits) { + await this.upsertExhibit(client, snapshot.id, ex); + } - // 4) Sync member events - await this.syncMemberEvents(db, snapshot.id, event.getMemberIds()); + // 4) Sync member events + await this.syncMemberEvents(client, snapshot.id, event.getMemberIds()); - // 5) Sync member exhibits - for (const exhibitDomain of event.getExhibits()) { - await this.syncMemberExhibits(db, exhibitDomain.id, exhibitDomain.getMemberIds()); - } + // 5) Sync member exhibits + for (const exhibitDomain of event.getExhibits()) { + await this.syncMemberExhibits(client, exhibitDomain.id, exhibitDomain.getMemberIds()); + } + }); } private async deleteObsoleteExhibits( diff --git a/src/infrastructure/drizzle/DrizzleKarteRepository.ts b/src/infrastructure/drizzle/DrizzleKarteRepository.ts index 0366285..4736ecb 100644 --- a/src/infrastructure/drizzle/DrizzleKarteRepository.ts +++ b/src/infrastructure/drizzle/DrizzleKarteRepository.ts @@ -21,7 +21,7 @@ import { type Resolution, type SupportRecord, } from "#domain"; -import { getClient } from "./client"; +import { getClient, runInTransaction } from "./client"; import { karteAssignees, kartes } from "./schema"; // ============================================================================ @@ -274,8 +274,6 @@ export class DrizzleKarteRepository implements KarteRepository { } async save(karte: Karte): Promise { - const db = getClient(); - const clientCols = clientToColumns(karte.client); const resCols = resolutionToColumns(karte.supportRecord.resolution); @@ -305,15 +303,16 @@ export class DrizzleKarteRepository implements KarteRepository { const { id: _, ...updateValues } = values; - await db.transaction(async (tx) => { + await runInTransaction(async () => { + const client = getClient(); // Upsert karte - await tx.insert(kartes).values(values).onConflictDoUpdate({ + await client.insert(kartes).values(values).onConflictDoUpdate({ target: kartes.id, set: updateValues, }); // Sync assignees (delete-all-then-insert) - await tx.delete(karteAssignees).where(eq(karteAssignees.karteId, karte.id as string)); + await client.delete(karteAssignees).where(eq(karteAssignees.karteId, karte.id as string)); if (karte.supportRecord.assignees.type === "recorded") { const assigneeRows = karte.supportRecord.assignees.value.map((assignee) => ({ @@ -322,7 +321,7 @@ export class DrizzleKarteRepository implements KarteRepository { memberId: assignee.type === "resolved" ? (assignee.memberId as string) : null, assigneeName: assignee.type === "unresolved" ? assignee.name : null, })); - await tx.insert(karteAssignees).values(assigneeRows); + await client.insert(karteAssignees).values(assigneeRows); } }); } diff --git a/src/infrastructure/drizzle/DrizzleMemberRepository.ts b/src/infrastructure/drizzle/DrizzleMemberRepository.ts index 144c8d1..a80fd68 100644 --- a/src/infrastructure/drizzle/DrizzleMemberRepository.ts +++ b/src/infrastructure/drizzle/DrizzleMemberRepository.ts @@ -16,7 +16,7 @@ import { type MemberRepository, type Recorded, } from "#domain"; -import { getClient } from "./client"; +import { getClient, runInTransaction } from "./client"; import { memberDomainEvents, members } from "./schema"; import { serializeMemberEventPayload } from "./serializeMemberEvent"; @@ -124,12 +124,12 @@ export class DrizzleMemberRepository implements MemberRepository { } async save(member: Member): Promise { - const db = getClient(); const values = toInsertValues(member); const events = member.getDomainEvents(); - await db.transaction(async (tx) => { - await tx + await runInTransaction(async () => { + const client = getClient(); + await client .insert(members) .values(values) .onConflictDoUpdate({ @@ -146,7 +146,7 @@ export class DrizzleMemberRepository implements MemberRepository { }); if (events.length > 0) { - await tx.insert(memberDomainEvents).values( + await client.insert(memberDomainEvents).values( events.map((event) => ({ id: uuid(), memberId: event.id as string, diff --git a/src/infrastructure/drizzle/client.ts b/src/infrastructure/drizzle/client.ts index d37edc2..af83232 100644 --- a/src/infrastructure/drizzle/client.ts +++ b/src/infrastructure/drizzle/client.ts @@ -1,24 +1,12 @@ /// import { AsyncLocalStorage } from "node:async_hooks"; -<<<<<<< HEAD import type { PgDatabase } from "drizzle-orm/pg-core"; import { drizzle } from "drizzle-orm/postgres-js"; import type { PostgresJsQueryResultHKT } from "drizzle-orm/postgres-js/session"; import postgres, { type Sql } from "postgres"; import * as schema from "./schema"; -export type DrizzleDb = PgDatabase; -======= -import type { NodePgQueryResultHKT } from "drizzle-orm/node-postgres"; -import { drizzle } from "drizzle-orm/node-postgres"; -import type { PgDatabase } from "drizzle-orm/pg-core"; -import { Pool } from "pg"; -import * as schema from "./schema"; - -export type DrizzleClient = PgDatabase; - -let pool: Pool | null = null; ->>>>>>> 6d5f1a6 (refactor: DrizzleClientをPgDatabase型で定義しトランザクションの強制キャストを除去) +export type DrizzleClient = PgDatabase; let sqlClient: Sql | null = null; @@ -34,23 +22,11 @@ function getSqlClient(): Sql { return sqlClient; } -<<<<<<< HEAD -<<<<<<< HEAD -function createDb() { - return drizzle(getSqlClient(), { schema }); -} - -const transactionContext = new AsyncLocalStorage(); -======= -function createClient() { -======= function createClient(): DrizzleClient { ->>>>>>> 6d5f1a6 (refactor: DrizzleClientをPgDatabase型で定義しトランザクションの強制キャストを除去) - return drizzle(getPool(), { schema }); + return drizzle(getSqlClient(), { schema }); } const transactionContext = new AsyncLocalStorage(); ->>>>>>> 91008a2 (refactor: getDb/createDb/DrizzleDb を getClient/createClient/DrizzleClient にリネーム) /** * Drizzleクライアントを取得する @@ -73,14 +49,6 @@ export function runInTransaction(fn: () => Promise): Promise { } const db = createClient(); return db.transaction(async (tx) => { -<<<<<<< HEAD -<<<<<<< HEAD - return transactionContext.run(tx, fn); -======= - return transactionContext.run(tx as unknown as DrizzleClient, fn); ->>>>>>> 91008a2 (refactor: getDb/createDb/DrizzleDb を getClient/createClient/DrizzleClient にリネーム) -======= return transactionContext.run(tx, fn); ->>>>>>> 6d5f1a6 (refactor: DrizzleClientをPgDatabase型で定義しトランザクションの強制キャストを除去) }); }