Skip to content

Commit

Permalink
✨ feat:improve mapping
Browse files Browse the repository at this point in the history
  • Loading branch information
jingyuexing committed Jan 1, 2025
1 parent 1e483f4 commit 55924be
Show file tree
Hide file tree
Showing 4 changed files with 263 additions and 51 deletions.
88 changes: 73 additions & 15 deletions datetime.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,24 +118,82 @@ func From(time time.Time) DateTime {
return d
}

// 通用的 SetDateTime 函数
func (dt DateTime) SetDateTime(year, month, day, hour, minute, second, nanosecond int) DateTime {
newTime := time.Date(year, time.Month(month), day, hour, minute, second, nanosecond, time.UTC)
return DateTime{
time: newTime,
DateFormat: dt.DateFormat,
TimeFormat: dt.TimeFormat,
Year: newTime.Year(),
Month: int(newTime.Month()),
Day: newTime.Day(),
Hour: newTime.Hour(),
Minute: newTime.Minute(),
Second: newTime.Second(),
Nanosecond: newTime.Nanosecond(),
}
}

func (dt DateTime) SetYear(year int, month int, day int, hour int, minute int, second int, nanosecond int) DateTime {
d := DateTime{
time: time.Date(year, time.Month(month), day, hour, minute, second, nanosecond, time.UTC),
DateFormat: dt.DateFormat,
TimeFormat: dt.TimeFormat,
monthFormat: dt.monthFormat,
weekFormat: dt.weekFormat,
}
d.Year = d.time.Year()
d.Month = int(d.time.Month())
d.Day = d.time.Day()
d.Hour = d.time.Hour()
d.Minute = d.time.Minute()
d.Second = d.time.Second()
d.Nanosecond = d.time.Nanosecond()
return d
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
}

func (dt DateTime) Set(opts ...DataOption[DateTime]) DateTime {

Check failure on line 142 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 142 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
for _, opt := range opts {
// 应用每个选项函数,修改 dt
opt(&dt)
}
return dt
}

func SetDateTimeOption(setter func(dt DateTime, year, month, day, hour, minute, second, nanosecond int) DateTime) DataOption[DateTime] {

Check failure on line 150 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 150 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return func(dt *DateTime) {
*dt = setter(*dt, dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, dt.Second, dt.Nanosecond)
}
}

func WithDateTimeYear(year int) DataOption[DateTime] {

Check failure on line 156 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 156 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, _, month, day, hour, minute, second, nanosecond int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}

func WithDateTimeMonth(month int) DataOption[DateTime] {

Check failure on line 162 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 162 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, year, _, day, hour, minute, second, nanosecond int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}

func WithDateTimeDay(day int) DataOption[DateTime] {

Check failure on line 168 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 168 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, year, month, _, hour, minute, second, nanosecond int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}

func WithDateTimeHour(hour int) DataOption[DateTime] {

Check failure on line 174 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 174 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, year, month, day, _, minute, second, nanosecond int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}

func WithDateTimeMinute(minute int) DataOption[DateTime] {

Check failure on line 180 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 180 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, year, month, day, hour, _, second, nanosecond int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}

func WithDateTimeSecond(second int) DataOption[DateTime] {

Check failure on line 186 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 186 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, year, month, day, hour, minute, _, nanosecond int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}

func WithDateTimeNanosecond(nanosecond int) DataOption[DateTime] {

Check failure on line 192 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.18)

undefined: DataOption

Check failure on line 192 in datetime.go

View workflow job for this annotation

GitHub Actions / build (1.19)

undefined: DataOption
return SetDateTimeOption(func(dt DateTime, year, month, day, hour, minute, second, _ int) DateTime {
return dt.SetDateTime(year, month, day, hour, minute, second, nanosecond)
})
}
func (dt DateTime) SetMonth(month int, day int, hour int, minute int, second int, nanosecond int) DateTime {
return dt.SetYear(dt.Year, month, day, hour, minute, second, nanosecond)
}
Expand Down
195 changes: 163 additions & 32 deletions mapping.go
Original file line number Diff line number Diff line change
@@ -1,71 +1,202 @@
package utils

