Upgrade gopkg.in/testfixtures.v2 (#4999)
parent
b8d048fa0d
commit
dba955be7c
@ -0,0 +1,41 @@ |
||||
package testfixtures |
||||
|
||||
import ( |
||||
"errors" |
||||
"fmt" |
||||
) |
||||
|
||||
var ( |
||||
// ErrWrongCastNotAMap is returned when a map is not a map[interface{}]interface{}
|
||||
ErrWrongCastNotAMap = errors.New("Could not cast record: not a map[interface{}]interface{}") |
||||
|
||||
// ErrFileIsNotSliceOrMap is returned the the fixture file is not a slice or map.
|
||||
ErrFileIsNotSliceOrMap = errors.New("The fixture file is not a slice or map") |
||||
|
||||
// ErrKeyIsNotString is returned when a record is not of type string
|
||||
ErrKeyIsNotString = errors.New("Record map key is not string") |
||||
|
||||
// ErrNotTestDatabase is returned when the database name doesn't contains "test"
|
||||
ErrNotTestDatabase = errors.New(`Loading aborted because the database name does not contains "test"`) |
||||
) |
||||
|
||||
// InsertError will be returned if any error happens on database while
|
||||
// inserting the record
|
||||
type InsertError struct { |
||||
Err error |
||||
File string |
||||
Index int |
||||
SQL string |
||||
Params []interface{} |
||||
} |
||||
|
||||
func (e *InsertError) Error() string { |
||||
return fmt.Sprintf( |
||||
"testfixtures: error inserting record: %v, on file: %s, index: %d, sql: %s, params: %v", |
||||
e.Err, |
||||
e.File, |
||||
e.Index, |
||||
e.SQL, |
||||
e.Params, |
||||
) |
||||
} |
@ -0,0 +1,110 @@ |
||||
package testfixtures |
||||
|
||||
import ( |
||||
"database/sql" |
||||
"fmt" |
||||
"os" |
||||
"path" |
||||
"unicode/utf8" |
||||
|
||||
"gopkg.in/yaml.v2" |
||||
) |
||||
|
||||
// TableInfo is settings for generating a fixture for table.
|
||||
type TableInfo struct { |
||||
Name string // Table name
|
||||
Where string // A condition for extracting records. If this value is empty, extracts all records.
|
||||
} |
||||
|
||||
func (ti *TableInfo) whereClause() string { |
||||
if ti.Where == "" { |
||||
return "" |
||||
} |
||||
return fmt.Sprintf(" WHERE %s", ti.Where) |
||||
} |
||||
|
||||
// GenerateFixtures generates fixtures for the current contents of a database, and saves
|
||||
// them to the specified directory
|
||||
func GenerateFixtures(db *sql.DB, helper Helper, dir string) error { |
||||
tables, err := helper.tableNames(db) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
for _, table := range tables { |
||||
filename := path.Join(dir, table+".yml") |
||||
if err := generateFixturesForTable(db, helper, &TableInfo{Name: table}, filename); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// GenerateFixturesForTables generates fixtures for the current contents of specified tables in a database, and saves
|
||||
// them to the specified directory
|
||||
func GenerateFixturesForTables(db *sql.DB, tables []*TableInfo, helper Helper, dir string) error { |
||||
for _, table := range tables { |
||||
filename := path.Join(dir, table.Name+".yml") |
||||
if err := generateFixturesForTable(db, helper, table, filename); err != nil { |
||||
return err |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func generateFixturesForTable(db *sql.DB, h Helper, table *TableInfo, filename string) error { |
||||
query := fmt.Sprintf("SELECT * FROM %s%s", h.quoteKeyword(table.Name), table.whereClause()) |
||||
rows, err := db.Query(query) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer rows.Close() |
||||
|
||||
columns, err := rows.Columns() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
fixtures := make([]interface{}, 0, 10) |
||||
for rows.Next() { |
||||
entries := make([]interface{}, len(columns)) |
||||
entryPtrs := make([]interface{}, len(entries)) |
||||
for i := range entries { |
||||
entryPtrs[i] = &entries[i] |
||||
} |
||||
if err := rows.Scan(entryPtrs...); err != nil { |
||||
return err |
||||
} |
||||
|
||||
entryMap := make(map[string]interface{}, len(entries)) |
||||
for i, column := range columns { |
||||
entryMap[column] = convertValue(entries[i]) |
||||
} |
||||
fixtures = append(fixtures, entryMap) |
||||
} |
||||
if err = rows.Err(); err != nil { |
||||
return err |
||||
} |
||||
|
||||
f, err := os.Create(filename) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
defer f.Close() |
||||
|
||||
marshaled, err := yaml.Marshal(fixtures) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
_, err = f.Write(marshaled) |
||||
return err |
||||
} |
||||
|
||||
func convertValue(value interface{}) interface{} { |
||||
switch v := value.(type) { |
||||
case []byte: |
||||
if utf8.Valid(v) { |
||||
return string(v) |
||||
} |
||||
} |
||||
return value |
||||
} |
@ -0,0 +1,44 @@ |
||||
package testfixtures |
||||
|
||||
import ( |
||||
"database/sql/driver" |
||||
"encoding/json" |
||||
) |
||||
|
||||
var ( |
||||
_ driver.Valuer = jsonArray{} |
||||
_ driver.Valuer = jsonMap{} |
||||
) |
||||
|
||||
type jsonArray []interface{} |
||||
|
||||
func (a jsonArray) Value() (driver.Value, error) { |
||||
return json.Marshal(a) |
||||
} |
||||
|
||||
type jsonMap map[string]interface{} |
||||
|
||||
func (m jsonMap) Value() (driver.Value, error) { |
||||
return json.Marshal(m) |
||||
} |
||||
|
||||
// Go refuses to convert map[interface{}]interface{} to JSON because JSON only support string keys
|
||||
// So it's necessary to recursively convert all map[interface]interface{} to map[string]interface{}
|
||||
func recursiveToJSON(v interface{}) (r interface{}) { |
||||
switch v := v.(type) { |
||||
case []interface{}: |
||||
for i, e := range v { |
||||
v[i] = recursiveToJSON(e) |
||||
} |
||||
r = jsonArray(v) |
||||
case map[interface{}]interface{}: |
||||
newMap := make(map[string]interface{}, len(v)) |
||||
for k, e := range v { |
||||
newMap[k.(string)] = recursiveToJSON(e) |
||||
} |
||||
r = jsonMap(newMap) |
||||
default: |
||||
r = v |
||||
} |
||||
return |
||||
} |
@ -1,36 +1,34 @@ |
||||
package testfixtures |
||||
|
||||
import "regexp" |
||||
|
||||
var ( |
||||
regexpDate = regexp.MustCompile("\\d\\d\\d\\d-\\d\\d-\\d\\d") |
||||
regexpDateTime = regexp.MustCompile("\\d\\d\\d\\d-\\d\\d-\\d\\d \\d\\d:\\d\\d:\\d\\d") |
||||
regexpTime = regexp.MustCompile("\\d\\d:\\d\\d:\\d\\d") |
||||
import ( |
||||
"errors" |
||||
"time" |
||||
) |
||||
|
||||
func isDate(value interface{}) bool { |
||||
str, isStr := value.(string) |
||||
if !isStr { |
||||
return false |
||||
} |
||||
|
||||
return regexpDate.MatchString(str) |
||||
var timeFormats = []string{ |
||||
"2006-01-02", |
||||
"2006-01-02 15:04", |
||||
"2006-01-02 15:04:05", |
||||
"20060102", |
||||
"20060102 15:04", |
||||
"20060102 15:04:05", |
||||
"02/01/2006", |
||||
"02/01/2006 15:04", |
||||
"02/01/2006 15:04:05", |
||||
"2006-01-02T15:04-07:00", |
||||
"2006-01-02T15:04:05-07:00", |
||||
} |
||||
|
||||
func isDateTime(value interface{}) bool { |
||||
str, isStr := value.(string) |
||||
if !isStr { |
||||
return false |
||||
} |
||||
// ErrCouldNotConvertToTime is returns when a string is not a reconizable time format
|
||||
var ErrCouldNotConvertToTime = errors.New("Could not convert string to time") |
||||
|
||||
return regexpDateTime.MatchString(str) |
||||
} |
||||
|
||||
func isTime(value interface{}) bool { |
||||
str, isStr := value.(string) |
||||
if !isStr { |
||||
return false |
||||
func tryStrToDate(s string) (time.Time, error) { |
||||
for _, f := range timeFormats { |
||||
t, err := time.ParseInLocation(f, s, time.Local) |
||||
if err != nil { |
||||
continue |
||||
} |
||||
return t, nil |
||||
} |
||||
|
||||
return regexpTime.MatchString(str) |
||||
return time.Time{}, ErrCouldNotConvertToTime |
||||
} |
||||
|
Loading…
Reference in new issue