package main import ( "database/sql" "encoding/json" "fmt" "log" "os" "slices" "strings" _ "modernc.org/sqlite" ) func main() { db, err := sql.Open("sqlite", os.Args[1]) if err != nil { log.Fatal(err) } defer db.Close() tables, err := Tables(db) if err != nil { log.Fatal(err) } if len(os.Args) > 2 { tables = slices.DeleteFunc(tables, func(s string) bool { return !slices.Contains(os.Args[2:], s) }) } for i, table := range tables { if err := func() error { rows, err := db.Query(fmt.Sprintf(`SELECT * FROM %q`, table)) if err != nil { return err } defer rows.Close() columns, err := rows.Columns() if err != nil { return err } if i > 0 { fmt.Println("") } fmt.Println("---", table) fmt.Println(strings.Join(func() []string { quoted := []string{} for _, col := range columns { quoted = append(quoted, fmt.Sprintf("%q", col)) } return quoted }(), ",")) row := make([]any, len(columns)) for rows.Next() { for i := range row { var a any row[i] = &a } if err := rows.Scan(row...); err != nil { return err } jsons := []string{} for i := range row { row[i] = *(row[i].(*any)) if b, ok := row[i].([]byte); ok { row[i] = string(b) } b, _ := json.Marshal(row[i]) jsons = append(jsons, string(b)) } fmt.Println(strings.Join(jsons, ",")) } return rows.Err() }(); err != nil { log.Fatalf("%s: %v", table, err) } } } func Tables(db *sql.DB) ([]string, error) { return Select[string](db, `SELECT name FROM sqlite_schema WHERE type = 'table' AND name NOT LIKE 'sqlite_%'`) } func Select[T any](db *sql.DB, q string, args ...any) ([]T, error) { rows, err := db.Query(q, args...) if err != nil { return nil, err } defer rows.Close() results := []T{} for rows.Next() { var some T if err := rows.Scan(&some); err != nil { return nil, err } results = append(results, some) } return results, rows.Err() }