Repository
Base class for creating database repositories with swappable database context.
Repository Class
import { Repository } from '@repo/db'
class OrderRepository extends Repository<typeof getDbContext> {
async getById(id: string) {
const { db, orders } = await this.getDbContext()
return db.query.orders.findFirst({ where: eq(orders.id, id) })
}
async create(values: typeof orders.$inferInsert) {
const { db, orders } = await this.getDbContext()
return db.insert(orders).values(values).returning()
}
}
const orderRepo = new OrderRepository(getDbContext)
The constructor takes a getDbContext function. All repository methods call this.getDbContext() to obtain the database instance and schema tables.
withDb
Creates a new repository instance bound to a different database context. The original instance is unchanged.
withDb(customGetDb?: Fn): this
Returns this if customGetDb is undefined (no-op). Otherwise returns a new instance of the same subclass with the overridden context.
Use Cases
Transactions -- bind a repository to a transaction:
await db.transaction(async (tx) => {
const txOrderRepo = orderRepo.withDb(() => ({ db: tx, ...schema }))
const txUserRepo = userRepo.withDb(() => ({ db: tx, ...schema }))
await txOrderRepo.create({ userId: '1', total: 100 })
await txUserRepo.updateBalance('1', -100)
})
Testing -- inject a test database:
const testRepo = orderRepo.withDb(() => ({ db: testDb, ...schema }))
Hooked database -- combine with wrapDbWithHooks:
const hookedContext = wrapDbWithHooks(getDbContext, hooks)
const hookedRepo = orderRepo.withDb(hookedContext)