Files
Курнат Андрей 2315f25754 Initial QSfera import
2026-06-07 10:20:04 +03:00

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()
}