mirror of
https://github.com/oarkflow/mq.git
synced 2025-10-04 07:37:05 +08:00
344 lines
7.8 KiB
Go
344 lines
7.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/oarkflow/json"
|
|
"github.com/oarkflow/mq"
|
|
"github.com/oarkflow/mq/dag"
|
|
)
|
|
|
|
// FieldHandler handles field manipulation operations (filter, add, remove, rename, etc.)
|
|
type FieldHandler struct {
|
|
dag.Operation
|
|
}
|
|
|
|
func (h *FieldHandler) 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}
|
|
}
|
|
|
|
operation, ok := h.Payload.Data["operation"].(string)
|
|
if !ok {
|
|
return mq.Result{Error: fmt.Errorf("operation not specified")}
|
|
}
|
|
|
|
var result map[string]any
|
|
switch operation {
|
|
case "filter", "select":
|
|
result = h.filterFields(data)
|
|
case "exclude", "remove":
|
|
result = h.excludeFields(data)
|
|
case "rename":
|
|
result = h.renameFields(data)
|
|
case "add", "set":
|
|
result = h.addFields(data)
|
|
case "copy":
|
|
result = h.copyFields(data)
|
|
case "merge":
|
|
result = h.mergeFields(data)
|
|
case "prefix":
|
|
result = h.prefixFields(data)
|
|
case "suffix":
|
|
result = h.suffixFields(data)
|
|
case "transform_keys":
|
|
result = h.transformKeys(data)
|
|
default:
|
|
return mq.Result{Error: fmt.Errorf("unsupported operation: %s", operation)}
|
|
}
|
|
|
|
resultPayload, err := json.Marshal(result)
|
|
if err != nil {
|
|
return mq.Result{Error: fmt.Errorf("failed to marshal result: %w", err)}
|
|
}
|
|
|
|
return mq.Result{Payload: resultPayload, Ctx: ctx}
|
|
}
|
|
|
|
func (h *FieldHandler) filterFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
allowedFields := h.getTargetFields()
|
|
|
|
if len(allowedFields) == 0 {
|
|
return data // If no fields specified, return all
|
|
}
|
|
|
|
for _, field := range allowedFields {
|
|
if val, ok := data[field]; ok {
|
|
result[field] = val
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) excludeFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
excludeFields := h.getTargetFields()
|
|
|
|
// Copy all fields except excluded ones
|
|
for key, value := range data {
|
|
if !contains(excludeFields, key) {
|
|
result[key] = value
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) renameFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
renameMap := h.getFieldMapping()
|
|
|
|
// Copy all fields, renaming as specified
|
|
for key, value := range data {
|
|
if newKey, ok := renameMap[key]; ok {
|
|
result[newKey] = value
|
|
} else {
|
|
result[key] = value
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) addFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
newFields := h.getNewFields()
|
|
|
|
// Copy all original data
|
|
for key, value := range data {
|
|
result[key] = value
|
|
}
|
|
|
|
// Add new fields
|
|
for key, value := range newFields {
|
|
result[key] = value
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) copyFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
copyMap := h.getFieldMapping()
|
|
|
|
// Copy all original data
|
|
for key, value := range data {
|
|
result[key] = value
|
|
}
|
|
|
|
// Copy fields to new names
|
|
for sourceKey, targetKey := range copyMap {
|
|
if val, ok := data[sourceKey]; ok {
|
|
result[targetKey] = val
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) mergeFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
mergeConfig := h.getMergeConfig()
|
|
|
|
// Copy all original data
|
|
for key, value := range data {
|
|
result[key] = value
|
|
}
|
|
|
|
// Merge fields
|
|
for targetField, config := range mergeConfig {
|
|
sourceFields := config["fields"].([]string)
|
|
separator := config["separator"].(string)
|
|
|
|
var values []string
|
|
for _, field := range sourceFields {
|
|
if val, ok := data[field]; ok && val != nil {
|
|
values = append(values, fmt.Sprintf("%v", val))
|
|
}
|
|
}
|
|
|
|
if len(values) > 0 {
|
|
result[targetField] = strings.Join(values, separator)
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) prefixFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
prefix := h.getPrefix()
|
|
targetFields := h.getTargetFields()
|
|
|
|
for key, value := range data {
|
|
if len(targetFields) == 0 || contains(targetFields, key) {
|
|
result[prefix+key] = value
|
|
} else {
|
|
result[key] = value
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) suffixFields(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
suffix := h.getSuffix()
|
|
targetFields := h.getTargetFields()
|
|
|
|
for key, value := range data {
|
|
if len(targetFields) == 0 || contains(targetFields, key) {
|
|
result[key+suffix] = value
|
|
} else {
|
|
result[key] = value
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) transformKeys(data map[string]any) map[string]any {
|
|
result := make(map[string]any)
|
|
transformation := h.getKeyTransformation()
|
|
|
|
for key, value := range data {
|
|
newKey := h.applyKeyTransformation(key, transformation)
|
|
result[newKey] = value
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) applyKeyTransformation(key string, transformation string) string {
|
|
switch transformation {
|
|
case "lowercase":
|
|
return strings.ToLower(key)
|
|
case "uppercase":
|
|
return strings.ToUpper(key)
|
|
case "snake_case":
|
|
return h.toSnakeCase(key)
|
|
case "camel_case":
|
|
return h.toCamelCase(key)
|
|
case "kebab_case":
|
|
return h.toKebabCase(key)
|
|
case "pascal_case":
|
|
return h.toPascalCase(key)
|
|
default:
|
|
return key
|
|
}
|
|
}
|
|
|
|
func (h *FieldHandler) toSnakeCase(s string) string {
|
|
result := strings.ReplaceAll(s, " ", "_")
|
|
result = strings.ReplaceAll(result, "-", "_")
|
|
return strings.ToLower(result)
|
|
}
|
|
|
|
func (h *FieldHandler) toCamelCase(s string) string {
|
|
parts := strings.FieldsFunc(s, func(c rune) bool {
|
|
return c == ' ' || c == '_' || c == '-'
|
|
})
|
|
|
|
if len(parts) == 0 {
|
|
return s
|
|
}
|
|
|
|
result := strings.ToLower(parts[0])
|
|
for _, part := range parts[1:] {
|
|
if len(part) > 0 {
|
|
result += strings.ToUpper(part[:1]) + strings.ToLower(part[1:])
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) toKebabCase(s string) string {
|
|
result := strings.ReplaceAll(s, " ", "-")
|
|
result = strings.ReplaceAll(result, "_", "-")
|
|
return strings.ToLower(result)
|
|
}
|
|
|
|
func (h *FieldHandler) toPascalCase(s string) string {
|
|
camel := h.toCamelCase(s)
|
|
if len(camel) > 0 {
|
|
return strings.ToUpper(camel[:1]) + camel[1:]
|
|
}
|
|
return camel
|
|
}
|
|
|
|
func (h *FieldHandler) getTargetFields() []string {
|
|
if fields, ok := h.Payload.Data["fields"].([]interface{}); ok {
|
|
var result []string
|
|
for _, field := range fields {
|
|
if str, ok := field.(string); ok {
|
|
result = append(result, str)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (h *FieldHandler) getFieldMapping() map[string]string {
|
|
result := make(map[string]string)
|
|
if mapping, ok := h.Payload.Data["mapping"].(map[string]interface{}); ok {
|
|
for key, value := range mapping {
|
|
if str, ok := value.(string); ok {
|
|
result[key] = str
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) getNewFields() map[string]interface{} {
|
|
if fields, ok := h.Payload.Data["new_fields"].(map[string]interface{}); ok {
|
|
return fields
|
|
}
|
|
return make(map[string]interface{})
|
|
}
|
|
|
|
func (h *FieldHandler) getMergeConfig() map[string]map[string]interface{} {
|
|
result := make(map[string]map[string]interface{})
|
|
if config, ok := h.Payload.Data["merge_config"].(map[string]interface{}); ok {
|
|
for key, value := range config {
|
|
if configMap, ok := value.(map[string]interface{}); ok {
|
|
result[key] = configMap
|
|
}
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func (h *FieldHandler) getPrefix() string {
|
|
if prefix, ok := h.Payload.Data["prefix"].(string); ok {
|
|
return prefix
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (h *FieldHandler) getSuffix() string {
|
|
if suffix, ok := h.Payload.Data["suffix"].(string); ok {
|
|
return suffix
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func (h *FieldHandler) getKeyTransformation() string {
|
|
if transform, ok := h.Payload.Data["transformation"].(string); ok {
|
|
return transform
|
|
}
|
|
return ""
|
|
}
|
|
|
|
func NewFieldHandler(id string) *FieldHandler {
|
|
return &FieldHandler{
|
|
Operation: dag.Operation{ID: id, Key: "field", Type: dag.Function, Tags: []string{"data", "transformation", "field"}},
|
|
}
|
|
}
|