141 lines
3.9 KiB
Go
141 lines
3.9 KiB
Go
package lx
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Field represents a key-value pair where the key is a string and the value is of any type.
|
|
type Field struct {
|
|
Key string
|
|
Value interface{}
|
|
}
|
|
|
|
// Fields represents a slice of key-value pairs.
|
|
type Fields []Field
|
|
|
|
// Map converts the Fields slice to a map[string]interface{}.
|
|
// This is useful for backward compatibility or when map operations are needed.
|
|
// Example:
|
|
//
|
|
// fields := lx.Fields{{"user", "alice"}, {"age", 30}}
|
|
// m := fields.Map() // Returns map[string]interface{}{"user": "alice", "age": 30}
|
|
func (f Fields) Map() map[string]interface{} {
|
|
m := make(map[string]interface{}, len(f))
|
|
for _, pair := range f {
|
|
m[pair.Key] = pair.Value
|
|
}
|
|
return m
|
|
}
|
|
|
|
// Get returns the value for a given key and a boolean indicating if the key was found.
|
|
// This provides O(n) lookup, which is fine for small numbers of fields.
|
|
// Example:
|
|
//
|
|
// fields := lx.Fields{{"user", "alice"}, {"age", 30}}
|
|
// value, found := fields.Get("user") // Returns "alice", true
|
|
func (f Fields) Get(key string) (interface{}, bool) {
|
|
for _, pair := range f {
|
|
if pair.Key == key {
|
|
return pair.Value, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
// Filter returns a new Fields slice containing only pairs where the predicate returns true.
|
|
// Example:
|
|
//
|
|
// fields := lx.Fields{{"user", "alice"}, {"password", "secret"}, {"age", 30}}
|
|
// filtered := fields.Filter(func(key string, value interface{}) bool {
|
|
// return key != "password" // Remove sensitive fields
|
|
// })
|
|
func (f Fields) Filter(predicate func(key string, value interface{}) bool) Fields {
|
|
result := make(Fields, 0, len(f))
|
|
for _, pair := range f {
|
|
if predicate(pair.Key, pair.Value) {
|
|
result = append(result, pair)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Translate returns a new Fields slice with keys translated according to the provided mapping.
|
|
// Keys not in the mapping are passed through unchanged. This is useful for adapters like Victoria.
|
|
// Example:
|
|
//
|
|
// fields := lx.Fields{{"user", "alice"}, {"timestamp", time.Now()}}
|
|
// translated := fields.Translate(map[string]string{
|
|
// "user": "username",
|
|
// "timestamp": "ts",
|
|
// })
|
|
// // Returns: {{"username", "alice"}, {"ts", time.Now()}}
|
|
func (f Fields) Translate(mapping map[string]string) Fields {
|
|
result := make(Fields, len(f))
|
|
for i, pair := range f {
|
|
if newKey, ok := mapping[pair.Key]; ok {
|
|
result[i] = Field{Key: newKey, Value: pair.Value}
|
|
} else {
|
|
result[i] = pair
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
// Merge merges another Fields slice into this one, with the other slice's fields taking precedence
|
|
// for duplicate keys (overwrites existing keys).
|
|
// Example:
|
|
//
|
|
// base := lx.Fields{{"user", "alice"}, {"age", 30}}
|
|
// additional := lx.Fields{{"age", 31}, {"city", "NYC"}}
|
|
// merged := base.Merge(additional)
|
|
// // Returns: {{"user", "alice"}, {"age", 31}, {"city", "NYC"}}
|
|
func (f Fields) Merge(other Fields) Fields {
|
|
result := make(Fields, 0, len(f)+len(other))
|
|
|
|
// Create a map to track which keys from 'other' we've seen
|
|
seen := make(map[string]bool, len(other))
|
|
|
|
// First add all fields from 'f'
|
|
result = append(result, f...)
|
|
|
|
// Then add fields from 'other', overwriting duplicates
|
|
for _, pair := range other {
|
|
// Check if this key already exists in result
|
|
found := false
|
|
for i, existing := range result {
|
|
if existing.Key == pair.Key {
|
|
result[i] = pair // Overwrite
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
result = append(result, pair)
|
|
}
|
|
seen[pair.Key] = true
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// String returns a human-readable string representation of the fields.
|
|
// Example:
|
|
//
|
|
// fields := lx.Fields{{"user", "alice"}, {"age", 30}}
|
|
// str := fields.String() // Returns: "[user=alice age=30]"
|
|
func (f Fields) String() string {
|
|
var builder strings.Builder
|
|
builder.WriteString(LeftBracket)
|
|
for i, pair := range f {
|
|
if i > 0 {
|
|
builder.WriteString(Space)
|
|
}
|
|
builder.WriteString(pair.Key)
|
|
builder.WriteString("=")
|
|
builder.WriteString(fmt.Sprint(pair.Value))
|
|
}
|
|
builder.WriteString(RightBracket)
|
|
return builder.String()
|
|
}
|