Fixtures

You can use fixtures to load initial data into a database for testing or demonstration purposes. You can write fixtures in YAML format and load them on demand from tests or Go-based migrations.

Creating fixtures

A fixture is a plain YAML file with the ability to use text/templateFixtures - 图1open in new window expressions to generate values. Bun unmarshals YAML data into Go models using yaml.v3Fixtures - 图2open in new window and then saves the model in a database.

Here is how a fixture for a User model might look like:

  1. - model: User
  2. rows:
  3. - name: John Smith
  4. email: john@smith.com
  5. created_at: '{{ now }}'
  6. - name: Jonh Doe
  7. email: john@doe.com
  8. created_at: '{{ now }}'

A single fixture can contain data for multiple models. You can also use the _id field to name rows and reference them from other models using text/template syntax:

  1. - model: User
  2. rows:
  3. - _id: smith
  4. name: John Smith
  5. email: john@smith.com
  6. created_at: '{{ now }}'
  7. - _id: doe
  8. name: Jonh Doe
  9. email: john@doe.com
  10. created_at: '{{ now }}'
  11. - model: Org
  12. rows:
  13. - name: "{{ $.User.smith.Name }}'s Org"
  14. owner_id: '{{ $.User.smith.ID }}'
  15. - name: "{{ $.User.doe.Name }}'s Org"
  16. owner_id: '{{ $.User.doe.ID }}'

Loading fixtures

Assuming the fixture is stored in testdata/fixture.yml, you can load it with the following code:

  1. // Let the db know about the models.
  2. db.RegisterModel((*User)(nil), (*Org)(nil))
  3. fixture := dbfixture.New(db)
  4. err := fixture.Load(ctx, os.DirFS("testdata"), "fixture.yml")

By using fixture.WithRecreateTables() option, you can make bun drop existing tables and replace them with new ones. Or you can use fixture.WithTruncateTables() option to truncate tables.

  1. fixture := dbfixture.New(db, dbfixture.WithRecreateTables())
  2. fixture := dbfixture.New(db, dbfixture.WithTruncateTables())

You can also register and use in fixtures custom template functions:

  1. funcMap := template.FuncMap{
  2. "now": func() string {
  3. return time.Now().Format(time.RFC3339Nano)
  4. },
  5. }
  6. fixture := dbfixture.New(db, dbfixture.WithTemplateFuncs(funcMap))

Retrieving fixture data

Later you can retrieve the loaded models using Row and MustRow methods:

  1. fmt.Println("Smith", fixture.MustRow("User.smith").(*User))

You can also retrieve rows without _id field by a primary key:

  1. fmt.Println("Org with id=1", fixture.MustRow("Org.pk1").(*Org))

Field names

Bun uses SQL column names to find the matching struct field and then calls yaml.v3Fixtures - 图3open in new window to unmarshal the data. So when unmarshaling into a struct field, you may need to use yaml tag to override the default YAML field name.

  1. type User struct {
  2. ID int64 `bun:",pk,autoincrement"`
  3. Params UserParams `bun:"type:jsonb"`
  4. }
  5. type UserParams struct {
  6. Param1 string `yaml:"param1"`
  7. Param2 string `yaml:"param2"`
  8. }

Source code

You can find the source code for the example above on GitHubFixtures - 图4open in new window.