UNPKG

iagate-querykit

Version:

QueryKit: lightweight TypeScript query toolkit with models, views, triggers, events, scheduler and adapters (better-sqlite3).

114 lines (113 loc) 3.55 kB
import { getExecutorForTable } from './config'; import { QueryBuilder } from './query-builder'; /** * Classe base para seeds customizadas. * Implementa SeedRunnable com comportamento padrão vazio. * * @example * ```typescript * // Dados iniciais * class ProductSeed extends Seed<Product> { * async run(ctx: SeedContext): Promise<Partial<Product>[]> { * return [ * { name: 'Product A', price: 100 }, * { name: 'Product B', price: 200 } * ]; * } * } * * // Como usar * await runSeed('products', new ProductSeed()); * * // Output: Produtos inseridos no banco de dados * ``` */ export class Seed { /** * Método padrão que retorna array vazio. * Deve ser sobrescrito em classes filhas. * * @param _ctx - Contexto da execução (não usado na implementação padrão) * @returns Array vazio */ async run(_ctx) { return []; } } /** * Executa um seed em uma tabela específica. * Suporta dados diretos ou classes SeedRunnable. * Oferece opções para truncate, upsert e tratamento de duplicatas. * * @param table - Nome da tabela para executar o seed * @param dataOrSeed - Dados para inserir ou classe seed executável * @param opts - Opções de execução * @returns Promise que resolve com número de linhas inseridas * @throws Error se não houver executor configurado * * @example * ```typescript * // Dados iniciais * const userData = [ * { name: 'John Doe', email: 'john@example.com' }, * { name: 'Jane Smith', email: 'jane@example.com' } * ]; * * // Como usar * const insertedRows = await runSeed('users', userData, { * truncate: true, * uniqueBy: ['email'] * }); * * // Output: 2 (número de usuários inseridos) * ``` */ export async function runSeed(table, dataOrSeed, opts = {}) { const exec = getExecutorForTable(table); if (!exec) throw new Error('No executor configured for QueryKit'); if (opts.truncate) { if (exec.runSync) exec.runSync(`DELETE FROM ${table}`, []); else await exec.executeQuery(`DELETE FROM ${table}`, []); } let rows; if (Array.isArray(dataOrSeed)) rows = dataOrSeed; else { const ctx = { exec, qb: (t) => new QueryBuilder(t) }; const out = await dataOrSeed.run(ctx); rows = out || []; } if (!rows.length) return 0; // batch insert with optional conflict handling const uniqueKeys = (opts.uniqueBy || []); const shouldUpsert = !!opts.upsert; const shouldIgnore = !!opts.ignoreDuplicates; for (const row of rows) { if (uniqueKeys.length && shouldIgnore) { const attributes = {}; for (const key of uniqueKeys) attributes[String(key)] = row[String(key)]; const exists = await new QueryBuilder(table).whereAll(attributes).exists(); if (exists) continue; await new QueryBuilder(table).insert(row).make(); continue; } if (uniqueKeys.length && shouldUpsert) { const attributes = {}; const values = {}; for (const [k, v] of Object.entries(row)) { if (uniqueKeys.includes(k)) attributes[k] = v; else values[k] = v; } await new QueryBuilder(table).updateOrInsert(attributes, values).make(); continue; } await new QueryBuilder(table).insert(row).make(); } return rows.length; }