adding new functionality for mocks

- working through insert logic
- ideally return struct with 'good' fields
- also return list of args to prevent relooping
This commit is contained in:
2025-09-29 15:47:51 -04:00
parent 3b40f8061f
commit ff62b371c9
2 changed files with 90 additions and 9 deletions

17
driver.go Normal file
View File

@@ -0,0 +1,17 @@
package lazy
//driver.Result does not play well with creation, overriding it here so we can return the results without
//requiring sqlmock
type sqlResult struct {
insertID int64
rowsAffected int64
err error
}
func (r *sqlResult) LastInsertId() (int64, error) {
return r.insertID, r.err
}
func (r *sqlResult) RowsAffected() (int64, error) {
return r.rowsAffected, r.err
}

82
lazy.go
View File

@@ -17,29 +17,47 @@ 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")
ErrUnsupportedType = errors.New("")
)
// 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 //if set, length of keys must = RowCount
RowCount int
}
type StructMock struct {
Query string
Args []any
MockStruct any
Result driver.Result
}
type StructConfig struct {
Query string
Example any
}
// generates mock data based on configuration to be used for sqlmock
func RandomGenerate(m Config) (*Mock, error) {
func RandomRows(m RowConfig) (*RowMock, error) {
//example struct cannot be nil and must be a struct
if m.Example == nil {
return nil, errors.New("example value cannot be nil")
return nil, ErrBadExample
}
if reflect.ValueOf(m.Example).Kind() != reflect.Struct {
return nil, errors.New("example value must be a struct")
return nil, ErrBadExample
}
//any weirdness, just pull one row
@@ -52,7 +70,7 @@ func RandomGenerate(m Config) (*Mock, error) {
if len(m.Keys) > 0 {
primaryKey = true
if len(m.Keys) != m.RowCount {
return nil, errors.New("you must provide a key for each row")
return nil, ErrMissingKeys
}
}
@@ -84,14 +102,14 @@ func RandomGenerate(m Config) (*Mock, error) {
//generate random values
nv := kindToRandom(field)
if nv == nil {
return nil, fmt.Errorf("could not match type: %s", retType.Name())
return nil, ErrUnsupportedType
}
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)),
Columns: columns,
@@ -99,6 +117,52 @@ func RandomGenerate(m Config) (*Mock, error) {
}, nil
}
// so this would "work" but only accounts for inserting one row and doesn't allow for hardcoded ID's
// it would also have to account in the results struct these changes for rowsAffected, etc.
func RandomStruct(c StructConfig) (*StructMock, error) {
if c.Example == nil {
return nil, ErrBadExample
}
if reflect.ValueOf(c.Example).Kind() != reflect.Struct {
return nil, ErrBadExample
}
retType := reflect.TypeOf(c.Example)
maxFieldCount := retType.NumField()
filled := reflect.New(retType).Elem()
args := make([]any, 0, maxFieldCount)
for y := 0; y < maxFieldCount; y++ {
field := retType.Field(y)
dbTag := field.Tag.Get(DB_TAG)
if dbTag == "" {
continue
}
nv := kindToRandom(field)
if nv == nil {
return nil, ErrUnsupportedType
}
args[y] = nv
nf := filled.Field(y)
if nf.CanSet() {
filled.Field(y).Set(reflect.ValueOf(nv))
}
}
return &StructMock{
Query: sqlx.Rebind(sqlx.AT, regexp.QuoteMeta(c.Query)),
Args: args,
MockStruct: filled,
Result: &sqlResult{
insertID: 1,
rowsAffected: 1,
err: nil,
},
}, nil
}
// converts basic reflect Kind's to psuedo-random data, slices are given a random amount of entries
func kindToRandom(field reflect.StructField) any {
kind := field.Type.Kind()