ce5be947b4
Revert fixture fixes for postgres Use postgres connection string with spaces instead of url Fix label order Make postgres tests in ci less verbose Add sequence update script Skip resets in postgres Remove option to skip resets in postgres Make postgres tests in ci verboseq Update test fixtures database Fix file tests on postgres Add postgres options to sample config Make sure tests init test fixtures before running the actual tests Fix issues with IDs too big to fit in an int Fix duplicate auto incremented IDs Refactor / Fix team tests Refactor team member tests Fix team member create Fix label test Fix getting labels Fix test fixtures for postgresql Fix connection string params Disable ssl mode on postgres integration tests Disable ssl mode on postgres tests Use sprintf to create the connection string for postgresql fixup! Add postgres support Add postgres support Added generate as a make dependency for make build Clarify docs on building Co-authored-by: kolaente <k@knt.li> Co-authored-by: Jan Tojnar <jtojnar@gmail.com> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/135
155 lines
3.1 KiB
Go
155 lines
3.1 KiB
Go
package testfixtures
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"unicode/utf8"
|
|
|
|
"gopkg.in/yaml.v2"
|
|
)
|
|
|
|
// Dumper is resposible for dumping fixtures from the database into a
|
|
// directory.
|
|
type Dumper struct {
|
|
db *sql.DB
|
|
helper helper
|
|
dir string
|
|
|
|
tables []string
|
|
}
|
|
|
|
// NewDumper creates a new dumper with the given options.
|
|
//
|
|
// The "DumpDatabase", "DumpDialect" and "DumpDirectory" options are required.
|
|
func NewDumper(options ...func(*Dumper) error) (*Dumper, error) {
|
|
d := &Dumper{}
|
|
|
|
for _, option := range options {
|
|
if err := option(d); err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return d, nil
|
|
}
|
|
|
|
// DumpDatabase sets the database to be dumped.
|
|
func DumpDatabase(db *sql.DB) func(*Dumper) error {
|
|
return func(d *Dumper) error {
|
|
d.db = db
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// DumpDialect informs Loader about which database dialect you're using.
|
|
//
|
|
// Possible options are "postgresql", "timescaledb", "mysql", "mariadb",
|
|
// "sqlite" and "sqlserver".
|
|
func DumpDialect(dialect string) func(*Dumper) error {
|
|
return func(d *Dumper) error {
|
|
h, err := helperForDialect(dialect)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
d.helper = h
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// DumpDirectory sets the directory where the fixtures files will be created.
|
|
func DumpDirectory(dir string) func(*Dumper) error {
|
|
return func(d *Dumper) error {
|
|
d.dir = dir
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// DumpTables allows you to choose which tables you want to dump.
|
|
//
|
|
// If not informed, Dumper will dump all tables by default.
|
|
func DumpTables(tables ...string) func(*Dumper) error {
|
|
return func(d *Dumper) error {
|
|
d.tables = tables
|
|
return nil
|
|
}
|
|
}
|
|
|
|
// Dump dumps the databases as YAML fixtures.
|
|
func (d *Dumper) Dump() error {
|
|
tables := d.tables
|
|
if len(tables) == 0 {
|
|
var err error
|
|
tables, err = d.helper.tableNames(d.db)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
for _, table := range tables {
|
|
if err := d.dumpTable(table); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (d *Dumper) dumpTable(table string) error {
|
|
query := fmt.Sprintf("SELECT * FROM %s", d.helper.quoteKeyword(table))
|
|
rows, err := d.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
|
|
}
|
|
|
|
filePath := filepath.Join(d.dir, table+".yml")
|
|
f, err := os.Create(filePath)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
data, err := yaml.Marshal(fixtures)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = f.Write(data)
|
|
return err
|
|
}
|
|
|
|
func convertValue(value interface{}) interface{} {
|
|
switch v := value.(type) {
|
|
case []byte:
|
|
if utf8.Valid(v) {
|
|
return string(v)
|
|
}
|
|
}
|
|
return value
|
|
}
|