/** * Database seeding utilities. * * @module @kysera/testing */ import type { Kysely, Transaction } from 'kysely' /** * Seed database with test data. * * Executes the seeding function within a transaction. * If the seeding function throws, the transaction is rolled back. * * @param db - Kysely database instance * @param fn - Seeding function that receives a transaction * * @example * ```typescript * import { seedDatabase } from '@kysera/testing'; * * beforeAll(async () => { * await seedDatabase(db, async (trx) => { * // Insert test users * await trx * .insertInto('users') * .values([ * { email: 'alice@example.com', name: 'Alice' }, * { email: 'bob@example.com', name: 'Bob' }, * ]) * .execute(); * * // Insert related data * await trx * .insertInto('posts') * .values([ * { user_id: 1, title: 'First Post' }, * ]) * .execute(); * }); * }); * ``` */ export async function seedDatabase( db: Kysely, fn: (trx: Transaction) => Promise ): Promise { await db.transaction().execute(fn) } /** * Seed function type for reusable seeders. */ export type SeedFunction = (trx: Transaction) => Promise /** * Create a composable seeder. * * Allows combining multiple seeders into one. * * @param seeders - Array of seed functions * @returns Combined seed function * * @example * ```typescript * import { composeSeeders, seedDatabase } from '@kysera/testing'; * * const seedUsers: SeedFunction = async (trx) => { * await trx.insertInto('users').values([...]).execute(); * }; * * const seedPosts: SeedFunction = async (trx) => { * await trx.insertInto('posts').values([...]).execute(); * }; * * const seedAll = composeSeeders([seedUsers, seedPosts]); * * beforeAll(async () => { * await seedDatabase(db, seedAll); * }); * ``` */ export function composeSeeders(seeders: SeedFunction[]): SeedFunction { return async (trx: Transaction): Promise => { for (const seeder of seeders) { await seeder(trx) } } }