mirror of
				https://github.com/oarkflow/mq.git
				synced 2025-11-01 05:32:42 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			286 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			286 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package handlers
 | |
| 
 | |
| import (
 | |
| 	"context"
 | |
| 	"fmt"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/oarkflow/json"
 | |
| 	"github.com/oarkflow/mq"
 | |
| 	"github.com/oarkflow/mq/dag"
 | |
| )
 | |
| 
 | |
| // FormatHandler handles data formatting operations
 | |
| type FormatHandler struct {
 | |
| 	dag.Operation
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) ProcessTask(ctx context.Context, task *mq.Task) mq.Result {
 | |
| 	data, err := dag.UnmarshalPayload[map[string]any](ctx, task.Payload)
 | |
| 	if err != nil {
 | |
| 		return mq.Result{Error: fmt.Errorf("failed to unmarshal task payload: %w", err), Ctx: ctx}
 | |
| 	}
 | |
| 	if data == nil {
 | |
| 		data = make(map[string]any)
 | |
| 	}
 | |
| 
 | |
| 	// Handle mapping first
 | |
| 	if h.Payload.Mapping != nil {
 | |
| 		for k, v := range h.Payload.Mapping {
 | |
| 			_, val := dag.GetVal(ctx, v, data)
 | |
| 			data[k] = val
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	formatType, ok := h.Payload.Data["format_type"].(string)
 | |
| 	if !ok {
 | |
| 		// If no format_type specified, just return the data with mapping applied
 | |
| 		resultPayload, err := json.Marshal(data)
 | |
| 		if err != nil {
 | |
| 			return mq.Result{Error: fmt.Errorf("failed to marshal result: %w", err), Ctx: ctx}
 | |
| 		}
 | |
| 		return mq.Result{Payload: resultPayload, Ctx: ctx}
 | |
| 	}
 | |
| 
 | |
| 	var result map[string]any
 | |
| 	// Copy data to result
 | |
| 	if data != nil {
 | |
| 		result = make(map[string]any)
 | |
| 		for k, v := range data {
 | |
| 			result[k] = v
 | |
| 		}
 | |
| 	} else {
 | |
| 		result = make(map[string]any)
 | |
| 	}
 | |
| 
 | |
| 	switch formatType {
 | |
| 	case "string":
 | |
| 		result = h.formatToString(result)
 | |
| 	case "number":
 | |
| 		result = h.formatToNumber(result)
 | |
| 	case "date":
 | |
| 		result = h.formatDate(result)
 | |
| 	case "currency":
 | |
| 		result = h.formatCurrency(result)
 | |
| 	case "uppercase":
 | |
| 		result = h.formatUppercase(result)
 | |
| 	case "lowercase":
 | |
| 		result = h.formatLowercase(result)
 | |
| 	case "capitalize":
 | |
| 		result = h.formatCapitalize(result)
 | |
| 	case "trim":
 | |
| 		result = h.formatTrim(result)
 | |
| 	default:
 | |
| 		return mq.Result{Error: fmt.Errorf("unsupported format_type: %s", formatType), Ctx: ctx}
 | |
| 	}
 | |
| 
 | |
| 	resultPayload, err := json.Marshal(result)
 | |
| 	if err != nil {
 | |
| 		return mq.Result{Error: fmt.Errorf("failed to marshal result: %w", err), Ctx: ctx}
 | |
| 	}
 | |
| 
 | |
| 	return mq.Result{Payload: resultPayload, Ctx: ctx}
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatToString(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			result[key] = fmt.Sprintf("%v", value)
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatToNumber(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if str, ok := value.(string); ok {
 | |
| 				if num, err := strconv.ParseFloat(str, 64); err == nil {
 | |
| 					result[key] = num
 | |
| 				} else {
 | |
| 					result[key] = value // Keep original if conversion fails
 | |
| 				}
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatDate(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 	dateFormat := h.getDateFormat()
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if str, ok := value.(string); ok {
 | |
| 				if t, err := time.Parse(time.RFC3339, str); err == nil {
 | |
| 					result[key] = t.Format(dateFormat)
 | |
| 				} else if t, err := time.Parse("2006-01-02", str); err == nil {
 | |
| 					result[key] = t.Format(dateFormat)
 | |
| 				} else {
 | |
| 					result[key] = value // Keep original if parsing fails
 | |
| 				}
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatCurrency(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 	currency := h.getCurrency()
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if num, ok := value.(float64); ok {
 | |
| 				result[key] = fmt.Sprintf("%s%.2f", currency, num)
 | |
| 			} else if str, ok := value.(string); ok {
 | |
| 				if num, err := strconv.ParseFloat(str, 64); err == nil {
 | |
| 					result[key] = fmt.Sprintf("%s%.2f", currency, num)
 | |
| 				} else {
 | |
| 					result[key] = value
 | |
| 				}
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatUppercase(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if str, ok := value.(string); ok {
 | |
| 				result[key] = strings.ToUpper(str)
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatLowercase(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if str, ok := value.(string); ok {
 | |
| 				result[key] = strings.ToLower(str)
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatCapitalize(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if str, ok := value.(string); ok {
 | |
| 				result[key] = strings.Title(strings.ToLower(str))
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) formatTrim(data map[string]any) map[string]any {
 | |
| 	result := make(map[string]any)
 | |
| 	fields := h.getTargetFields(data)
 | |
| 
 | |
| 	for key, value := range data {
 | |
| 		if len(fields) == 0 || contains(fields, key) {
 | |
| 			if str, ok := value.(string); ok {
 | |
| 				result[key] = strings.TrimSpace(str)
 | |
| 			} else {
 | |
| 				result[key] = value
 | |
| 			}
 | |
| 		} else {
 | |
| 			result[key] = value
 | |
| 		}
 | |
| 	}
 | |
| 	return result
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) getTargetFields(data map[string]any) []string {
 | |
| 	if fields, ok := h.Payload.Data["fields"].([]any); ok {
 | |
| 		var result []string
 | |
| 		for _, field := range fields {
 | |
| 			if str, ok := field.(string); ok {
 | |
| 				result = append(result, str)
 | |
| 			}
 | |
| 		}
 | |
| 		return result
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) getDateFormat() string {
 | |
| 	if format, ok := h.Payload.Data["date_format"].(string); ok {
 | |
| 		return format
 | |
| 	}
 | |
| 	return "2006-01-02" // Default date format
 | |
| }
 | |
| 
 | |
| func (h *FormatHandler) getCurrency() string {
 | |
| 	if currency, ok := h.Payload.Data["currency"].(string); ok {
 | |
| 		return currency
 | |
| 	}
 | |
| 	return "$" // Default currency symbol
 | |
| }
 | |
| 
 | |
| func contains(slice []string, item string) bool {
 | |
| 	for _, s := range slice {
 | |
| 		if s == item {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func NewFormatHandler(id string) *FormatHandler {
 | |
| 	return &FormatHandler{
 | |
| 		Operation: dag.Operation{ID: id, Key: "format", Type: dag.Function, Tags: []string{"data", "transformation"}},
 | |
| 	}
 | |
| }
 | 
