feat: 添加 Lookuper 接口和 MustLookup 方法
- 新增 Lookuper 接口,提供 Lookup 和 MustLookup 两种路径查找方式 - Accessor 接口继承 Lookuper,保持向后兼容 - MustLookup 在路径不存在时返回 Nil 访问器,简化调用代码 - 更新 fieldx.Schema 使用 Lookuper 接口,支持更灵活的数据源 - 添加 Required 字段选项,控制字段不存在时的行为
This commit is contained in:
parent
b73099d205
commit
39da1d55dd
@ -3,9 +3,9 @@ package fieldx
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"git.fsdpf.net/go/reflux"
|
"git.fsdpf.net/go/reflux"
|
||||||
|
"git.fsdpf.net/go/reflux/valuex"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FieldType 定义字段类型
|
// FieldType 定义字段类型
|
||||||
@ -31,6 +31,10 @@ type Field struct {
|
|||||||
Value string `json:"value,omitempty"`
|
Value string `json:"value,omitempty"`
|
||||||
// Fields 当 Type 为 object 时,包含嵌套的字段定义
|
// Fields 当 Type 为 object 时,包含嵌套的字段定义
|
||||||
Fields Schema `json:"fields,omitempty"`
|
Fields Schema `json:"fields,omitempty"`
|
||||||
|
// Required 标识字段是否必须存在,仅对 FieldTypeField 类型有效
|
||||||
|
// 如果为 true,字段不存在时会返回错误
|
||||||
|
// 如果为 false(默认),字段不存在时返回 nil
|
||||||
|
Required bool `json:"required,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Schema 定义字段映射表
|
// Schema 定义字段映射表
|
||||||
@ -48,17 +52,23 @@ func (s Schema) Generate(source any) (result map[string]any, err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// 使用 reflux 包装源数据,提供统一的访问接口
|
var lkp valuex.Lookuper = valuex.Nil
|
||||||
rfx := reflux.New(source)
|
|
||||||
|
if v, ok := source.(valuex.Lookuper); ok {
|
||||||
|
lkp = v
|
||||||
|
} else if source != nil {
|
||||||
|
// 使用 reflux 包装源数据,提供统一的访问接口
|
||||||
|
lkp = reflux.New(source)
|
||||||
|
}
|
||||||
|
|
||||||
result = make(map[string]any)
|
result = make(map[string]any)
|
||||||
err = s.generateFields(rfx, result)
|
err = s.generateFields(lkp, result)
|
||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// generateFields 递归生成字段
|
// generateFields 递归生成字段
|
||||||
func (s Schema) generateFields(source reflux.R, target map[string]any) error {
|
func (s Schema) generateFields(source valuex.Lookuper, target map[string]any) error {
|
||||||
for fieldName, field := range s {
|
for fieldName, field := range s {
|
||||||
value, err := field.generateValue(source)
|
value, err := field.generateValue(source)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -70,12 +80,12 @@ func (s Schema) generateFields(source reflux.R, target map[string]any) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generateValue 生成字段值
|
// generateValue 生成字段值
|
||||||
func (f Field) generateValue(source reflux.R) (any, error) {
|
func (f Field) generateValue(source valuex.Lookuper) (any, error) {
|
||||||
switch f.Type {
|
switch f.Type {
|
||||||
case FieldTypeString:
|
case FieldTypeString:
|
||||||
return f.Value, nil
|
return f.Value, nil
|
||||||
case FieldTypeField:
|
case FieldTypeField:
|
||||||
return getFieldValue(f.Value, source)
|
return getFieldValue(f.Value, source, f.Required)
|
||||||
case FieldTypeObject:
|
case FieldTypeObject:
|
||||||
// 嵌套对象
|
// 嵌套对象
|
||||||
nestedResult := make(map[string]any)
|
nestedResult := make(map[string]any)
|
||||||
@ -91,17 +101,16 @@ func (f Field) generateValue(source reflux.R) (any, error) {
|
|||||||
|
|
||||||
// getFieldValue 从源对象获取字段值
|
// getFieldValue 从源对象获取字段值
|
||||||
// 支持点号分隔的路径,如 "user.name"
|
// 支持点号分隔的路径,如 "user.name"
|
||||||
func getFieldValue(path string, source reflux.R) (any, error) {
|
// required: 如果为 true,字段不存在时返回错误;如果为 false,字段不存在时返回 nil
|
||||||
// 分割路径
|
func getFieldValue(path string, source valuex.Lookuper, required bool) (any, error) {
|
||||||
parts := strings.Split(path, ".")
|
accessor, ok := source.Lookup(path)
|
||||||
|
|
||||||
// 检查字段是否存在
|
// 检查字段是否存在
|
||||||
if !source.Exists(parts...) {
|
// 只有 required 为 true 时才返回错误
|
||||||
|
if !ok && required {
|
||||||
return nil, fmt.Errorf("field not found: %s", path)
|
return nil, fmt.Errorf("field not found: %s", path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取值
|
|
||||||
accessor := source.Get(parts...)
|
|
||||||
return accessor.Any(), nil
|
return accessor.Any(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,6 +162,13 @@ func fieldFromMap(data any) (Field, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 解析 required
|
||||||
|
if required, ok := m["required"]; ok {
|
||||||
|
if requiredBool, ok := required.(bool); ok {
|
||||||
|
field.Required = requiredBool
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 解析 fields (嵌套)
|
// 解析 fields (嵌套)
|
||||||
if fields, ok := m["fields"]; ok {
|
if fields, ok := m["fields"]; ok {
|
||||||
if fieldsMap, ok := fields.(map[string]any); ok {
|
if fieldsMap, ok := fields.(map[string]any); ok {
|
||||||
|
|||||||
10
rfx.go
10
rfx.go
@ -566,6 +566,16 @@ func (r *rfx) Lookup(path string) (valuex.Accessor, bool) {
|
|||||||
return valuex.Nil, false
|
return valuex.Nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustLookup 根据路径查找并直接返回对应值的访问器
|
||||||
|
// 如果路径不存在,返回 valuex.Nil 访问器(所有方法返回零值)
|
||||||
|
func (r *rfx) MustLookup(path string) valuex.Accessor {
|
||||||
|
v := r.Get(path)
|
||||||
|
if v.Exists() {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return valuex.Nil
|
||||||
|
}
|
||||||
|
|
||||||
// Ptr 返回指向当前值的指针
|
// Ptr 返回指向当前值的指针
|
||||||
func (r *rfx) Ptr() any {
|
func (r *rfx) Ptr() any {
|
||||||
v := r.value
|
v := r.value
|
||||||
|
|||||||
@ -2,11 +2,20 @@ package valuex
|
|||||||
|
|
||||||
import "reflect"
|
import "reflect"
|
||||||
|
|
||||||
// Accessor 为参数值转换相关接口
|
// Lookuper 提供基于路径查找值的能力
|
||||||
type Accessor interface {
|
type Lookuper interface {
|
||||||
// Lookup 根据路径查找并返回对应值的访问器
|
// Lookup 根据路径查找并返回对应值的访问器
|
||||||
Lookup(path string) (Accessor, bool)
|
Lookup(path string) (Accessor, bool)
|
||||||
|
|
||||||
|
// MustLookup 根据路径查找并直接返回对应值的访问器
|
||||||
|
// 如果路径不存在,返回 Nil 访问器(所有方法返回零值)
|
||||||
|
MustLookup(path string) Accessor
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessor 为参数值转换相关接口
|
||||||
|
type Accessor interface {
|
||||||
|
Lookuper
|
||||||
|
|
||||||
// Raw 返回底层的 reflect.Value
|
// Raw 返回底层的 reflect.Value
|
||||||
Raw() reflect.Value
|
Raw() reflect.Value
|
||||||
|
|
||||||
|
|||||||
@ -14,6 +14,11 @@ func (n *nilAccessor) Lookup(path string) (Accessor, bool) {
|
|||||||
return n, false
|
return n, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustLookup 总是返回自身,表示路径不存在
|
||||||
|
func (n *nilAccessor) MustLookup(path string) Accessor {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
func (n *nilAccessor) Raw() reflect.Value {
|
func (n *nilAccessor) Raw() reflect.Value {
|
||||||
return reflect.Value{}
|
return reflect.Value{}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user