WORK IN PROGRESS
Seedr, being heavily inspired by Factory Girl, allows to easily declare factories, insert records into database (optional) and initialize objects (structs) from those newly created records.
- MySQL
Let's assume we have MySQL database testdb
with users
table:
create table users (
id int(10) unsigned not null auto_increment,
name varchar(250) not null,
sex varchar(10),
age int(5) unsigned,
created_at datetime not null default NOW(),
primary key (id)
) engine=InnoDB default charset=utf8;
Basic seedr usage:
package whatever
import (
"database/sql"
"time"
_ "github.com/go-sql-driver/mysql"
. "github.com/josephbuchma/seedr" // dot import for convenience.
"github.com/josephbuchma/seedr/driver/sql/mysql"
)
// Define 'users' factory
var users = Factory{
FactoryConfig{
// Entity is a MySQL table name in this case
Entity: "users",
PrimaryKey: "id",
},
// to see relations in action check out tests and docs (links below)
Relations{},
// Traits are different variations of user.
// Each field of trait must be same as name of field in `users` table.
Traits{
"base": {
// Auto means that this field will be initialized by driver (DB)
"id": Auto(),
"name": SequenceString("John-%d"), // produces John-1, John-2, John-3...
"age": nil, // nil -> NULL
"sex": nil,
"created_at": Func(func()interface{}{ return time.Now() }),
},
"old": {
"age": 80,
},
"young": {
"age": 15,
},
"male": {
"sex": "male",
},
"female": {
"sex": "female",
},
"User": {
Include: "base",
},
"OldWoman": {
Include: "base old female", // traits can be combined using include
"name": "Ann", // you can override any field
},
"YoungMan": {
Include: "base young male",
},
"User9999": {
Include: "base",
"id": 9999,
},
},
}
// Create new Seedr (usually you'll do it in separate file,
// so New() will be seedr.New()
var testdb = New("test_seedr",
SetCreateDriver(mysql.New(openTestDB())), // configure MySQL driver (openTestDB is at the end)
// field mapper is used for mapping trait fields to struct fields.
// In this case seedr will look for `sql:"column_name"` tag, and if it's not
// provided it'll fall back to SnakeFieldMapper, which converts struct field
// name to snake case.
SetFieldMapper(
TagFieldMapper("sql", seedr.SnakeFieldMapper()),
),
).Add("users", users) // add users factory
// Create some records
func test() {
var u User
var users []User
// Lines below are doing exactly what you're thinking (creating records in DB and initializing objects)
// And yes, you can only create traits that starts with
// capital letter (other traits are "private" to the factory,
// and can only be included by other traits in this factory)
testdb.Create("User").Scan(&u)
testdb.Create("User9999").Scan(&u)
testdb.CreateBatch("OldWoman", 10).Scan(&users)
testdb.CreateCustom("User", Trait{
"name": "Mike",
"age": 22,
}).Scan(&u)
testdb.CreateCustomBatch("User", 4, Trait{
"name": "Mike",
"age": 22,
}).Scan(&users)
// You can also only "build" the object, without inserting to DB
testdb.Build("User").Scan(&u) // u.ID == 0
}
// User model
type User struct {
ID int `sql:"id"`
Name string `sql:"name"`
Age *int `sql:"age"`
Sex *string `sql:"sex"`
CreatedAt time.Time `sql:"created_at"`
}
func openTestDB() *sql.DB {
db, err := sql.Open("mysql", "root:@/testdb?parseTime=true")
if err != nil {
panic(err)
}
return db
}
To see how to work with relations and other features, check out tests and docs