Skip to content

Commit

Permalink
update readme
Browse files Browse the repository at this point in the history
  • Loading branch information
Goldziher committed Apr 22, 2022
1 parent 08ad6eb commit b96b8cb
Showing 1 changed file with 161 additions and 8 deletions.
169 changes: 161 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ type Person struct {
}
```

Since factories can be reused, its a good idea to define them in a specific package from which they can be imported. In
Since factories can be reused, it's a good idea to define them in a specific package from which they can be imported. In
the case of our imaginary app, this will be the `testhelpers` package:

```golang
Expand Down Expand Up @@ -114,20 +114,173 @@ import (
"github/someName/types"
)

var PersonFactory = fabricator.New[types.Person](types.Person{}, fabricator.Options[Person]{
var PersonFactory = fabricator.New[types.Person](types.Person{}, fabricator.Options[types.Person]{
Defaults: map[string]any{
"FirstName": "Moishe",
"LastName": "Zuchmir",
"Pets": []types.Pet{
{
"Flippy",
"Dolphin",
},
"Pets": func(iteration int, fieldName string) interface{} {
pets := []types.Pet{}
if iteration%2 == 0 {
pets = append(pets, types.Pet{
"Flippy",
"Dolphin",
})
}
return pets
},
},
})
```

As you can see above, the factory receives a `Defaults` object that maps struct field names, as map keys, to either
pre-specified values, or factory functions.

While factory functions are more verbose, they are a powerful way to generate data and they can of course be shared
across different fields or even different factories.

The signature for a factory function is `func(iteration int, fieldName string) interface{}`, with `iteration` being the
current value of the factory's internal counter, and `fieldName` being the name of the specific struct field for which a
value is being generated.

### Persistence Handler

When defining a factory, you can pass a `PersistenceHandler`, that is, a struct conforming to
the `fabricator.PersistenceHandler` interface:

```golang
package fabricator

type PersistenceHandler[T any] interface {
Save(instance T) T
SaveMany(instance []T) []T
}
```

With a persistence handler defined for the factory, you can call the `.Create` and `.CreateBatch` methods which build
and then persist the data in one command. For example:

```golang
package testhelpers

import (
"github.com/Goldziher/fabricator"

"github/someName/db"
"github/someName/types"
)

type MyPersistenceHandler[T any] struct{}

func (handler MyPersistenceHandler[T]) Save(instance T) T {
db.Create(&instance)
return instance
}

func (handler MyPersistenceHandler[T]) SaveMany(instances []T) []T {
db.Create(&instances)
return instances
}

var PersonFactory = fabricator.New[types.Person](types.Person{}, fabricator.Options[types.Person]{
PersistenceHandler: MyPersistenceHandler[types.Person]{},
})
```

## Factory Methods

Once a factory is defined it exposes the following methods:

### Build

Build is the
`func (factory *Factory[T]) Build(overrides ...map[string]any) T`

Build creates a single instance of the factory's model:

```golang
package test_something

import (
"testing"

"github/someName/testhelpers"
)

func TestSomething(t *testing.T) {
person := testhelpers.PersonFactory.Build()
// ...
}
```

You can pass to build a mapping of override values, this works exactly like the factory defaults, for example:

```golang
package test_something

import (
"testing"

"github/someName/types"
"github/someName/testhelpers"
)

func TestSomething(t *testing.T) {
person := testhelpers.PersonFactory.Build(map[string]any{
"FirstName": "Moishe",
"LastName": "Zuchmir",
"Pets": func(iteration int, fieldName string) interface{} {
pets := []types.Pet{}
if iteration%2 == 0 {
pets = append(pets, types.Pet{
"Flippy",
"Dolphin",
})
}
return pets
},
})
// ...
}
```

### Batch

`func (factory *Factory[T]) Batch(size int, overrides ...map[string]any) []T`

Batch builds a slice of instances of a given size:

```golang
package test_something

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

"github/someName/types"
"github/someName/testhelpers"
)

func TestSomething(t *testing.T) {
people := testhelpers.PersonFactory.Batch(5)
assert.Len(t, people, 5)
}
```

Note: You can pass to batch overrides the same as you can for build

### Create

`func (factory *Factory[T]) Create(overrides ...map[string]any) T`

If a factory defines a [Persistence Handler](#persistence-handler) you can use `.Create` to build and persist a model
instance. Create is identical to `.Build` in terms of its API.

### CreateBatch

`func (factory *Factory[T]) CreateBatch(size int, overrides ...map[string]any) []T`

If a factory defines a [Persistence Handler](#persistence-handler) you can use `.CreateBatch` to build and persist a
slice of model instances of a given size. CreateBatch is identical to `.Batch` in terms of its API.

## Contribution

This library is open to contributions. Please consult the [Contribution Guide](CONTRIBUTING.md).

0 comments on commit b96b8cb

Please sign in to comment.