Files
MyClub/internal/controllers/export_helper.go
T
Tomas Dvorak 9ccca365b3 dev day #65
2025-10-19 18:09:28 +02:00

138 lines
3.3 KiB
Go

package controllers
import (
"encoding/csv"
"encoding/json"
"fmt"
"reflect"
"strconv"
"time"
"github.com/gin-gonic/gin"
)
// ExportHelper provides export utilities for CSV, JSON, etc.
type ExportHelper struct{}
// NewExportHelper creates a new ExportHelper instance
func NewExportHelper() *ExportHelper {
return &ExportHelper{}
}
// ExportToCSV exports data to CSV format
func (eh *ExportHelper) ExportToCSV(c *gin.Context, data interface{}, filename string, headers []string) error {
c.Header("Content-Type", "text/csv")
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
writer := csv.NewWriter(c.Writer)
defer writer.Flush()
// Write headers
if err := writer.Write(headers); err != nil {
return err
}
// Convert data to slice of records
records, err := eh.convertToCSVRecords(data)
if err != nil {
return err
}
// Write records
for _, record := range records {
if err := writer.Write(record); err != nil {
return err
}
}
return nil
}
// ExportToJSON exports data to JSON format
func (eh *ExportHelper) ExportToJSON(c *gin.Context, data interface{}, filename string) error {
c.Header("Content-Type", "application/json")
c.Header("Content-Disposition", fmt.Sprintf("attachment; filename=%s", filename))
return json.NewEncoder(c.Writer).Encode(data)
}
// convertToCSVRecords converts a slice of structs to CSV records
func (eh *ExportHelper) convertToCSVRecords(data interface{}) ([][]string, error) {
v := reflect.ValueOf(data)
if v.Kind() != reflect.Slice {
return nil, fmt.Errorf("data must be a slice")
}
records := make([][]string, 0, v.Len())
for i := 0; i < v.Len(); i++ {
item := v.Index(i)
if item.Kind() == reflect.Ptr {
item = item.Elem()
}
record := make([]string, 0, item.NumField())
for j := 0; j < item.NumField(); j++ {
field := item.Field(j)
record = append(record, eh.formatFieldValue(field))
}
records = append(records, record)
}
return records, nil
}
// formatFieldValue formats a field value for CSV export
func (eh *ExportHelper) formatFieldValue(v reflect.Value) string {
switch v.Kind() {
case reflect.String:
return v.String()
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(v.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return strconv.FormatUint(v.Uint(), 10)
case reflect.Float32, reflect.Float64:
return strconv.FormatFloat(v.Float(), 'f', -1, 64)
case reflect.Bool:
return strconv.FormatBool(v.Bool())
case reflect.Struct:
// Handle time.Time
if t, ok := v.Interface().(time.Time); ok {
return t.Format(time.RFC3339)
}
return fmt.Sprintf("%v", v.Interface())
case reflect.Ptr:
if v.IsNil() {
return ""
}
return eh.formatFieldValue(v.Elem())
default:
return fmt.Sprintf("%v", v.Interface())
}
}
// ImportFromCSV imports data from CSV file
func (eh *ExportHelper) ImportFromCSV(c *gin.Context, formFieldName string) ([][]string, error) {
file, err := c.FormFile(formFieldName)
if err != nil {
return nil, err
}
f, err := file.Open()
if err != nil {
return nil, err
}
defer f.Close()
reader := csv.NewReader(f)
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
return records, nil
}
// Global ExportHelper instance
var Exporter = NewExportHelper()