@@ -621,7 +621,7 @@ func (r *Rows) StructScan(dest interface{}) error {
621621 r .started = true
622622 }
623623
624- octx := reflectx . NewObjectContext ()
624+ octx := newObjectContext ()
625625 err := fieldsByTraversal (octx , v , r .fields , r .values , true )
626626 if err != nil {
627627 return err
@@ -782,7 +782,7 @@ func (r *Row) scanAny(dest interface{}, structOnly bool) error {
782782 }
783783 values := make ([]interface {}, len (columns ))
784784
785- octx := reflectx . NewObjectContext ()
785+ octx := newObjectContext ()
786786
787787 err = fieldsByTraversal (octx , v , fields , values , true )
788788 if err != nil {
@@ -951,7 +951,7 @@ func scanAll(rows rowsi, dest interface{}, structOnly bool) error {
951951 return fmt .Errorf ("missing destination name %s in %T" , columns [f ], dest )
952952 }
953953 values = make ([]interface {}, len (columns ))
954- octx := reflectx . NewObjectContext ()
954+ octx := newObjectContext ()
955955
956956 for rows .Next () {
957957 // create a new struct type (which returns PtrTo) and indirect it
@@ -1024,7 +1024,7 @@ func baseType(t reflect.Type, expected reflect.Kind) (reflect.Type, error) {
10241024// when iterating over many rows. Empty traversals will get an interface pointer.
10251025// Because of the necessity of requesting ptrs or values, it's considered a bit too
10261026// specialized for inclusion in reflectx itself.
1027- func fieldsByTraversal (octx * reflectx. ObjectContext , v reflect.Value , traversals [][]int , values []interface {}, ptrs bool ) error {
1027+ func fieldsByTraversal (octx * objectContext , v reflect.Value , traversals [][]int , values []interface {}, ptrs bool ) error {
10281028 v = reflect .Indirect (v )
10291029 if v .Kind () != reflect .Struct {
10301030 return errors .New ("argument not a struct" )
@@ -1055,3 +1055,50 @@ func missingFields(transversals [][]int) (field int, err error) {
10551055 }
10561056 return 0 , nil
10571057}
1058+
1059+ // objectContext provides a single layer to abstract away
1060+ // nested struct scanning functionality
1061+ type objectContext struct {
1062+ value reflect.Value
1063+ }
1064+
1065+ func newObjectContext () * objectContext {
1066+ return & objectContext {}
1067+ }
1068+
1069+ // NewRow updates the object reference.
1070+ // This ensures all columns point to the same object
1071+ func (o * objectContext ) NewRow (value reflect.Value ) {
1072+ o .value = value
1073+ }
1074+
1075+ // FieldForIndexes returns the value for address. If the address is a nested struct,
1076+ // a nestedFieldScanner is returned instead of the standard value reference
1077+ func (o * objectContext ) FieldForIndexes (indexes []int ) reflect.Value {
1078+ if len (indexes ) == 1 {
1079+ return reflectx .FieldByIndexes (o .value , indexes )
1080+ }
1081+
1082+ obj := & nestedFieldScanner {
1083+ parent : o ,
1084+ indexes : indexes ,
1085+ }
1086+
1087+ return reflect .ValueOf (obj ).Elem ()
1088+ }
1089+
1090+ // nestedFieldScanner will only forward the Scan to the nested value if
1091+ // the database value is not nil.
1092+ type nestedFieldScanner struct {
1093+ parent * objectContext
1094+ indexes []int
1095+ }
1096+
1097+ // Scan implements sql.Scanner.
1098+ func (o * nestedFieldScanner ) Scan (src interface {}) error {
1099+ if src == nil {
1100+ return nil
1101+ }
1102+ dest := reflectx .FieldByIndexes (o .parent .value , o .indexes )
1103+ return convertAssign (dest .Addr ().Interface (), src )
1104+ }
0 commit comments