github.com/blend/go-sdk@v1.20220411.3/db/reflection.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package db
     9  
    10  import (
    11  	"reflect"
    12  )
    13  
    14  // ReflectValue returns the reflect.Value for an object following pointers.
    15  func ReflectValue(obj interface{}) reflect.Value {
    16  	v := reflect.ValueOf(obj)
    17  	for v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface {
    18  		v = v.Elem()
    19  	}
    20  	return v
    21  }
    22  
    23  // ReflectType retruns the reflect.Type for an object following pointers.
    24  func ReflectType(obj interface{}) reflect.Type {
    25  	t := reflect.TypeOf(obj)
    26  	for t.Kind() == reflect.Ptr || t.Kind() == reflect.Interface {
    27  		t = t.Elem()
    28  	}
    29  
    30  	return t
    31  }
    32  
    33  // ReflectSliceType returns the inner type of a slice following pointers.
    34  func ReflectSliceType(collection interface{}) reflect.Type {
    35  	v := reflect.ValueOf(collection)
    36  	for v.Kind() == reflect.Ptr {
    37  		v = v.Elem()
    38  	}
    39  	if v.Len() == 0 {
    40  		t := v.Type()
    41  		for t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice {
    42  			t = t.Elem()
    43  		}
    44  		return t
    45  	}
    46  	v = v.Index(0)
    47  	for v.Kind() == reflect.Interface || v.Kind() == reflect.Ptr {
    48  		v = v.Elem()
    49  	}
    50  	return v.Type()
    51  }
    52  
    53  // makeNew creates a new object.
    54  func makeNew(t reflect.Type) interface{} {
    55  	return reflect.New(t).Interface()
    56  }
    57  
    58  func makeSliceOfType(t reflect.Type) interface{} {
    59  	return reflect.New(reflect.SliceOf(t)).Interface()
    60  }
    61  
    62  // haveSameUnderlyingTypes returns if T and V are such that V is *T or V is **T etc.
    63  // It handles the cases where we're assigning T = convert(**T) which can happen when we're setting up
    64  // scan output array.
    65  // Convert can smush T and **T together somehow.
    66  func haveSameUnderlyingTypes(t, v reflect.Value) bool {
    67  	tt := t.Type()
    68  	tv := ReflectType(v)
    69  	return tv.AssignableTo(tt) || tv.ConvertibleTo(tt)
    70  }