Skip to main content
version 1.0.0

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()