Açıklama Yok
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

query_csv.go 3.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package functions
  2. import (
  3. "database/sql"
  4. "encoding/csv"
  5. "fmt"
  6. "strings"
  7. "git.x2erp.com/qdy/go-base/ctx"
  8. "git.x2erp.com/qdy/go-base/logger"
  9. "github.com/jmoiron/sqlx"
  10. "go.uber.org/zap"
  11. )
  12. // QueryToCSV 无参数查询并返回 CSV 字节数据
  13. func QueryToCSV(db *sqlx.DB, sql string, writerHeader bool, reqCtx *ctx.RequestContext) ([]byte, error) {
  14. logger.DebugC(reqCtx, "Executing QueryToCSV",
  15. zap.String("sql", sql),
  16. zap.Bool("writerHeader", writerHeader))
  17. if sql == "" {
  18. return nil, logger.ErrorCf(reqCtx, "SQL query cannot be empty")
  19. }
  20. rows, err := db.Query(sql)
  21. if err != nil {
  22. return nil, logger.ErrorCf(reqCtx, "query execution failed: %v", err)
  23. }
  24. return rowsToCSV(rows, writerHeader, reqCtx)
  25. }
  26. // QueryParamsToCSV 位置参数查询并返回 CSV 字节数据
  27. func QueryPositionalToCSV(db *sqlx.DB, sql string, writerHeader bool, params []interface{}, reqCtx *ctx.RequestContext) ([]byte, error) {
  28. logger.DebugC(reqCtx, "Executing QueryToCSV: sql=%s, writerHeader=%v", sql, writerHeader)
  29. if sql == "" {
  30. return nil, logger.ErrorCf(reqCtx, "SQL query cannot be empty")
  31. }
  32. rows, err := db.Query(sql, params...)
  33. if err != nil {
  34. return nil, logger.ErrorCf(reqCtx, "query execution failed: %v", err)
  35. }
  36. return rowsToCSV(rows, writerHeader, reqCtx)
  37. }
  38. // QueryParamsNameToCSV 命名参数查询并返回 CSV 字节数据
  39. // params 可以是 map[string]interface{} 或结构体
  40. func QueryParamsNameToCSV(db *sqlx.DB, sql string, writerHeader bool, params map[string]interface{}, reqCtx *ctx.RequestContext) ([]byte, error) {
  41. logger.DebugC(reqCtx, "Executing QueryToCSV",
  42. zap.String("sql", sql),
  43. zap.Bool("writerHeader", writerHeader))
  44. if sql == "" {
  45. return nil, logger.ErrorCf(reqCtx, "SQL query cannot be empty")
  46. }
  47. query, args, err := sqlx.Named(sql, params)
  48. if err != nil {
  49. return nil, logger.ErrorCf(reqCtx, "query execution failed: %v", err)
  50. }
  51. query = db.Rebind(query)
  52. rows, err := db.Query(query, args...)
  53. if err != nil {
  54. return nil, logger.ErrorCf(reqCtx, "query execution failed: %v", err)
  55. }
  56. return rowsToCSV(rows, writerHeader, reqCtx)
  57. }
  58. // rowsToCSV 公共方法:将查询结果转换为 CSV 字节数据
  59. func rowsToCSV(rows *sql.Rows, writerHeader bool, reqCtx *ctx.RequestContext) ([]byte, error) {
  60. defer rows.Close()
  61. columns, err := rows.Columns()
  62. if err != nil {
  63. return nil, logger.ErrorCf(reqCtx, "failed to get columns: %v", err)
  64. }
  65. var builder strings.Builder
  66. writer := csv.NewWriter(&builder)
  67. // 根据参数决定是否写入表头
  68. if writerHeader {
  69. if err := writer.Write(columns); err != nil {
  70. return nil, logger.ErrorCf(reqCtx, "failed to write CSV header: %v", err)
  71. }
  72. }
  73. for rows.Next() {
  74. values := make([]interface{}, len(columns))
  75. valuePtrs := make([]any, len(columns))
  76. for i := range columns {
  77. valuePtrs[i] = &values[i]
  78. }
  79. if err := rows.Scan(valuePtrs...); err != nil {
  80. return nil, logger.ErrorCf(reqCtx, "failed to scan row: %v", err)
  81. }
  82. // 所有值转为字符串
  83. row := make([]string, len(columns))
  84. for i, val := range values {
  85. if val == nil {
  86. row[i] = ""
  87. } else {
  88. row[i] = fmt.Sprintf("%v", val)
  89. }
  90. }
  91. if err := writer.Write(row); err != nil {
  92. return nil, logger.ErrorCf(reqCtx, "failed to write CSV row: %v", err)
  93. }
  94. }
  95. writer.Flush()
  96. if err := writer.Error(); err != nil {
  97. return nil, logger.ErrorCf(reqCtx, "failed to flush CSV: %v", err)
  98. }
  99. if err := rows.Err(); err != nil {
  100. return nil, logger.ErrorCf(reqCtx, "row iteration error: %v", err)
  101. }
  102. return []byte(builder.String()), nil
  103. }