Skip to content

debugger84/sqlc-fixture

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

SQLc plugin generation of fixtures

This plugin helps you to create objects that control data in your tests. These objects are called fixtures. They are used to create, and cleanup data in the database.

Installation

First of all you need to install the SQLc code generator. You can find the installation instructions here.

After that you need to install the plugin. You can do it by running the following command:

git clone [email protected]:debugger84/sqlc-fixture.git
cd sqlc-fixture
make all

Then you need to configure your sqlc.yaml file to use the plugin. You can find the configuration instructions here. For example, you can add the following lines to your sqlc.yaml file:

version: '2'

plugins:
  - name: fixture
    process:
      ## The path to the sqlc-fixture binary
      cmd: "../sqlc-fixture/bin/sqlc-fixture"

  - name: golang
    ## The path to the sqlc-gen-go wasm fork. 
    ## This fork improves the names of the generated structs if they are in different PostgreSQL schemas.
    ## But you can use the original sqlc-gen-go wasmas well.
    wasm:
      url: "https://github.com/debugger84/sqlc-gen-go/releases/download/v1.3.1/sqlc-gen-go.wasm"
      sha256: "fe6e5a2b75153ecba02b0c30bf4a11db2120bef537b650299473da133d272bf4"
sql:
  - schema:
    - "migration"
    - "../types/migration"
    queries: "queries"
    engine: "postgresql"

    codegen:
      - plugin: fixture
        ## The path to the generated code. Should be the same as the path in the golang plugin.
        out: "./"
        options:
          ## The package name for the generated code. 
          ## In this case the all fuxtures will be added to the subfolder "fixture" 
          ## instead of storing in the same folder as other generated files.
          package: "fixture"
          ## The package name for the generated by golang plugin models.
          ## Should be set up if the "package" option is configured previously.
          model_import: "sqlc-gen-test/test"
          ## The primary keys columns that should be used in the fixtures.
          ## If the primary key is not named as "id" you need to specify it here.
          primary_keys_columns:
            - "user.name"
          ## All the next options should be the same as in the "golang" plugin. 
          sql_package: "pgx/v5"
          default_schema: "test"
          overrides:
            - db_type: "uuid"
              nullable: true
              engine: "postgresql"
              go_type:
                import: "github.com/gofrs/uuid"
                package: "uuid"
                type: "NullUUID"
            - db_type: "uuid"
              nullable: false
              engine: "postgresql"
              go_type:
                import: "github.com/gofrs/uuid"
                package: "uuid"
                type: "UUID"

      - plugin: golang
        out: "./"
        options:
          package: "test"
          sql_package: "pgx/v5"
          default_schema: "test"
          exclude:
            - "User.createdAt"
            - "UpdateStatusInput.id"
          ## The same overrides as in the "fixture" plugin. 
          ## If you wish to change some types, you need to do it in both plugins.
          overrides:
            - db_type: "uuid"
              nullable: true
              engine: "postgresql"
              go_type:
                import: "github.com/gofrs/uuid"
                package: "uuid"
                type: "NullUUID"
            - db_type: "uuid"
              nullable: false
              engine: "postgresql"
              go_type:
                import: "github.com/gofrs/uuid"
                package: "uuid"
                type: "UUID"

Usage

After you have configured the plugin you can run the sqlc code generator as usual:

sqlc generate

The plugin will generate the fixtures for each table in the database. The fixtures will be stored in the subfolder "fixtures" in the package you have configured in the sqlc.yaml file.

For example, if you have the following table in the database:

CREATE TABLE users (
    id uuid PRIMARY KEY,
    name TEXT NOT NULL,
    email TEXT NOT NULL
);

The plugin will generate the following fixture:

// Code generated by sqlc-fixture plugin for SQLc. DO NOT EDIT.

package fixture

import (
	"context"
	uuid "github.com/gofrs/uuid"
	"sqlc-gen-test/test"
	"testing"
)

type UserFixture struct {
	entity test.User
	db     test.DBTX
}