import "reflect"
import (
"reflect"
"strings"
"unicode"
)

// KeyFunc defines a function type for generating map keys from struct fields
type KeyFunc func(field reflect.StructField) string

// omit specify field in target struct
//
// type People struct {
// Name string
// Age int
// Address string
// }
// p := &People{
// Name: "william",
// Age: 20,
// Address: "BC",
// }
// Omit(p,[]string{"Name"})
// type People struct {
// Name string
// Age int
// Address string
// }
//
// p := &People{
// Name: "william",
// Age: 20,
// Address: "BC",
// }
//
func Omit[T any](target T, fields []string) map[string]any {
// Omit(p,"Name")
func Omit[T any](target T, fields ...string) map[string]any {
mapping := map[string]bool{}
for _, value := range fields {
mapping[SnakeCase(value)] = true
mapping[value] = true
mapping[value] = true
}
result := StructFilter(target, func(field string, val reflect.Value) bool {
_, ok := mapping[field]
return !ok
})
}, nil)
return result
}

// pick specify field in target struct
//
// type People struct {
// Name string
// Age int
// Address string
// }
// p := &People{
// Name: "william",
// Age: 20,
// Address: "BC",
// }
// Pick(p,[]string{"Name"})
// type People struct {
// Name string
// Age int
// Address string
// }
//
// p := &People{
// Name: "william",
// Age: 20,
// Address: "BC",
// }
//
func Pick[T any](target T, fields []string) map[string]any {
// Pick(p,[]string{"Name"})
func Pick[T any](target T, fields ...string) map[string]any {
mapping := map[string]bool{}
for _, value := range fields {
mapping[value] = true
}
result := StructFilter(target, func(field string, val reflect.Value) bool {
_, ok := mapping[field]
return ok
})
}, nil)
return result
}

