import { PrismaClient } from '@prisma/client';
import { faker } from '@faker-js/faker';
const prisma = new PrismaClient();
async function main() {
// Fixăm seed-ul pentru consistență în CI
faker.seed(42);
const adminEmail = 'admin@dev-community.ro';
await prisma.user.upsert({
where: { email: adminEmail },
update: {},
create: {
email: adminEmail,
name: faker.person.fullName(),
role: 'ADMIN',
posts: {
create: Array.from({ length: 3 }).map(() => ({
title: faker.lorem.sentence(),
content: faker.lorem.paragraphs(),
published: true,
})),
},
},
});
console.log('Seed completed successfully.');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});Salutare tuturor. Am trecut recent printr-un refactor pe partea de seed-uri la un proiect cu vreo 12 microservicii și mi-am adus aminte cât de multă lume ignoră partea asta până când crapă pipeline-ul de CI. De cele mai multe ori, seed-ul e tratat ca un cetățean de rangul doi, ceva ce scrii în 5 minute și uiți de el. Până când un coleg nou își face setup-ul și nimic nu merge.
Problema cu seed-urile clasice
Majoritatea începem cu un fișier seed.ts unde aruncăm niște prisma.user.create. Merge brici prima dată, pe o bază de date curată. A doua oară? Primești un frumos Unique constraint failed. Și uite așa începe distracția. Dacă ai un workflow de GitHub Actions care rulează teste de integrare, nu vrei să-ți crape build-ul doar pentru că baza de date n-a fost curățată perfect sau pentru că cineva a mai rulat seed-ul manual înainte.
Am pățit asta la un proiect cu peste 200 de teste de integrare unde seed-ul dura vreo 3 minute pentru că inseram totul bulk, fără nicio logică de verificare. Am redus timpul de execuție cu aproximativ 40% și am eliminat erorile de duplicare trecând la o strategie bazată pe upsert și ID-uri deterministe.
Strategia de Upsert
Regula de aur pe care am învățat-o pe pielea mea: un seed trebuie să fie idempotent. Adică trebuie să poți să-l rulezi de 100 de ori la rând și rezultatul să fie exact același, fără nicio eroare în consolă. În loc de create, folosesc mereu upsert. E un trade-off aici: scrii un pic mai mult cod pentru că trebuie să definești where, update și create, dar dormi mult mai liniștit noaptea.
La un proiect cu vreo 8k useri simulați, folosirea upsert-ului pe un câmp de email ne-a salvat de zeci de intervenții manuale în baza de date de staging. E mult mai sănătos să zici: „dacă userul admin există deja, doar asigură-te că are rolul de ADMIN”, decât să încerci să-l ștergi și să-l recreezi, riscând să strici relațiile cu alte tabele din cauza constrângerilor de foreign key.
Date care arată a realitate cu Faker
Nimic nu e mai enervant pentru un developer de frontend decât să lucreze cu date de tip test-user-1, test-user-2. Folosesc @faker-js/faker ca să generez nume, adrese și UUID-uri care chiar au sens. Dar atenție la o mare capcană: dacă folosești faker.seed(123), te asiguri că datele generate sunt aceleași la fiecare rulare.
E vital pentru testele de snapshot sau pentru momentele când vrei să reproduci un bug raportat pe un anumit ID. Dacă Faker scoate date random la fiecare execuție în CI, testele tale devin „flaky” și o să pierzi ore întregi căutând bug-uri care de fapt nu există în cod, ci doar în consistența datelor.
Integrarea în CI și performanța
În package.json, Prisma are câmpul dedicat pentru seed. Deși e tentant să-l pui să ruleze automat la fiecare prisma migrate deploy, eu prefer să-l țin sub control manual în scripturile de CI. În pipeline, rulez prisma db seed imediat după ce baza de date e ridicată și migrată.
Un alt mic truc: nu genera mii de înregistrări dacă nu testezi activ performanța. Pentru un mediu de development sau CI, 10-20 de rânduri per tabelă sunt arhisuficiente. Am văzut pipeline-uri care stăteau 5 minute doar să bage date inutile în Postgres, lungind feedback loop-ul pentru toată echipa fără niciun beneficiu real.
Voi ce abordare aveți pentru datele de test? Mergeți pe varianta de dump-uri SQL luate din producție (anonimizate, sper!) sau aveți seed-uri complexe în TypeScript care oglindesc logica de business?