restructure project, add claudemd
This commit is contained in:
123
go/csv/csv.go
Normal file
123
go/csv/csv.go
Normal file
@@ -0,0 +1,123 @@
|
||||
package csv
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func WriteCSVtoHTTP(w http.ResponseWriter, csv string, filename string) {
|
||||
w.Header().Set("Content-Type", "text/csv")
|
||||
w.Header().Set("Content-Disposition", "attachment; filename="+filename+".csv")
|
||||
|
||||
w.Write([]byte(csv))
|
||||
}
|
||||
|
||||
func MakeCSV(headers []string, records [][]string) (string, error) {
|
||||
if len(records) > 0 {
|
||||
if len(headers) != len(records[0]) {
|
||||
return "", errors.New("data contains more columns then specified by headers")
|
||||
}
|
||||
}
|
||||
|
||||
// Write to CSV
|
||||
var csvBuilder strings.Builder
|
||||
writer := csv.NewWriter(&csvBuilder)
|
||||
|
||||
// Write headers
|
||||
if err := writer.Write(headers); err != nil {
|
||||
return "", fmt.Errorf("failed to write headers: %v", err)
|
||||
}
|
||||
|
||||
// Write records
|
||||
for _, record := range records {
|
||||
if err := writer.Write(record); err != nil {
|
||||
return "", fmt.Errorf("failed to write record: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
writer.Flush()
|
||||
if err := writer.Error(); err != nil {
|
||||
return "", fmt.Errorf("csv writer error: %v", err)
|
||||
}
|
||||
|
||||
return csvBuilder.String(), nil
|
||||
}
|
||||
|
||||
func StructToCSV(data any) (string, error) {
|
||||
val := reflect.ValueOf(data)
|
||||
if val.Kind() != reflect.Slice {
|
||||
return "", fmt.Errorf("input must be a slice of structs")
|
||||
}
|
||||
|
||||
if val.Len() == 0 {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var headers []string
|
||||
var records [][]string
|
||||
|
||||
// Get the first element to determine struct fields
|
||||
first := val.Index(0)
|
||||
if first.Kind() == reflect.Ptr {
|
||||
first = first.Elem()
|
||||
}
|
||||
|
||||
if first.Kind() != reflect.Struct {
|
||||
return "", fmt.Errorf("slice elements must be structs or pointers to structs")
|
||||
}
|
||||
|
||||
// Get field names as headers
|
||||
t := first.Type()
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
// Use json tag if present, otherwise use field name
|
||||
tag := field.Tag.Get("json")
|
||||
if tag != "" && tag != "-" {
|
||||
headers = append(headers, tag)
|
||||
} else {
|
||||
headers = append(headers, field.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// Convert each struct to a record
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
item := val.Index(i)
|
||||
if item.Kind() == reflect.Ptr {
|
||||
item = item.Elem()
|
||||
}
|
||||
|
||||
var record []string
|
||||
for j := 0; j < item.NumField(); j++ {
|
||||
fieldVal := item.Field(j)
|
||||
record = append(record, fmt.Sprintf("%v", fieldVal.Interface()))
|
||||
}
|
||||
records = append(records, record)
|
||||
}
|
||||
|
||||
// Write to CSV
|
||||
var csvBuilder strings.Builder
|
||||
writer := csv.NewWriter(&csvBuilder)
|
||||
|
||||
// Write headers
|
||||
if err := writer.Write(headers); err != nil {
|
||||
return "", fmt.Errorf("failed to write headers: %v", err)
|
||||
}
|
||||
|
||||
// Write records
|
||||
for _, record := range records {
|
||||
if err := writer.Write(record); err != nil {
|
||||
return "", fmt.Errorf("failed to write record: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
writer.Flush()
|
||||
if err := writer.Error(); err != nil {
|
||||
return "", fmt.Errorf("csv writer error: %v", err)
|
||||
}
|
||||
|
||||
return csvBuilder.String(), nil
|
||||
}
|
||||
Reference in New Issue
Block a user