func NewUserFixture(db test.DBTX, defaultEntity test.User) *UserFixture {
	return &UserFixture{
		db:     db,
		entity: defaultEntity,
	}
}

func (f *UserFixture) ID(iD uuid.UUID) *UserFixture {
	c := f.clone()
	c.entity.ID = iD
	return c
}

func (f *UserFixture) Name(name string) *UserFixture {
	c := f.clone()
	c.entity.Name = name
	return c
}

func (f *UserFixture) Email(email string) *UserFixture {
	c := f.clone()
	c.entity.Email = email
	return c
}

func (f *UserFixture) clone() *UserFixture {
	return &UserFixture{
		db:     f.db,
		entity: f.entity,
	}
}

func (f *UserFixture) save(ctx context.Context) error {
	query := `INSERT INTO users
            (id, name, email)
            VALUES ($1, $2, $3)
            RETURNING id, name, email
        `
	row := f.db.QueryRow(ctx, query,
		f.entity.ID,
		f.entity.Name,
		f.entity.Email,
	)
	err := row.Scan(
		&f.entity.ID,
		&f.entity.Name,
		&f.entity.Email,
	)
	return err
}

func (f *UserFixture) GetEntity() test.User {
	return f.entity
}

func (f *UserFixture) Create(tb testing.TB) *UserFixture {
	err := f.save(context.Background())
	if err != nil {
		tb.Fatalf("failed to create User: %v", err)
	}
	f.Cleanup(tb)
	c := f.clone()
	return c
}

func (f *UserFixture) Cleanup(tb testing.TB) {
	tb.Cleanup(
		func() {
			query := `DELETE FROM users WHERE id = $1`
			_, err := f.db.Exec(context.Background(), query, f.entity.ID)

			if err != nil {
				tb.Fatalf("failed to cleanup User: %v", err)
			}
		})
}

func (f *UserFixture) PullUpdates(tb testing.TB) *UserFixture {
	c := f.clone()
	ctx := context.Background()
	query := `SELECT * FROM users WHERE id = $1`
	row := f.db.QueryRow(ctx, query,
		c.entity.ID,
	)

	err := row.Scan(
		&c.entity.ID,
		&c.entity.Name,
		&c.entity.Email,
	)
	if err != nil {
		tb.Fatalf("failed to actualize data User: %v", err)
	}
	return c
}

You can use the fixtures in your tests as follows:

  1. Create the main test file where all tests dependencies will be initialized. Initialize the database connection and the fixtures for the tables you need to test.
package test_test

import (
	"context"
	"github.com/gofrs/uuid"
	"github.com/jackc/pgx/v5"
	"log"
	"sqlc-gen-test/test"
	"sqlc-gen-test/test/fixture"
	"testing"
)

var testFixture *fixture.UserFixture

func TestMain(m *testing.M) {
	// Initialize the database connection
	ctx := context.Background()
	db, err := pgx.Connect(ctx, "postgres://postgres:[email protected]:5432/test?sslmode=disable")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close(ctx)

	// Initialize the fixtures with the fields that the same in all tests of a package 
	testFixture = fixture.NewUserFixture(
		db, test.User{
			ID: uuid.Must(uuid.NewV4()),
		},
	)
	m.Run()
}
  1. Write a test where you need to create a new user in the database.
package test_test

import (
	"github.com/stretchr/testify/assert"
	"testing"
)

func TestFixture(t *testing.T) {
	// testFixture is initialized in the TestMain function
	created := testFixture.
		// Add fields to the fixture that are relevant for this test
		// Don't worry. The fixture is developed as an immutable object. 
		// So setting the fields will create the cole of an object and not change the original fixture.
		Email("[email protected]").
		// Create the entity in the database
		// After finishing the test, the entity will be deleted automatically
		Create(t)

	// Do any logic with the created entity inside tested code
	//....

	// Pull the data from the database to fixture
	checkedEntity := created.PullUpdates(t).GetEntity()
	assert.Equal(t, checkedEntity.Email, "[email protected]")
}

About

Db fixtures generator based on SQLc library.

Resources

License

Stars

Watchers

Forks

Packages

No packages published