2019-02-14 13:33:42 +00:00
|
|
|
// Copyright (C) 2019 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package dbschema
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sort"
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
"github.com/zeebo/errs"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Data is the database content formatted as strings
|
|
|
|
type Data struct {
|
|
|
|
Tables []*TableData
|
|
|
|
}
|
|
|
|
|
|
|
|
// TableData is content of a sql table
|
|
|
|
type TableData struct {
|
|
|
|
Name string
|
|
|
|
Columns []string
|
|
|
|
Rows []RowData
|
|
|
|
}
|
|
|
|
|
|
|
|
// RowData is content of a single row
|
|
|
|
type RowData []string
|
|
|
|
|
|
|
|
// AddTable adds a new table.
|
|
|
|
func (data *Data) AddTable(table *TableData) {
|
|
|
|
data.Tables = append(data.Tables, table)
|
|
|
|
}
|
|
|
|
|
|
|
|
// AddRow adds a new row.
|
|
|
|
func (table *TableData) AddRow(row RowData) {
|
|
|
|
table.Rows = append(table.Rows, row)
|
|
|
|
}
|
|
|
|
|
2019-02-14 21:55:21 +00:00
|
|
|
// FindTable finds a table by name
|
|
|
|
func (data *Data) FindTable(tableName string) (*TableData, bool) {
|
|
|
|
for _, table := range data.Tables {
|
|
|
|
if table.Name == tableName {
|
|
|
|
return table, true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil, false
|
|
|
|
}
|
|
|
|
|
2019-02-14 13:33:42 +00:00
|
|
|
// Sort sorts all tables.
|
|
|
|
func (data *Data) Sort() {
|
|
|
|
for _, table := range data.Tables {
|
|
|
|
table.Sort()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sort sorts all rows.
|
|
|
|
func (table *TableData) Sort() {
|
|
|
|
sort.Slice(table.Rows, func(i, k int) bool {
|
|
|
|
return lessStrings(table.Rows[i], table.Rows[k])
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clone returns a clone of row data.
|
|
|
|
func (row RowData) Clone() RowData {
|
|
|
|
return append(RowData{}, row...)
|
|
|
|
}
|
|
|
|
|
|
|
|
// QueryData loads all data from tables
|
|
|
|
func QueryData(db Queryer, schema *Schema, quoteColumn func(string) string) (*Data, error) {
|
|
|
|
data := &Data{}
|
|
|
|
|
|
|
|
for _, tableSchema := range schema.Tables {
|
|
|
|
columnNames := tableSchema.ColumnNames()
|
|
|
|
table := &TableData{
|
|
|
|
Name: tableSchema.Name,
|
|
|
|
Columns: columnNames,
|
|
|
|
}
|
2019-02-14 21:55:21 +00:00
|
|
|
data.AddTable(table)
|
2019-02-14 13:33:42 +00:00
|
|
|
|
|
|
|
// quote column names
|
|
|
|
quotedColumns := make([]string, len(columnNames))
|
|
|
|
for i, columnName := range columnNames {
|
|
|
|
quotedColumns[i] = quoteColumn(columnName)
|
|
|
|
}
|
|
|
|
|
|
|
|
// build query for selecting all values
|
|
|
|
query := `SELECT ` + strings.Join(quotedColumns, ", ") + ` FROM ` + table.Name
|
|
|
|
|
|
|
|
err := func() (err error) {
|
|
|
|
rows, err := db.Query(query)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer func() { err = errs.Combine(err, rows.Close()) }()
|
|
|
|
|
|
|
|
row := make(RowData, len(columnNames))
|
|
|
|
rowargs := make([]interface{}, len(columnNames))
|
|
|
|
for i := range row {
|
|
|
|
rowargs[i] = &row[i]
|
|
|
|
}
|
|
|
|
|
|
|
|
for rows.Next() {
|
|
|
|
err := rows.Scan(rowargs...)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
table.AddRow(row.Clone())
|
|
|
|
}
|
|
|
|
|
|
|
|
return rows.Err()
|
|
|
|
}()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return data, nil
|
|
|
|
}
|