ORM: Factories
Introduction
When testing your application or seeding your database, you may need to insert a few records into your database. Instead of manually specifying the value of each column,
Athenna allows you to define a set of default attributes for each of your models
using model factories.
Defining model factories
Before start using the static factory
method of models we need to define the static definition
method in our model. The definition
method returns the default set of attribute
values that should be applied when creating a model using the factory, let's use as example the User
model:
import { Model } from '@athenna/database'
export class User extends Model {
static definition() {
return {
name: this.faker.name.fullName(),
email: this.faker.internet.email(),
}
}
/*...*/
}
tip
As you can see, we are using the static faker
attribute to create fake data for our definition
method. This attribute is using the Faker library
,
that is very used in applications to generate massive amounts of fake (but realistic) data for testing and development. You can check their documentation to generated more
specific types of data.
Generating models using factories
Instantiating models
Once you have defined your static definition
method, you may use the static factory
method of your models in order to instantiate a factory instance for that model. Let's
take a look at a few examples of creating models. First, we'll use the make
method to create models without persisting them to the database:
import { User } from '#app/Models/User'
const user = await User.factory().make()
You may create an array of many models using the count
method:
const users = await User.factory().count(3).make()
Overriding attributes
If you would like to override some default values of your models, you may pass a record of values to the make
method. Only the specified attributes will be replaced while
the rest of the attributes remain set to their default values as specified by the static definition
method of your model:
const user = await User.factory()
.make({
email: 'danrley.morais@kadabra.school'
})
Persisting models
The create
method instantiates model instances and persists them to the database:
// Create a single User instance
const user = await User.factory().create()
// Create three User instances
const users = await User.factory().count(3).create()
Generating soft deleted models
If your model can be softly deleted, you may invoke the built-in trashed
state method to indicate that the created model should already be "soft deleted":
const user = await User.factory().trashed().make()
const user = await User.factory().trashed().create()
Defining relationships within factories
To define a relationship within your model factory, you will typically assign a new factory instance to the foreign key of the relationship. This is normally done for the
"inverse" relationships such as belongsTo
relationships. For example, if you would like to create a new user when creating a post, you may do the following:
import { User } from '#app/Models/User'
import { Model } from '@athenna/database'
export class Post extends Model {
static definition() {
const returningKey = 'id'
return {
title: this.faker.commerce.productName(),
userId: User.factory(returningKey)
}
}
/*...*/
}
warning
The returningKey
will be used to return that specific value when executing your relationship factory, check this example:
const returningKey = 'id'
// The "user.id" will be returned from the "create"
// method and assigned in the "userId" constant.
const userId = await User.factory(returningKey).create()