stardb/reflect.go

258 lines
6.9 KiB
Go
Raw Permalink Normal View History

2021-06-16 15:26:58 +08:00
package stardb
import (
"errors"
"reflect"
2021-07-21 17:25:57 +08:00
"time"
2021-06-16 15:26:58 +08:00
)
2026-03-07 19:27:44 +08:00
// setStructFieldsFromRow sets struct fields from a row result using reflection
func (r *StarRows) setStructFieldsFromRow(target interface{}, tagKey string, rowIndex int) error {
targetType := reflect.TypeOf(target)
targetValue := reflect.ValueOf(target)
if targetType.Kind() == reflect.Ptr {
targetValue = targetValue.Elem()
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if targetType.Kind() != reflect.Ptr && !targetValue.CanSet() {
return errors.New("target is not writable")
2021-06-16 15:26:58 +08:00
}
2026-03-07 19:27:44 +08:00
if targetType.Kind() == reflect.Ptr {
targetType = targetType.Elem()
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if targetValue.Kind() != reflect.Struct {
return errors.New("target is not a struct")
2021-06-16 15:26:58 +08:00
}
2021-06-17 14:58:29 +08:00
2026-03-07 19:27:44 +08:00
for i := 0; i < targetType.NumField(); i++ {
field := targetType.Field(i)
fieldValue := targetValue.Field(i)
tagValue := field.Tag.Get(tagKey)
2021-06-17 14:58:29 +08:00
2026-03-07 19:27:44 +08:00
// Handle nested structs
if fieldValue.Kind() == reflect.Ptr && reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
if tagValue == "" {
2021-07-21 17:25:57 +08:00
continue
}
2026-03-07 19:27:44 +08:00
if tagValue == "---" {
nestedPtr := reflect.New(reflect.TypeOf(fieldValue.Interface()).Elem()).Interface()
r.setStructFieldsFromRow(nestedPtr, tagKey, rowIndex)
targetValue.Field(i).Set(reflect.ValueOf(nestedPtr))
2021-07-21 17:25:57 +08:00
continue
}
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if fieldValue.Kind() == reflect.Struct {
if tagValue == "" {
2021-07-21 17:25:57 +08:00
continue
}
2026-03-07 19:27:44 +08:00
if tagValue == "---" {
nestedPtr := reflect.New(reflect.TypeOf(targetValue.Field(i).Interface())).Interface()
r.setStructFieldsFromRow(nestedPtr, tagKey, rowIndex)
targetValue.Field(i).Set(reflect.ValueOf(nestedPtr).Elem())
2021-07-21 17:25:57 +08:00
continue
}
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if tagValue == "" {
2021-06-16 15:26:58 +08:00
continue
}
2026-03-07 19:27:44 +08:00
// Check if column exists
if _, ok := r.Row(rowIndex).columnIndex[tagValue]; !ok {
2021-06-16 15:26:58 +08:00
continue
}
2026-03-07 19:27:44 +08:00
// Set field value based on type
r.setFieldValue(fieldValue, tagValue, rowIndex)
2021-06-16 15:26:58 +08:00
}
return nil
}
2026-03-07 19:27:44 +08:00
// setFieldValue sets a single field value
func (r *StarRows) setFieldValue(fieldValue reflect.Value, columnName string, rowIndex int) {
row := r.Row(rowIndex)
switch fieldValue.Kind() {
case reflect.String:
fieldValue.SetString(row.MustString(columnName))
case reflect.Int:
fieldValue.SetInt(int64(row.MustInt(columnName)))
case reflect.Int8:
fieldValue.SetInt(int64(int8(row.MustInt64(columnName))))
case reflect.Int16:
fieldValue.SetInt(int64(int16(row.MustInt64(columnName))))
case reflect.Int32:
fieldValue.SetInt(int64(row.MustInt32(columnName)))
case reflect.Int64:
fieldValue.SetInt(row.MustInt64(columnName))
case reflect.Uint:
fieldValue.SetUint(uint64(row.MustUint64(columnName)))
case reflect.Uint8:
fieldValue.SetUint(uint64(uint8(row.MustUint64(columnName))))
case reflect.Uint16:
fieldValue.SetUint(uint64(uint16(row.MustUint64(columnName))))
case reflect.Uint32:
fieldValue.SetUint(uint64(uint32(row.MustUint64(columnName))))
case reflect.Uint64:
fieldValue.SetUint(row.MustUint64(columnName))
case reflect.Bool:
fieldValue.SetBool(row.MustBool(columnName))
case reflect.Float32:
fieldValue.SetFloat(float64(row.MustFloat32(columnName)))
case reflect.Float64:
fieldValue.SetFloat(row.MustFloat64(columnName))
case reflect.Interface, reflect.Struct, reflect.Ptr:
// Handle special types like time.Time
colIndex := r.columnIndex[columnName]
val := row.Result()[colIndex]
if t, ok := val.(time.Time); ok {
fieldValue.Set(reflect.ValueOf(t))
2021-06-16 15:26:58 +08:00
}
}
}
2026-03-07 19:27:44 +08:00
// getStructFieldValues extracts all field values from a struct
func getStructFieldValues(target interface{}, tagKey string) (map[string]interface{}, error) {
2021-06-16 15:26:58 +08:00
result := make(map[string]interface{})
2026-03-07 19:27:44 +08:00
targetType := reflect.TypeOf(target)
targetValue := reflect.ValueOf(target)
if targetType.Kind() == reflect.Ptr {
if targetValue.IsNil() {
return nil, errors.New("pointer target is nil")
2021-07-21 17:25:57 +08:00
}
2026-03-07 19:27:44 +08:00
targetType = targetType.Elem()
targetValue = targetValue.Elem()
2021-06-16 15:26:58 +08:00
}
2026-03-07 19:27:44 +08:00
if targetValue.Kind() != reflect.Struct {
return nil, errors.New("target is not a struct")
2021-07-21 17:25:57 +08:00
}
2026-03-07 19:27:44 +08:00
for i := 0; i < targetType.NumField(); i++ {
field := targetType.Field(i)
fieldValue := targetValue.Field(i)
tagValue := field.Tag.Get(tagKey)
// Handle nested pointer structs
if fieldValue.Kind() == reflect.Ptr && reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
if fieldValue.IsNil() {
2021-07-21 17:25:57 +08:00
continue
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if tagValue == "---" {
nestedValues, err := getStructFieldValues(reflect.ValueOf(fieldValue.Elem().Interface()).Interface(), tagKey)
2021-07-21 17:25:57 +08:00
if err != nil {
return result, err
}
2026-03-07 19:27:44 +08:00
for k, v := range nestedValues {
2021-07-21 17:25:57 +08:00
result[k] = v
}
continue
2021-06-17 14:58:29 +08:00
}
}
2026-03-07 19:27:44 +08:00
// Handle nested structs
if targetValue.Field(i).Kind() == reflect.Struct {
if tagValue == "---" {
nestedValues, err := getStructFieldValues(targetValue.Field(i).Interface(), tagKey)
2021-07-21 17:25:57 +08:00
if err != nil {
return result, err
}
2026-03-07 19:27:44 +08:00
for k, v := range nestedValues {
2021-07-21 17:25:57 +08:00
result[k] = v
}
continue
2021-06-17 14:58:29 +08:00
}
}
2026-03-07 19:27:44 +08:00
if tagValue == "" {
2021-06-16 15:26:58 +08:00
continue
}
2026-03-07 19:27:44 +08:00
if !fieldValue.CanInterface() {
2021-06-16 15:26:58 +08:00
continue
}
2026-03-07 19:27:44 +08:00
result[tagValue] = fieldValue.Interface()
2021-06-16 15:26:58 +08:00
}
2026-03-07 19:27:44 +08:00
2021-06-16 15:26:58 +08:00
return result, nil
}
2026-03-07 19:27:44 +08:00
// getStructFieldNames extracts all field names (tag values) from a struct
func getStructFieldNames(target interface{}, tagKey string) ([]string, error) {
2021-06-16 15:26:58 +08:00
var result []string
2026-03-07 19:27:44 +08:00
if !isStruct(target) {
return []string{}, errors.New("target is not a struct")
2021-06-16 15:26:58 +08:00
}
2026-03-07 19:27:44 +08:00
targetType := reflect.TypeOf(target)
targetValue := reflect.ValueOf(target)
if targetType.Kind() == reflect.Ptr {
if targetValue.IsNil() {
return []string{}, errors.New("pointer target is nil")
2021-07-21 17:25:57 +08:00
}
2026-03-07 19:27:44 +08:00
targetType = targetType.Elem()
targetValue = targetValue.Elem()
2021-06-16 15:26:58 +08:00
}
2026-03-07 19:27:44 +08:00
for i := 0; i < targetType.NumField(); i++ {
fieldValue := targetValue.Field(i)
field := targetType.Field(i)
tagValue := field.Tag.Get(tagKey)
// Handle nested pointer structs
if fieldValue.Kind() == reflect.Ptr && reflect.TypeOf(fieldValue.Interface()).Elem().Kind() == reflect.Struct {
if fieldValue.IsNil() {
2021-07-21 17:25:57 +08:00
continue
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if tagValue == "---" {
nestedNames, err := getStructFieldNames(reflect.ValueOf(fieldValue.Elem().Interface()).Interface(), tagKey)
2021-07-21 17:25:57 +08:00
if err != nil {
return result, err
}
2026-03-07 19:27:44 +08:00
result = append(result, nestedNames...)
2021-07-21 17:25:57 +08:00
continue
2021-06-17 14:58:29 +08:00
}
}
2026-03-07 19:27:44 +08:00
// Handle nested structs
if targetValue.Field(i).Kind() == reflect.Struct && tagValue == "---" {
nestedNames, err := getStructFieldNames(targetValue.Field(i).Interface(), tagKey)
2021-06-17 14:58:29 +08:00
if err != nil {
return result, err
}
2026-03-07 19:27:44 +08:00
result = append(result, nestedNames...)
continue
2021-06-17 14:58:29 +08:00
}
2026-03-07 19:27:44 +08:00
if tagValue != "" {
result = append(result, tagValue)
2021-06-16 15:26:58 +08:00
}
}
2026-03-07 19:27:44 +08:00
2021-06-16 15:26:58 +08:00
return result, nil
}
2026-03-07 19:27:44 +08:00
// isWritable checks if a value is writable
func isWritable(target interface{}) bool {
targetType := reflect.TypeOf(target)
targetValue := reflect.ValueOf(target)
return targetType.Kind() == reflect.Ptr || targetValue.CanSet()
}
// isStruct checks if a value is a struct
func isStruct(target interface{}) bool {
targetValue := reflect.ValueOf(target)
if targetValue.Kind() == reflect.Ptr {
targetValue = targetValue.Elem()
2021-06-16 15:26:58 +08:00
}
2026-03-07 19:27:44 +08:00
return targetValue.Kind() == reflect.Struct
2021-06-16 15:26:58 +08:00
}