github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqx/daonull.go (about)

     1  package sqx
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"reflect"
     7  
     8  	"github.com/bingoohuang/gg/pkg/reflector"
     9  )
    10  
    11  // NullAny represents any that may be null.
    12  // NullAny implements the Scanner interface so it can be used as a scan destination.
    13  type NullAny struct {
    14  	Type reflect.Type
    15  	Val  reflect.Value
    16  }
    17  
    18  // Scan assigns a value from a database driver.
    19  //
    20  // The src value will be of one of the following types:
    21  //
    22  //	int64
    23  //	float64
    24  //	bool
    25  //	[]byte
    26  //	string
    27  //	time.Time
    28  //	nil - for NULL values
    29  //
    30  // An error should be returned if the value cannot be stored
    31  // without loss of information.
    32  //
    33  // Reference types such as []byte are only valid until the next call to Scan
    34  // and should not be retained. Their underlying memory is owned by the driver.
    35  // If retention is necessary, copy their values before the next call to Scan.
    36  func (n *NullAny) Scan(value interface{}) error {
    37  	if value == nil {
    38  		return nil
    39  	}
    40  
    41  	var err error
    42  	n.Val = reflect.ValueOf(value)
    43  	if converter, ok := CustomDriverValueConverters[n.Val.Type()]; ok {
    44  		value, err = converter.Convert(value)
    45  		if err != nil {
    46  			return err
    47  		}
    48  		n.Val = reflect.ValueOf(value)
    49  	}
    50  
    51  	if n.Type == nil {
    52  		return nil
    53  	}
    54  
    55  	switch n.Type.Kind() {
    56  	case reflect.String:
    57  		sn := &sql.NullString{}
    58  		if err := sn.Scan(value); err != nil {
    59  			return err
    60  		}
    61  
    62  		n.Val = reflect.ValueOf(sn.String).Convert(n.Type)
    63  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32,
    64  		reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32:
    65  		sn := &sql.NullInt32{}
    66  		if err := sn.Scan(value); err != nil {
    67  			return err
    68  		}
    69  		n.Val = reflect.ValueOf(sn.Int32).Convert(n.Type)
    70  	case reflect.Int64, reflect.Uint64:
    71  		sn := &sql.NullInt64{}
    72  		if err := sn.Scan(value); err != nil {
    73  			return err
    74  		}
    75  		n.Val = reflect.ValueOf(sn.Int64).Convert(n.Type)
    76  	case reflect.Float32, reflect.Float64:
    77  		sn := &sql.NullFloat64{}
    78  		if err := sn.Scan(value); err != nil {
    79  			return err
    80  		}
    81  
    82  		n.Val = reflect.ValueOf(sn.Float64).Convert(n.Type)
    83  	case reflect.Bool:
    84  		sn := &sql.NullBool{}
    85  		if err := sn.Scan(value); err != nil {
    86  			return err
    87  		}
    88  
    89  		n.Val = reflect.ValueOf(sn.Bool).Convert(n.Type)
    90  	case reflect.Interface:
    91  		n.Val = n.Val.Convert(n.Type)
    92  	default:
    93  		if n.Type == reflector.TimeType || reflector.TimeType.ConvertibleTo(n.Type) {
    94  			sn := &sql.NullTime{}
    95  			if err := sn.Scan(value); err != nil {
    96  				return err
    97  			}
    98  
    99  			n.Val = reflect.ValueOf(sn.Time).Convert(n.Type)
   100  		} else {
   101  			sn := &sql.NullString{}
   102  			if err := sn.Scan(value); err != nil {
   103  				return err
   104  			}
   105  
   106  			n.Val = reflect.ValueOf(sn.String).Convert(n.Type)
   107  		}
   108  	}
   109  
   110  	return nil
   111  }
   112  
   113  func (n *NullAny) Get() interface{} {
   114  	if n.Val.IsValid() {
   115  		i := n.Val.Interface()
   116  		if s, ok := i.([]byte); ok {
   117  			return string(s)
   118  		}
   119  
   120  		return i
   121  	}
   122  
   123  	return nil
   124  }
   125  
   126  func (n *NullAny) GetVal() reflect.Value {
   127  	if n.Type == nil {
   128  		return reflect.Value{}
   129  	}
   130  
   131  	if n.Val.IsValid() {
   132  		return n.Val
   133  	}
   134  
   135  	return reflect.New(n.Type).Elem()
   136  }
   137  
   138  func (n *NullAny) String() string {
   139  	if n.Val.IsValid() {
   140  		i := n.Val.Interface()
   141  		if iv, ok := i.([]byte); ok {
   142  			return string(iv)
   143  		}
   144  		return fmt.Sprintf("%v", i)
   145  	}
   146  
   147  	return ""
   148  }
   149  
   150  func (n *NullAny) Valid() bool {
   151  	return n.Val.IsValid()
   152  }