Compare commits
18 Commits
v1.1.0
...
new/insert
Author | SHA1 | Date | |
---|---|---|---|
77b8bdf218 | |||
2161c201bc | |||
935285a9f3 | |||
5f24529730 | |||
5563e93efd | |||
d0ec9465e2 | |||
0c4a1abb9a | |||
791ffad0e3 | |||
2415af38b2 | |||
053f5b5fd8 | |||
6326711424 | |||
6a9cdafcf1 | |||
5e2ddecdcc | |||
9033530a55 | |||
6bbb452b03 | |||
21b1291dbc | |||
c62da47a31 | |||
ff62b371c9 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,3 +25,5 @@ go.work.sum
|
||||
# env file
|
||||
.env
|
||||
|
||||
#ignore test files
|
||||
cmd/
|
118
lazy.go
118
lazy.go
@@ -17,51 +17,69 @@ const (
|
||||
KEY_VALUE = "key" //tag value for LAZY_TAG
|
||||
)
|
||||
|
||||
var (
|
||||
ErrBadExample = errors.New("example field must be a non-nil struct")
|
||||
ErrMissingKeys = errors.New("there must be a key for each row requested with RowCount")
|
||||
//contains placeholder to inject type on runtime
|
||||
ErrUnsupportedType = errors.New("type: %s is not yet supported")
|
||||
)
|
||||
|
||||
// mock data generated based on config
|
||||
type Mock struct {
|
||||
type RowMock struct {
|
||||
Query string
|
||||
Columns []string
|
||||
Rows [][]driver.Value
|
||||
}
|
||||
|
||||
// configuration for RandomGenerate
|
||||
type Config struct {
|
||||
type RowConfig struct {
|
||||
Query string
|
||||
Example any
|
||||
Keys []any //length of keys must = RowCount, if set
|
||||
Keys []any
|
||||
RowCount int
|
||||
}
|
||||
|
||||
// generates mock data based on configuration to be used for sqlmock
|
||||
func RandomGenerate(m Config) (*Mock, error) {
|
||||
//example struct cannot be nil and must be a struct
|
||||
if m.Example == nil {
|
||||
return nil, errors.New("example value cannot be nil")
|
||||
type StructConfig struct {
|
||||
Query string
|
||||
Example any
|
||||
RowCount int
|
||||
}
|
||||
if reflect.ValueOf(m.Example).Kind() != reflect.Struct {
|
||||
return nil, errors.New("example value must be a struct")
|
||||
|
||||
type StructMock struct {
|
||||
Query string
|
||||
MockStructs []any
|
||||
}
|
||||
|
||||
// generates mock data based on configuration to be used for sqlmock
|
||||
func RandomRows(r RowConfig) (*RowMock, error) {
|
||||
//example struct cannot be nil and must be a struct
|
||||
if r.Example == nil {
|
||||
return nil, ErrBadExample
|
||||
}
|
||||
if reflect.ValueOf(r.Example).Kind() != reflect.Struct {
|
||||
return nil, ErrBadExample
|
||||
}
|
||||
|
||||
//any weirdness, just pull one row
|
||||
if m.RowCount <= 0 {
|
||||
m.RowCount = 1
|
||||
if r.RowCount <= 0 {
|
||||
r.RowCount = 1
|
||||
}
|
||||
|
||||
//if keys are set, ensure there are enough to populate requested rows
|
||||
primaryKey := false
|
||||
if len(m.Keys) > 0 {
|
||||
if len(r.Keys) > 0 {
|
||||
primaryKey = true
|
||||
if len(m.Keys) != m.RowCount {
|
||||
return nil, errors.New("you must provide a key for each row")
|
||||
if len(r.Keys) != r.RowCount {
|
||||
return nil, ErrMissingKeys
|
||||
}
|
||||
}
|
||||
|
||||
retType := reflect.TypeOf(m.Example)
|
||||
retType := reflect.TypeOf(r.Example)
|
||||
maxFieldCount := retType.NumField()
|
||||
columns := make([]string, 0, maxFieldCount)
|
||||
rows := make([][]driver.Value, 0)
|
||||
|
||||
for y := 0; y < m.RowCount; y++ {
|
||||
for y := 0; y < r.RowCount; y++ {
|
||||
rows = append(rows, make([]driver.Value, 0))
|
||||
for x := 0; x < maxFieldCount; x++ {
|
||||
field := retType.Field(x)
|
||||
@@ -77,29 +95,85 @@ func RandomGenerate(m Config) (*Mock, error) {
|
||||
|
||||
//if field has lazy:"key" tag and tags are present inject primary key
|
||||
if field.Tag.Get(LAZY_TAG) == KEY_VALUE && primaryKey {
|
||||
rows[y] = append(rows[y], m.Keys[y])
|
||||
rows[y] = append(rows[y], r.Keys[y])
|
||||
continue
|
||||
}
|
||||
|
||||
//generate random values
|
||||
nv := kindToRandom(field)
|
||||
if nv == nil {
|
||||
return nil, fmt.Errorf("could not match type: %s", retType.Name())
|
||||
return nil, fmt.Errorf(ErrUnsupportedType.Error(), field.Type.Name())
|
||||
}
|
||||
|
||||
rows[y] = append(rows[y], nv)
|
||||
}
|
||||
}
|
||||
|
||||
return &Mock{
|
||||
return &RowMock{
|
||||
//sql is rebound and escaped for sqlmock.ExpectQuery
|
||||
Query: sqlx.Rebind(sqlx.AT, regexp.QuoteMeta(m.Query)),
|
||||
Query: sqlx.Rebind(sqlx.AT, regexp.QuoteMeta(r.Query)),
|
||||
Columns: columns,
|
||||
Rows: rows,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// converts basic reflect Kind's to psuedo-random data, slices are given a random amount of entries
|
||||
// generates mock data for insert statements to be used for sqlmock, it also returns a slice of
|
||||
// example structs with mock data
|
||||
func RandomStruct(c StructConfig) (*StructMock, error) {
|
||||
//make sure we have an example struct
|
||||
if c.Example == nil {
|
||||
return nil, ErrBadExample
|
||||
}
|
||||
if reflect.ValueOf(c.Example).Kind() != reflect.Struct {
|
||||
return nil, ErrBadExample
|
||||
}
|
||||
|
||||
//we need at least one row
|
||||
if c.RowCount <= 0 {
|
||||
c.RowCount = 1
|
||||
}
|
||||
|
||||
//get example type and number of fields
|
||||
retType := reflect.TypeOf(c.Example)
|
||||
maxFieldCount := retType.NumField()
|
||||
|
||||
//create slice of example structs
|
||||
ft := reflect.SliceOf(retType)
|
||||
filled := reflect.MakeSlice(ft, 0, c.RowCount)
|
||||
|
||||
for x := 0; x < c.RowCount; x++ {
|
||||
//add empty example struct
|
||||
filled = reflect.Append(filled, reflect.ValueOf(c.Example))
|
||||
for y := 0; y < maxFieldCount; y++ {
|
||||
field := retType.Field(y)
|
||||
|
||||
//get random value
|
||||
nv := kindToRandom(field)
|
||||
if nv == nil {
|
||||
return nil, fmt.Errorf(ErrUnsupportedType.Error(), field.Type.Name())
|
||||
}
|
||||
|
||||
if filled.Index(x).Field(y).CanSet() {
|
||||
filled.Index(x).Field(y).Set(reflect.ValueOf(nv))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//convert reflect.Value to []any
|
||||
fl := filled.Len()
|
||||
retStructs := make([]any, fl)
|
||||
for x := 0; x < fl; x++ {
|
||||
retStructs[x] = filled.Index(x).Interface()
|
||||
}
|
||||
|
||||
return &StructMock{
|
||||
Query: sqlx.Rebind(sqlx.AT, regexp.QuoteMeta(c.Query)),
|
||||
MockStructs: retStructs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// converts basic reflect Kind's to psuedo-random data, it is super basic and supports very basic types. Slices and arrays
|
||||
// are supported, slices will get 1-10 entries and arrays will fill length
|
||||
func kindToRandom(field reflect.StructField) any {
|
||||
kind := field.Type.Kind()
|
||||
switch kind {
|
||||
|
Reference in New Issue
Block a user