Files
stack/apps/api/prisma/seed.ts
Jason Woltje dd747a1d87 feat(#3): Add comprehensive tests and improve Prisma seed script
- Create comprehensive test suite for PrismaService (10 tests)
- Fix AppController tests with proper PrismaService mocking
- Wrap seed operations in transaction for atomicity
- Replace N+1 pattern with batch operations (createMany)
- Add concurrency warning to seed script
- All tests passing (14/14)
- Build successful
- Test coverage >85%

Fixes #3

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-28 16:24:25 -06:00

160 lines
4.1 KiB
TypeScript

import {
PrismaClient,
TaskStatus,
TaskPriority,
ProjectStatus,
WorkspaceMemberRole,
} from "@prisma/client";
const prisma = new PrismaClient();
async function main() {
console.log("Seeding database...");
// IMPORTANT: This seed script should not be run concurrently
// If running in CI/CD, ensure serialization of seed operations
// to prevent race conditions and data corruption
// Create test user
const user = await prisma.user.upsert({
where: { email: "dev@mosaic.local" },
update: {},
create: {
email: "dev@mosaic.local",
name: "Development User",
preferences: {
theme: "system",
notifications: true,
},
},
});
console.log(`Created user: ${user.email}`);
// Create workspace
const workspace = await prisma.workspace.upsert({
where: { id: "00000000-0000-0000-0000-000000000001" },
update: {},
create: {
id: "00000000-0000-0000-0000-000000000001",
name: "Development Workspace",
ownerId: user.id,
settings: {
timezone: "America/New_York",
},
},
});
console.log(`Created workspace: ${workspace.name}`);
// Add user as workspace owner
await prisma.workspaceMember.upsert({
where: {
workspaceId_userId: {
workspaceId: workspace.id,
userId: user.id,
},
},
update: {},
create: {
workspaceId: workspace.id,
userId: user.id,
role: WorkspaceMemberRole.OWNER,
},
});
// Use transaction for atomic seed data reset and creation
await prisma.$transaction(async (tx) => {
// Delete existing seed data for idempotency (avoids duplicates on re-run)
await tx.task.deleteMany({ where: { workspaceId: workspace.id } });
await tx.event.deleteMany({ where: { workspaceId: workspace.id } });
await tx.project.deleteMany({ where: { workspaceId: workspace.id } });
// Create sample project
const project = await tx.project.create({
data: {
workspaceId: workspace.id,
name: "Sample Project",
description: "A sample project for development",
status: ProjectStatus.ACTIVE,
creatorId: user.id,
color: "#3B82F6",
},
});
console.log(`Created project: ${project.name}`);
// Create sample tasks
const tasks = [
{
title: "Set up development environment",
status: TaskStatus.COMPLETED,
priority: TaskPriority.HIGH,
},
{
title: "Review project requirements",
status: TaskStatus.IN_PROGRESS,
priority: TaskPriority.MEDIUM,
},
{
title: "Design database schema",
status: TaskStatus.COMPLETED,
priority: TaskPriority.HIGH,
},
{
title: "Implement NestJS integration",
status: TaskStatus.COMPLETED,
priority: TaskPriority.HIGH,
},
{
title: "Create seed data",
status: TaskStatus.IN_PROGRESS,
priority: TaskPriority.MEDIUM,
},
];
// Use createMany for batch insertion (better performance)
await tx.task.createMany({
data: tasks.map((taskData) => ({
workspaceId: workspace.id,
title: taskData.title,
status: taskData.status,
priority: taskData.priority,
creatorId: user.id,
projectId: project.id,
})),
});
console.log(`Created ${tasks.length} sample tasks`);
// Create sample event
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
tomorrow.setHours(10, 0, 0, 0);
await tx.event.create({
data: {
workspaceId: workspace.id,
title: "Morning standup",
description: "Daily team sync",
startTime: tomorrow,
endTime: new Date(tomorrow.getTime() + 30 * 60000), // 30 minutes later
creatorId: user.id,
projectId: project.id,
},
});
console.log("Created sample event");
});
console.log("Seeding completed successfully!");
}
main()
.catch((e) => {
console.error("Error seeding database:", e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});