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 |
package testfixtures |
||||||
|
|
||||||
import "regexp" |
import ( |
||||||
|
"errors" |
||||||
var ( |
"time" |
||||||
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") |
|
||||||
) |
) |
||||||
|
|
||||||
func isDate(value interface{}) bool { |
var timeFormats = []string{ |
||||||
str, isStr := value.(string) |
"2006-01-02", |
||||||
if !isStr { |
"2006-01-02 15:04", |
||||||
return false |
"2006-01-02 15:04:05", |
||||||
} |
"20060102", |
||||||
|
"20060102 15:04", |
||||||
return regexpDate.MatchString(str) |
"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 { |
// ErrCouldNotConvertToTime is returns when a string is not a reconizable time format
|
||||||
str, isStr := value.(string) |
var ErrCouldNotConvertToTime = errors.New("Could not convert string to time") |
||||||
if !isStr { |
|
||||||
return false |
|
||||||
} |
|
||||||
|
|
||||||
return regexpDateTime.MatchString(str) |
func tryStrToDate(s string) (time.Time, error) { |
||||||
} |
for _, f := range timeFormats { |
||||||
|
t, err := time.ParseInLocation(f, s, time.Local) |
||||||
func isTime(value interface{}) bool { |
if err != nil { |
||||||
str, isStr := value.(string) |
continue |
||||||
if !isStr { |
} |
||||||
return false |
return t, nil |
||||||
} |
} |
||||||
|
return time.Time{}, ErrCouldNotConvertToTime |
||||||
return regexpTime.MatchString(str) |
|
||||||
} |
} |
||||||
|
Loading…
Reference in new issue