Seeds & Factories

Once you have got your database schema ready with migrations, the next step is to add some data to get started. It is where database seeds and factories comes into the picture.

Seeds

Seeds are Javascript classes with a run method on them. You are free to write any database related operation inside this method.

Just like migrations, a seed file can also be created using the adonis make command.

adonis make:seed User
Output
✔ create  database/seeds/UserSeeder.js

Now open this file and type the following code inside it.

const Factory = use('Factory')
const Database = use('Database')

class UserSeeder {
  async run () {
    const users = await Database.table('users')
    console.log(users)
  }
}

module.exports = UserSeeder

Run the seed file by calling adonis seed. It executes the run method on all the seed files.

Since you can write any database related code inside your seed files and execute them from the command line is helpful in off loading some tasks from your actual application code.

However, the real power of seeds is unlocked when you combine them with Factories.

Factories

The database factories are used to define a blueprint of a data structure and then using that blueprint to generate dummy data. Let’s check out this example.

The factory blueprints are defined inside database/factory.js file.

const Factory = use('Factory')

Factory.blueprint('App/Models/User', async (faker) => {
  return {
    username: faker.username(),
    password: await Hash.make(faker.password())
  }
})

Now every time you generate a model instance from this blueprint, it prefills the attributes from the keys we defined.

const user = await Factory
  .model('App/Models/User')
  .create()

Also, we can save multiple rows at a given point of time.

const usersArray = await Factory
  .model('App/Models/User')
  .createMany(5)

Creating relationships

It is so simple to use Lucid models and factories to setup associations. Let’s say we want to create a post and associate it with a user.

Make sure to define the posts relationship on the User model for this to work. Learn more about relationships here.

Post blueprint

Factory.blueprint('App/Models/Post', (faker) => {
  return {
    title: faker.sentence(),
    body: faker.paragraph()
  }
})

User blueprint

Factory.blueprint('App/Models/User', (faker) => {
  return {
    username: faker.username(),
    password: faker.password()
  }
})

Now let’s use these blueprints to create a user and associate posts with it.

const user = await Factory.model('App/Models/User').create()
const post = await Factory.model('App/Models/Post').make()

await user.posts().save(post)

If you would have noticed, we used the make method on the Post blueprint, this method does not persist the post inside the database and instead gives us an instance of Post model with pre-filled dummy data.

Available commands

Below is the list of available commands with their usage and description.

Command Options Description

adonis make:seed

None

Make a new seed file

adonis seed

--files

Execute seed files. Also, you can pass a comma separated list of files to be executed. Otherwise, all files get executed.

Usage without Lucid

You can also make use of Database provider if you have decided not to make use of Lucid models.

The blueprints are defined the same way, but instead, you make use of the table name over the model name.

Factory.blueprint('users', (faker) => {
  return {
    username: faker.username(),
    password: faker.password()
  }
})

Creating rows

The rows are created using the following factory methods.

run () {
  await Factory.get('users').create()
}

table

A different table name can also be defined at runtime.

await Factory
  .get('users')
  .table('my_users')
  .create()

returning

For PostgreSQL, you can also define a returning column

await Factory
  .get('users')
  .returning('id')
  .create()

connection

Choose a different connection at runtime.

await Factory
  .get('users')
  .connection('mysql')
  .returning('id')
  .create()

createMany

Create multiple rows

await Factory
  .get('users')
  .createMany(3)

Model factories API

Below is the list of available methods when you are using Lucid models via Factory.

create

Persist and return model instance

await Factory
  .model('App/Model/User')
  .create()

createMany

Persist and return many model instances

await Factory
  .model('App/Model/User')
  .createMany()

make

Return model instance with prefilled dummy data and do not persist it to the database.

await Factory
  .model('App/Model/User')
  .make()

makeMany

Return an array of model instances with prefilled dummy data and do not persist them to the database.

await Factory
  .model('App/Model/User')
  .makeMany(3)

Custom data

All methods make, makeMany, create and createMany accepts a custom data object, which is passed directly to the blueprints. For example

const user = await Factory
  .model('App/Models/User')
  .create({ status: 'admin' })

Now inside your blueprint, you can consume it as follows.

Factory.blueprint('App/Models/User', async (faker, i, data) => {
  return {
    username: faker.username(),
    status: data.status
  }
})

Faker API

The faker object passed to factory blueprint is a reference to chancejs library. Make sure to read their documentation for the list of available methods and properties.

FAQ’s

Since factories and seeds fit into many different use cases, the chances are you may get confused on how and when to use them. So here is the list of some frequently asked questions.

  1. Does factories and seeds have to be used together?
    No. Factories and seeds are not dependent upon each other and can be used independently.
    For example, you can make use of seed files to import data from a different app to Adonisjs app.

  2. Can I use factories when writing tests?
    Yes. Just import the factory provider and use it.

  3. How to run only selected seed files?
    You can pass --files with a list of comma separated file names to adonis seed command. It makes sure to run only those files.

    adonis seed --files='UsersSeeder.js, PostsSeeder.js'