Named States
Define factory variants using named states with f.State() and apply them with f.WithState().
Named States
Named states let you define variants of a factory that override specific fields. This is useful for creating different "types" of the same struct — like an admin user, an unverified account, or a published post.
Defining States
Use f.State() to register a named state on a factory. The state receives a factory.Faker and the base instance, and returns a modified instance with the desired overrides:
f.State(name string, fn func(faker factory.Faker, base T) T)| Method | Purpose |
|---|---|
f.State(name, fn) | Registers a named state modifier that receives the base instance |
f.WithState(name) | Returns a new factory that applies the named state on Make |
Example: User States
package factories
import (
"github.com/gopackx/go-migration/seeder/factory"
)
type User struct {
ID int
Name string
Email string
Role string
Verified bool
}
var UserFactory = factory.NewFactory(func(f factory.Faker) User {
return User{
ID: f.IntBetween(1, 10000),
Name: f.Name(),
Email: f.Email(),
Role: "user",
Verified: true,
}
})
func init() {
// Admin state — overrides Role to "admin"
UserFactory.State("admin", func(f factory.Faker, base User) User {
base.Role = "admin"
return base
})
// Unverified state — overrides Verified to false
UserFactory.State("unverified", func(f factory.Faker, base User) User {
base.Verified = false
return base
})
}Applying States
Use WithState() to get a factory that produces instances using the named state's builder:
// Default user — Role: "user", Verified: true
user := UserFactory.Make()
// Admin user — Role: "admin", Verified: true
admin := UserFactory.WithState("admin").Make()
// Unverified user — Role: "user", Verified: false
unverified := UserFactory.WithState("unverified").Make()WithState() returns a new factory instance, so the original factory remains unchanged.
Batch Generation with States
States work with MakeMany() for generating multiple instances:
// Generate 10 admin users
admins := UserFactory.WithState("admin").MakeMany(10)
// Generate 50 unverified users
unverifiedUsers := UserFactory.WithState("unverified").MakeMany(50)Using States in Seeders
States are especially useful in seeders where you need different data profiles:
package seeders
import (
"database/sql"
"fmt"
"myapp/factories"
)
type UserSeeder struct{}
func (s *UserSeeder) Run(db *sql.DB) error {
// Seed 5 admin users
admins := factories.UserFactory.WithState("admin").MakeMany(5)
for _, u := range admins {
_, err := db.Exec(
"INSERT INTO users (name, email, role, verified) VALUES ($1, $2, $3, $4)",
u.Name, u.Email, u.Role, u.Verified,
)
if err != nil {
return fmt.Errorf("failed to seed admin: %w", err)
}
}
// Seed 100 regular users
users := factories.UserFactory.MakeMany(100)
for _, u := range users {
_, err := db.Exec(
"INSERT INTO users (name, email, role, verified) VALUES ($1, $2, $3, $4)",
u.Name, u.Email, u.Role, u.Verified,
)
if err != nil {
return fmt.Errorf("failed to seed user: %w", err)
}
}
return nil
}States receive the base instance produced by the default definition, so you only need to override the fields you want to change.
What's Next?
- Make and MakeMany — generate single or batch instances from factories