func StructFilter[T any](target T, callback func(field string, val reflect.Value) bool) map[string]any {
func jsonKeyFunc(field reflect.StructField) string {
if jsonTag := field.Tag.Get("json"); jsonTag != "" && jsonTag != "-" {
return jsonTag
}
return ""
}

// SnakeCase 将 CamelCase 转换为 snake_case,并处理缩写词
func SnakeCase(s string) string {
var result []rune
n := len(s)
allUpper := true

for _, r := range s {
if unicode.IsLower(r) {
allUpper = false
break
}
}

if allUpper {
return strings.ToLower(s)
}

for i := 0; i < n; i++ {
r := rune(s[i])

if unicode.IsUpper(r) {
if i > 0 && !unicode.IsUpper(rune(s[i-1])) {
result = append(result, '_')
}
result = append(result, unicode.ToLower(r))
} else {
result = append(result, r)
}
}
return string(result)
}

// GetFieldName 根据字段的 JSON 标签或字段名返回正确的字段名称
func GetFieldName(field reflect.StructField) string {
jsonTag := field.Tag.Get("json")
if jsonTag == "" {
return SnakeCase(field.Name)
}
jsonName := strings.Split(jsonTag, ",")[0] // 获取 JSON 标签的第一个部分
if jsonName != "" && jsonName != "-" {
return jsonName
}
return SnakeCase(field.Name)
}

func structFilterRecursive(
value reflect.Value,
t reflect.Type,
callback func(field string, val reflect.Value) bool,
keyFunc KeyFunc,
result map[string]any,
) {
for i := 0; i < value.NumField(); i++ {
field := t.Field(i)
fieldValue := value.Field(i)

key := keyFunc(field)

if field.Anonymous {
// If the field is an embedded struct, recurse into it
structFilterRecursive(fieldValue, fieldValue.Type(), callback, keyFunc, result)
} else if callback(key, fieldValue) && key != "" {
result[key] = fieldValue.Interface()
}
}
}

func StructFilter[T any](
target T,
callback func(field string, val reflect.Value) bool,
key KeyFunc,
) map[string]any {
reflectValue := reflect.ValueOf(target)
reflectType := reflect.TypeOf(target)
if reflectValue.Kind() == reflect.Pointer {
reflectValue = reflectValue.Elem()
reflectType = reflectType.Elem()
reflectType = reflectType.Elem()
}
GenKey := key
if key == nil {
GenKey = GetFieldName
}
result := make(map[string]any)
structFilterRecursive(reflectValue, reflectType, callback, GenKey, result)
return result
}

func resolvePointer(value reflect.Value) reflect.Value {
if value.Kind() == reflect.Pointer {
return reflect.Indirect(value)
}
return value
}

func GetFields[T any](target T, callback func(reflect.Value)) {
reflectValue := reflect.ValueOf(target)
reflectValue = resolvePointer(reflectValue)
for i := 0; i < reflectValue.NumField(); i++ {
field := reflectType.Field(i)
if callback(field.Name, reflectValue.FieldByName(field.Name)) {
result[field.Name] = reflectValue.FieldByName(field.Name).Interface()
field := reflectValue.Field(i)
fieldType := reflectValue.Type().Field(i)
if fieldType.Anonymous {
embeddedValue := resolvePointer(field)
if embeddedValue.Kind() == reflect.Struct {
field := embeddedValue.FieldByName(field.Type().Name())
callback(field)
}
} else {
callback(field)
}
}
}

// 泛型函数 ArrayFilter,接收一个目标数组 target 和回调函数 cb
func ArrayFilter[T any](target []T, cb func(T) []map[string]any) []map[string]any {
var result []map[string]any // 存储过滤后的结果

for _, item := range target {
// 调用回调函数 cb,对每个元素进行处理
filtered := cb(item)

// 如果 cb 函数返回非空的结果,则将其添加到最终结果中
if len(filtered) > 0 {
result = append(result, filtered...)
}
}

return result
}
13 changes: 12 additions & 1 deletion set.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ type Set[T comparable] map[T]bool

func (s Set[T]) Values() []T {
values := make([]T, 0)
for k, _ := range s {
for k := range s {
values = append(values, k)
}
return values
Expand All @@ -20,6 +20,17 @@ func (s Set[T]) Add(value T) bool {
return s[value]
}

func (s Set[T]) Adds(values ...T) bool {
allAdded := true

for _, value := range values {
if !s.Add(value) {
allAdded = allAdded && false
}
}
return allAdded
}

func NewSet[T comparable](value ...T) Set[T] {
set := make(Set[T],0)
for _,val := range value {
Expand Down
18 changes: 15 additions & 3 deletions utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,11 +613,11 @@ func TestBigNumber(t *testing.T){
num15 := utils.NewBigNumber("2")
result := num14.Divide(num15)
if result.String() != "0.500000" {
t.Error(fmt.Sprintf(" 1 / 2 should be 0.5, but got %s",result.String()))
t.Error(fmt.Sprintf(" 1 / 2 should be 0.5, but got %s\n",result.String()))
}
nums16 := utils.NewBigNumber("-12")
if nums16.AbsoluteValue().String() != "12" {
t.Error(fmt.Sprintf("the -12 absolute value should be 12, but got %s",nums16.AbsoluteValue().String()))
t.Error(fmt.Sprintf("the -12 absolute value should be 12, but got %s\n",nums16.AbsoluteValue().String()))
}

num17 := utils.NewBigNumber("12")
Expand All @@ -628,5 +628,17 @@ func TestBigNumber(t *testing.T){

func TestRevese(t *testing.T){
d := utils.Reverse([]string{"A","B","C","D","E","F"})
fmt.Printf("%v",d)
fmt.Printf("%v\n",d)
}

func TestDatatimeOption(t *testing.T){
dt := utils.NewDateTime()
dt = dt.Set(
utils.WithDateTimeYear(2018),
)
if dt.Year != 2018 {
t.Error(fmt.Sprintf(" expected 2018, but got %d",dt.Year))
}
fmt.Printf("datetime is %s\n",dt.String())

}

0 comments on commit 55924be

Please sign in to comment.