github.com/ecodeclub/eorm@v0.0.2-0.20231001112437-dae71da914d0/internal/valuer/reflect.go (about) 1 // Copyright 2021 ecodeclub 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package valuer 16 17 import ( 18 "reflect" 19 20 "github.com/ecodeclub/eorm/internal/rows" 21 22 "github.com/ecodeclub/eorm/internal/errs" 23 "github.com/ecodeclub/eorm/internal/model" 24 ) 25 26 var _ Creator = NewReflectValue 27 28 // reflectValue 基于反射的 Value 29 type reflectValue struct { 30 val reflect.Value 31 meta *model.TableMeta 32 } 33 34 // NewReflectValue 返回一个封装好的,基于反射实现的 Value 35 // 输入 val 必须是一个指向结构体实例的指针,而不能是任何其它类型 36 func NewReflectValue(val interface{}, meta *model.TableMeta) Value { 37 return reflectValue{ 38 val: reflect.ValueOf(val).Elem(), 39 meta: meta, 40 } 41 } 42 43 // Field 返回字段值 44 func (r reflectValue) Field(name string) (reflect.Value, error) { 45 res, ok := r.fieldByIndex(name) 46 if !ok { 47 return reflect.Value{}, errs.NewInvalidFieldError(name) 48 } 49 return res, nil 50 } 51 52 func (r reflectValue) fieldByIndex(name string) (reflect.Value, bool) { 53 cm, ok := r.meta.FieldMap[name] 54 if !ok { 55 return reflect.Value{}, false 56 } 57 value := r.val 58 for _, i := range cm.FieldIndexes { 59 value = value.Field(i) 60 } 61 return value, true 62 } 63 64 func (r reflectValue) SetColumns(rows rows.Rows) error { 65 cs, err := rows.Columns() 66 if err != nil { 67 return err 68 } 69 if len(cs) > len(r.meta.Columns) { 70 return errs.ErrTooManyColumns 71 } 72 73 // TODO 性能优化 74 // colValues 和 colEleValues 实质上最终都指向同一个对象 75 colValues := make([]interface{}, len(cs)) 76 colEleValues := make([]reflect.Value, len(cs)) 77 78 for i, c := range cs { 79 cm, ok := r.meta.ColumnMap[c] 80 if !ok { 81 return errs.NewInvalidColumnError(c) 82 } 83 val := reflect.New(cm.Typ) 84 colValues[i] = val.Interface() 85 colEleValues[i] = val.Elem() 86 } 87 88 if err = rows.Scan(colValues...); err != nil { 89 return err 90 } 91 92 for i, c := range cs { 93 cm := r.meta.ColumnMap[c] 94 fd, _ := r.fieldByIndex(cm.FieldName) 95 fd.Set(colEleValues[i]) 96 } 97 return nil 98 }