Skip to main content

Persistence

Save generated objects directly to databases through adapters.

Quick Start

import { Factory } from 'interface-forge';

// Set default adapter
const userFactory = new Factory<User>(factoryFn).withAdapter(
new MongooseAdapter(UserModel),
);

// Create and save to database
const user = await userFactory.create();
const users = await userFactory.createMany(10);

PersistenceAdapter Interface

interface PersistenceAdapter<T, R = T> {
create(data: T): Promise<R>;
createMany(data: T[]): Promise<R[]>;
}

Database Adapters

Mongoose (MongoDB)

import mongoose from 'mongoose';

class MongooseAdapter<T> implements PersistenceAdapter<T> {
constructor(private model: mongoose.Model<T>) {}

async create(data: T): Promise<T> {
const doc = new this.model(data);
return doc.save();
}

async createMany(data: T[]): Promise<T[]> {
return this.model.insertMany(data);
}
}

// Usage
const adapter = new MongooseAdapter(UserModel);
const factory = userFactory.withAdapter(adapter);

Prisma

import { PrismaClient } from '@prisma/client';

class PrismaAdapter<T> implements PersistenceAdapter<T> {
constructor(
private prisma: PrismaClient,
private model: keyof PrismaClient,
) {}

async create(data: T): Promise<T> {
return (this.prisma[this.model] as any).create({ data });
}

async createMany(data: T[]): Promise<T[]> {
const results = await Promise.all(
data.map((item) => this.create(item)),
);
return results;
}
}

// Usage
const adapter = new PrismaAdapter(prisma, 'user');

TypeORM

import { Repository } from 'typeorm';

class TypeORMAdapter<T> implements PersistenceAdapter<T> {
constructor(private repository: Repository<T>) {}

async create(data: T): Promise<T> {
const entity = this.repository.create(data);
return this.repository.save(entity);
}

async createMany(data: T[]): Promise<T[]> {
const entities = this.repository.create(data);
return this.repository.save(entities);
}
}

Methods

create()

Generate and persist single object:

// With default adapter
const user = await userFactory.create();

// With overrides
const admin = await userFactory.create({ role: 'admin' });

// With specific adapter
const user = await userFactory.create(
{ name: 'John' },
{ adapter: new CustomAdapter() },
);

createMany()

Generate and persist multiple objects:

// Simple batch
const users = await userFactory.createMany(10);

// With overrides
const admins = await userFactory.createMany(5, { role: 'admin' });

// Cycling overrides
const mixed = await userFactory.createMany(6, [
{ role: 'admin' },
{ role: 'user' },
{ role: 'guest' },
]);

Advanced Patterns

Multiple Adapters

class UserService {
constructor(
private mongoAdapter: MongooseAdapter<User>,
private postgresAdapter: PrismaAdapter<User>,
) {}

async createInMongo(userData: Partial<User>) {
return userFactory.create(userData, {
adapter: this.mongoAdapter,
});
}

async createInPostgres(userData: Partial<User>) {
return userFactory.create(userData, {
adapter: this.postgresAdapter,
});
}
}

Transactions

class TransactionalAdapter<T> implements PersistenceAdapter<T> {
constructor(
private prisma: PrismaClient,
private model: keyof PrismaClient,
private transaction?: any,
) {}

async create(data: T): Promise<T> {
const client = this.transaction || this.prisma;
return (client[this.model] as any).create({ data });
}
}

// Usage with transaction
await prisma.$transaction(async (tx) => {
const adapter = new TransactionalAdapter(prisma, 'user', tx);
const users = await userFactory.createMany(5, {}, { adapter });
// All users created in same transaction
});

Seeding

async function seedDatabase() {
// Create admins
const admins = await userFactory.createMany(3, {
role: 'admin',
isActive: true,
});

// Create users for each admin
for (const admin of admins) {
await userFactory.createMany(10, {
managerId: admin.id,
role: 'user',
});
}
}

Hooks Integration

Persistence works with factory hooks:

const factory = userFactory
.withAdapter(adapter)
.beforeBuild((data) => {
data.email = data.email?.toLowerCase();
return data;
})
.afterBuild(async (user) => {
await sendWelcomeEmail(user.email);
return user;
});

// Hooks execute during create operations
const user = await factory.create();

Error Handling

try {
const user = await userFactory.create();
} catch (error) {
if (error instanceof ConfigurationError) {
console.error('No adapter configured');
}
// Handle database errors
}