mirror of
https://github.com/turbot/steampipe.git
synced 2026-02-15 04:00:14 -05:00
141 lines
3.4 KiB
Go
141 lines
3.4 KiB
Go
package utils
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
typeHelpers "github.com/turbot/go-kit/types"
|
|
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// functions specifically used for Debugging purposes.
|
|
func DebugDumpJSON(msg string, d interface{}) {
|
|
enc := json.NewEncoder(os.Stdout)
|
|
enc.SetIndent(" ", " ")
|
|
os.Stdout.WriteString(msg)
|
|
enc.Encode(d)
|
|
}
|
|
|
|
func DebugDumpViper() {
|
|
fmt.Println(strings.Repeat("*", 80))
|
|
for _, vKey := range viper.AllKeys() {
|
|
fmt.Printf("%-30s => %v\n", vKey, viper.Get(vKey))
|
|
}
|
|
fmt.Println(strings.Repeat("*", 80))
|
|
}
|
|
|
|
func DebugDumpRows(rows *sql.Rows) {
|
|
colTypes, err := rows.ColumnTypes()
|
|
if err != nil {
|
|
// we do not need to stream because
|
|
// defer takes care of it!
|
|
return
|
|
}
|
|
cols, err := rows.Columns()
|
|
if err != nil {
|
|
// we do not need to stream because
|
|
// defer takes care of it!
|
|
return
|
|
}
|
|
fmt.Println(cols)
|
|
fmt.Println("---------------------------------------")
|
|
for rows.Next() {
|
|
row, _ := readRow(rows, cols, colTypes)
|
|
rowAsString, _ := columnValuesAsString(row, colTypes)
|
|
fmt.Println(rowAsString)
|
|
}
|
|
}
|
|
|
|
func readRow(rows *sql.Rows, cols []string, colTypes []*sql.ColumnType) ([]interface{}, error) {
|
|
// slice of interfaces to receive the row data
|
|
columnValues := make([]interface{}, len(cols))
|
|
// make a slice of pointers to the result to pass to scan
|
|
resultPtrs := make([]interface{}, len(cols)) // A temporary interface{} slice
|
|
for i := range columnValues {
|
|
resultPtrs[i] = &columnValues[i]
|
|
}
|
|
err := rows.Scan(resultPtrs...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return populateRow(columnValues, colTypes), nil
|
|
}
|
|
|
|
func populateRow(columnValues []interface{}, colTypes []*sql.ColumnType) []interface{} {
|
|
result := make([]interface{}, len(columnValues))
|
|
for i, columnValue := range columnValues {
|
|
if columnValue != nil {
|
|
colType := colTypes[i]
|
|
dbType := colType.DatabaseTypeName()
|
|
switch dbType {
|
|
case "JSON", "JSONB":
|
|
var val interface{}
|
|
if err := json.Unmarshal(columnValue.([]byte), &val); err != nil {
|
|
// what???
|
|
// TODO how to handle error
|
|
}
|
|
result[i] = val
|
|
default:
|
|
result[i] = columnValue
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// columnValuesAsString converts a slice of columns into strings
|
|
func columnValuesAsString(values []interface{}, columns []*sql.ColumnType) ([]string, error) {
|
|
rowAsString := make([]string, len(columns))
|
|
for idx, val := range values {
|
|
val, err := columnValueAsString(val, columns[idx])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
rowAsString[idx] = val
|
|
}
|
|
return rowAsString, nil
|
|
}
|
|
|
|
// columnValueAsString converts column value to string
|
|
func columnValueAsString(val interface{}, colType *sql.ColumnType) (result string, err error) {
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
result = fmt.Sprintf("%v", val)
|
|
}
|
|
}()
|
|
|
|
if val == nil {
|
|
return "<null>", nil
|
|
}
|
|
|
|
//log.Printf("[TRACE] ColumnValueAsString type %s", colType.DatabaseTypeName())
|
|
// possible types for colType are defined in pq/oid/types.go
|
|
switch colType.DatabaseTypeName() {
|
|
case "JSON", "JSONB":
|
|
bytes, err := json.Marshal(val)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return string(bytes), nil
|
|
case "TIMESTAMP", "DATE", "TIME", "INTERVAL":
|
|
t, ok := val.(time.Time)
|
|
if ok {
|
|
return t.Format("2006-01-02 15:04:05"), nil
|
|
}
|
|
fallthrough
|
|
case "NAME":
|
|
result := string(val.([]uint8))
|
|
return result, nil
|
|
|
|
default:
|
|
return typeHelpers.ToString(val), nil
|
|
}
|
|
|
|
}
|