github.com/aldelo/common@v1.5.1/helper-reflect.go (about)

     1  package helper
     2  
     3  import (
     4  	"database/sql"
     5  	"fmt"
     6  	"log"
     7  	"reflect"
     8  	"time"
     9  )
    10  
    11  /*
    12   * Copyright 2020-2023 Aldelo, LP
    13   *
    14   * Licensed under the Apache License, Version 2.0 (the "License");
    15   * you may not use this file except in compliance with the License.
    16   * You may obtain a copy of the License at
    17   *
    18   *     http://www.apache.org/licenses/LICENSE-2.0
    19   *
    20   * Unless required by applicable law or agreed to in writing, software
    21   * distributed under the License is distributed on an "AS IS" BASIS,
    22   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    23   * See the License for the specific language governing permissions and
    24   * limitations under the License.
    25   */
    26  
    27  // ================================================================================================================
    28  // Custom Type Registry
    29  // ================================================================================================================
    30  var customTypeRegistry map[string]reflect.Type
    31  
    32  // ReflectTypeRegistryAdd will accept a custom struct object, and add its type into custom type registry,
    33  // if customFullTypeName is not specified, the type name is inferred from the type itself,
    34  // custom type registry is used by reflect unmarshal helpers to construct custom type for undefined interface targets
    35  func ReflectTypeRegistryAdd(customStructObj interface{}, customFullTypeName ...string) bool {
    36  	if customStructObj == nil {
    37  		return false
    38  	}
    39  
    40  	o := reflect.TypeOf(customStructObj)
    41  
    42  	if o.Kind() == reflect.Ptr {
    43  		o = o.Elem()
    44  	}
    45  
    46  	if o.Kind() != reflect.Struct {
    47  		return false
    48  	}
    49  
    50  	typeName := o.Name()
    51  	log.Println(typeName)
    52  
    53  	if len(customFullTypeName) > 0 {
    54  		if LenTrim(customFullTypeName[0]) > 0 {
    55  			typeName = Trim(customFullTypeName[0])
    56  		}
    57  	}
    58  
    59  	if customTypeRegistry == nil {
    60  		customTypeRegistry = make(map[string]reflect.Type)
    61  	}
    62  
    63  	customTypeRegistry[typeName] = o
    64  	return true
    65  }
    66  
    67  // ReflectTypeRegistryRemove will remove a pre-registered custom type from type registry for the given type name
    68  func ReflectTypeRegistryRemove(customFullTypeName string) {
    69  	if customTypeRegistry != nil {
    70  		delete(customTypeRegistry, customFullTypeName)
    71  	}
    72  }
    73  
    74  // ReflectTypeRegistryRemoveAll will clear all previously registered custom types from type registry
    75  func ReflectTypeRegistryRemoveAll() {
    76  	if customTypeRegistry != nil {
    77  		customTypeRegistry = make(map[string]reflect.Type)
    78  	}
    79  }
    80  
    81  // ReflectTypeRegistryCount returns count of custom types registered in the type registry
    82  func ReflectTypeRegistryCount() int {
    83  	if customTypeRegistry != nil {
    84  		return len(customTypeRegistry)
    85  	} else {
    86  		return 0
    87  	}
    88  }
    89  
    90  // ReflectTypeRegistryGet returns a previously registered custom type in the type registry, based on the given type name string
    91  func ReflectTypeRegistryGet(customFullTypeName string) reflect.Type {
    92  	if customTypeRegistry != nil {
    93  		if t, ok := customTypeRegistry[customFullTypeName]; ok {
    94  			return t
    95  		} else {
    96  			return nil
    97  		}
    98  	} else {
    99  		return nil
   100  	}
   101  }
   102  
   103  // ================================================================================================================
   104  // Custom Struct Tag Reflect Helpers
   105  // ================================================================================================================
   106  
   107  // GetStructTagValueByObject will accept a struct object, struct field name, and struct tag name,
   108  // and return the found tag value and reflect type,
   109  // if reflect type or struct tag is not found, a notFound is returned
   110  // [ Parameters ]
   111  //
   112  //	structObj = struct object variable
   113  //	structFieldName = struct's field name (CASE SENSITIVE)
   114  //	structTagName = struct's tag name (the left side of struct tag - the key portion) (CASE SENSITIVE)
   115  func GetStructTagValueByObject(structObj interface{}, structFieldName string, structTagName string) (notFound bool, tagValue string, t reflect.Type) {
   116  	// get reflect type from struct object
   117  	t = reflect.TypeOf(structObj)
   118  
   119  	if t == nil {
   120  		// no reflect type found
   121  		return true, "", nil
   122  	}
   123  
   124  	// get field
   125  	field, ok := t.FieldByName(structFieldName)
   126  
   127  	if !ok {
   128  		// struct field not found
   129  		return true, "", t
   130  	} else {
   131  		// struct field found
   132  		return false, field.Tag.Get(structTagName), t
   133  	}
   134  }
   135  
   136  // GetStructTagValueByType will accept a prior obtained reflect type, struct field name, and struct tag name,
   137  // and return the found tag value,
   138  // if struct tag value is not found, a notFound is returned,
   139  // if the reflect type is nil, then not found is returned too
   140  // [ Parameters ]
   141  //
   142  //	t = reflect type of a struct object (obtained via GetStructTagValueByObject)
   143  //	structFieldName = struct's field name (CASE SENSITIVE)
   144  //	structTagName = struct's tag name (the left side of struct tag - the key portion) (CASE SENSITIVE)
   145  func GetStructTagValueByType(t reflect.Type, structFieldName string, structTagName string) (notFound bool, tagValue string) {
   146  	// check if reflect type is valid
   147  	if t == nil {
   148  		return true, ""
   149  	}
   150  
   151  	// get field
   152  	field, ok := t.FieldByName(structFieldName)
   153  
   154  	if !ok {
   155  		// struct field not found
   156  		return true, ""
   157  	} else {
   158  		// struct field found
   159  		return false, field.Tag.Get(structTagName)
   160  	}
   161  }
   162  
   163  // GetStructTagsValueSlice returns named struct tag values from field, in the order queried
   164  func GetStructTagsValueSlice(field reflect.StructField, tagName ...string) (tagValues []string) {
   165  	for _, t := range tagName {
   166  		tagValues = append(tagValues, field.Tag.Get(t))
   167  	}
   168  
   169  	return
   170  }
   171  
   172  // ================================================================================================================
   173  // Reflection Helpers
   174  // ================================================================================================================
   175  
   176  // ReflectCall uses reflection to invoke a method by name, and pass in param values if any,
   177  // result is returned via reflect.Value object slice
   178  func ReflectCall(o reflect.Value, methodName string, paramValue ...interface{}) (resultSlice []reflect.Value, notFound bool) {
   179  	method := o.MethodByName(methodName)
   180  
   181  	if method.Kind() == reflect.Invalid {
   182  		return nil, true
   183  	}
   184  
   185  	if !method.IsZero() {
   186  		var params []reflect.Value
   187  
   188  		if len(paramValue) > 0 {
   189  			for _, p := range paramValue {
   190  				params = append(params, reflect.ValueOf(p))
   191  			}
   192  		}
   193  
   194  		resultSlice = method.Call(params)
   195  
   196  		if len(resultSlice) == 0 {
   197  			return nil, false
   198  		} else {
   199  			return resultSlice, false
   200  		}
   201  	} else {
   202  		return nil, true
   203  	}
   204  }
   205  
   206  // ReflectValueToString accepts reflect.Value and returns its underlying field value in string data type
   207  // boolTrue is the literal value to use for bool true condition, boolFalse is the false condition literal,
   208  // if boolTrue or boolFalse is not defined, then default 'true' or 'false' is used,
   209  // skipBlank and skipZero if true indicates if field value is blank (string) or Zero (int, float, time, pointer, bool) then skip render,
   210  // zeroBlank = will blank the value if it is 0, 0.00, or time.IsZero
   211  //
   212  // timeFormat:
   213  //
   214  //	2006, 06 = year,
   215  //	01, 1, Jan, January = month,
   216  //	02, 2, _2 = day (_2 = width two, right justified)
   217  //	03, 3, 15 = hour (15 = 24 hour format)
   218  //	04, 4 = minute
   219  //	05, 5 = second
   220  //	PM pm = AM PM
   221  func ReflectValueToString(o reflect.Value, boolTrue string, boolFalse string, skipBlank bool, skipZero bool, timeFormat string, zeroBlank bool) (valueStr string, skip bool, err error) {
   222  	buf := ""
   223  
   224  	switch o.Kind() {
   225  	case reflect.String:
   226  		buf = o.String()
   227  
   228  		if skipBlank && LenTrim(buf) == 0 {
   229  			return "", true, nil
   230  		}
   231  	case reflect.Bool:
   232  		if o.Bool() {
   233  			if len(boolTrue) == 0 {
   234  				buf = "true"
   235  			} else {
   236  				buf = Trim(boolTrue)
   237  			}
   238  		} else {
   239  			if skipZero {
   240  				return "", true, nil
   241  			} else {
   242  				if len(boolFalse) == 0 {
   243  					buf = "false"
   244  				} else {
   245  					if Trim(boolTrue) == Trim(boolFalse) {
   246  						buf = "false"
   247  					} else {
   248  						buf = Trim(boolFalse)
   249  					}
   250  				}
   251  			}
   252  		}
   253  	case reflect.Int8:
   254  		fallthrough
   255  	case reflect.Int16:
   256  		fallthrough
   257  	case reflect.Int:
   258  		fallthrough
   259  	case reflect.Int32:
   260  		fallthrough
   261  	case reflect.Int64:
   262  		if skipZero && o.Int() == 0 {
   263  			return "", true, nil
   264  		} else {
   265  			if zeroBlank && o.Int() == 0 {
   266  				buf = ""
   267  			} else {
   268  				buf = Int64ToString(o.Int())
   269  			}
   270  		}
   271  	case reflect.Float32:
   272  		fallthrough
   273  	case reflect.Float64:
   274  		if skipZero && o.Float() == 0.00 {
   275  			return "", true, nil
   276  		} else {
   277  			if zeroBlank && o.Float() == 0.00 {
   278  				buf = ""
   279  			} else {
   280  				buf = FloatToString(o.Float())
   281  			}
   282  		}
   283  	case reflect.Uint8:
   284  		fallthrough
   285  	case reflect.Uint16:
   286  		fallthrough
   287  	case reflect.Uint:
   288  		fallthrough
   289  	case reflect.Uint32:
   290  		fallthrough
   291  	case reflect.Uint64:
   292  		if skipZero && o.Uint() == 0 {
   293  			return "", true, nil
   294  		} else {
   295  			if zeroBlank && o.Uint() == 0 {
   296  				buf = ""
   297  			} else {
   298  				buf = UInt64ToString(o.Uint())
   299  			}
   300  		}
   301  	case reflect.Ptr:
   302  		if o.IsZero() || o.IsNil() {
   303  			if skipZero || skipBlank {
   304  				return "", true, nil
   305  			} else {
   306  				if rt, _, _ := DerefPointersZero(o); rt.Kind() == reflect.Bool {
   307  					if Trim(boolTrue) == Trim(boolFalse) {
   308  						return "false", false, nil
   309  					} else {
   310  						if LenTrim(boolFalse) > 0 {
   311  							return boolFalse, false, nil
   312  						} else {
   313  							return "", false, nil
   314  						}
   315  					}
   316  				} else {
   317  					return "", false, nil
   318  				}
   319  			}
   320  		}
   321  
   322  		o2 := o.Elem()
   323  
   324  		if o2.IsZero() {
   325  			if skipZero || skipBlank {
   326  				return "", true, nil
   327  			}
   328  		}
   329  
   330  		switch f := o2.Interface().(type) {
   331  		case int8:
   332  			if skipZero && f == 0 {
   333  				return "", true, nil
   334  			} else {
   335  				if zeroBlank && f == 0 {
   336  					buf = ""
   337  				} else {
   338  					buf = Itoa(int(f))
   339  				}
   340  			}
   341  		case int16:
   342  			if skipZero && f == 0 {
   343  				return "", true, nil
   344  			} else {
   345  				if zeroBlank && f == 0 {
   346  					buf = ""
   347  				} else {
   348  					buf = Itoa(int(f))
   349  				}
   350  			}
   351  		case int32:
   352  			if skipZero && f == 0 {
   353  				return "", true, nil
   354  			} else {
   355  				if zeroBlank && f == 0 {
   356  					buf = ""
   357  				} else {
   358  					buf = Itoa(int(f))
   359  				}
   360  			}
   361  		case int64:
   362  			if skipZero && f == 0 {
   363  				return "", true, nil
   364  			} else {
   365  				if zeroBlank && f == 0 {
   366  					buf = ""
   367  				} else {
   368  					buf = Int64ToString(f)
   369  				}
   370  			}
   371  		case int:
   372  			if skipZero && f == 0 {
   373  				return "", true, nil
   374  			} else {
   375  				if zeroBlank && f == 0 {
   376  					buf = ""
   377  				} else {
   378  					buf = Itoa(f)
   379  				}
   380  			}
   381  		case bool:
   382  			if f {
   383  				if len(boolTrue) == 0 {
   384  					buf = "true"
   385  				} else {
   386  					buf = Trim(boolTrue)
   387  				}
   388  			} else {
   389  				if skipZero {
   390  					return "", true, nil
   391  				} else {
   392  					if len(boolFalse) == 0 {
   393  						buf = "false"
   394  					} else {
   395  						if Trim(boolTrue) == Trim(boolFalse) {
   396  							buf = "false"
   397  						} else {
   398  							buf = Trim(boolFalse)
   399  						}
   400  					}
   401  				}
   402  			}
   403  		case string:
   404  			if skipBlank && LenTrim(f) == 0 {
   405  				return "", true, nil
   406  			} else {
   407  				buf = f
   408  			}
   409  		case float32:
   410  			if skipZero && f == 0.00 {
   411  				return "", true, nil
   412  			} else {
   413  				if zeroBlank && f == 0.00 {
   414  					buf = ""
   415  				} else {
   416  					buf = Float32ToString(f)
   417  				}
   418  			}
   419  		case float64:
   420  			if skipZero && f == 0.00 {
   421  				return "", true, nil
   422  			} else {
   423  				if zeroBlank && f == 0.00 {
   424  					buf = ""
   425  				} else {
   426  					buf = Float64ToString(f)
   427  				}
   428  			}
   429  		case uint:
   430  			if skipZero && f == 0 {
   431  				return "", true, nil
   432  			} else {
   433  				if zeroBlank && f == 0.00 {
   434  					buf = ""
   435  				} else {
   436  					buf = UintToStr(f)
   437  				}
   438  			}
   439  		case uint64:
   440  			if skipZero && f == 0 {
   441  				return "", true, nil
   442  			} else {
   443  				if zeroBlank && f == 0.00 {
   444  					buf = ""
   445  				} else {
   446  					buf = UInt64ToString(f)
   447  				}
   448  			}
   449  		case time.Time:
   450  			if skipZero && f.IsZero() {
   451  				return "", true, nil
   452  			} else {
   453  				if LenTrim(timeFormat) == 0 {
   454  					if zeroBlank && f.IsZero() {
   455  						buf = ""
   456  					} else {
   457  						buf = FormatDateTime(f)
   458  					}
   459  				} else {
   460  					if zeroBlank && f.IsZero() {
   461  						buf = ""
   462  					} else {
   463  						buf = f.Format(timeFormat)
   464  					}
   465  				}
   466  			}
   467  		default:
   468  			return "", false, fmt.Errorf("%s Unhandled [1]", o2.Type().Name())
   469  		}
   470  	default:
   471  		switch f := o.Interface().(type) {
   472  		case sql.NullString:
   473  			buf = FromNullString(f)
   474  
   475  			if skipBlank && LenTrim(buf) == 0 {
   476  				return "", true, nil
   477  			}
   478  		case sql.NullBool:
   479  			if FromNullBool(f) {
   480  				if len(boolTrue) == 0 {
   481  					buf = "true"
   482  				} else {
   483  					buf = Trim(boolTrue)
   484  				}
   485  			} else {
   486  				if skipZero {
   487  					return "", true, nil
   488  				} else {
   489  					if len(boolFalse) == 0 {
   490  						buf = "false"
   491  					} else {
   492  						if Trim(boolTrue) == Trim(boolFalse) {
   493  							buf = "false"
   494  						} else {
   495  							buf = Trim(boolFalse)
   496  						}
   497  					}
   498  				}
   499  			}
   500  		case sql.NullFloat64:
   501  			f64 := FromNullFloat64(f)
   502  
   503  			if skipZero && f64 == 0.00 {
   504  				return "", true, nil
   505  			} else {
   506  				if zeroBlank && f64 == 0.00 {
   507  					buf = ""
   508  				} else {
   509  					buf = FloatToString(f64)
   510  				}
   511  			}
   512  		case sql.NullInt32:
   513  			i32 := FromNullInt(f)
   514  
   515  			if skipZero && i32 == 0 {
   516  				return "", true, nil
   517  			} else {
   518  				if zeroBlank && i32 == 0 {
   519  					buf = ""
   520  				} else {
   521  					buf = Itoa(i32)
   522  				}
   523  			}
   524  		case sql.NullInt64:
   525  			i64 := FromNullInt64(f)
   526  
   527  			if skipZero && i64 == 0 {
   528  				return "", true, nil
   529  			} else {
   530  				if zeroBlank && i64 == 0 {
   531  					buf = ""
   532  				} else {
   533  					buf = Int64ToString(i64)
   534  				}
   535  			}
   536  		case sql.NullTime:
   537  			t := FromNullTime(f)
   538  
   539  			if skipZero && t.IsZero() {
   540  				return "", true, nil
   541  			} else {
   542  				if LenTrim(timeFormat) == 0 {
   543  					buf = FormatDateTime(t)
   544  				} else {
   545  					if zeroBlank && t.IsZero() {
   546  						buf = ""
   547  					} else {
   548  						buf = t.Format(timeFormat)
   549  					}
   550  				}
   551  			}
   552  		case time.Time:
   553  			if skipZero && f.IsZero() {
   554  				return "", true, nil
   555  			} else {
   556  				if LenTrim(timeFormat) == 0 {
   557  					if zeroBlank && f.IsZero() {
   558  						buf = ""
   559  					} else {
   560  						buf = FormatDateTime(f)
   561  					}
   562  				} else {
   563  					if zeroBlank && f.IsZero() {
   564  						buf = ""
   565  					} else {
   566  						buf = f.Format(timeFormat)
   567  					}
   568  				}
   569  			}
   570  		case nil:
   571  			if skipZero || skipBlank {
   572  				return "", true, nil
   573  			} else {
   574  				buf = ""
   575  			}
   576  		default:
   577  			return "", false, fmt.Errorf("%s Unhandled [2]", o.Type().Name())
   578  		}
   579  	}
   580  
   581  	return buf, false, nil
   582  }
   583  
   584  // ReflectStringToField accepts string value and reflects into reflect.Value field based on the field data type
   585  //
   586  // timeFormat:
   587  //
   588  //	2006, 06 = year,
   589  //	01, 1, Jan, January = month,
   590  //	02, 2, _2 = day (_2 = width two, right justified)
   591  //	03, 3, 15 = hour (15 = 24 hour format)
   592  //	04, 4 = minute
   593  //	05, 5 = second
   594  //	PM pm = AM PM
   595  func ReflectStringToField(o reflect.Value, v string, timeFormat string) error {
   596  	switch o.Kind() {
   597  	case reflect.String:
   598  		o.SetString(v)
   599  	case reflect.Bool:
   600  		b, _ := ParseBool(v)
   601  		o.SetBool(b)
   602  	case reflect.Int8:
   603  		fallthrough
   604  	case reflect.Int16:
   605  		fallthrough
   606  	case reflect.Int:
   607  		fallthrough
   608  	case reflect.Int32:
   609  		fallthrough
   610  	case reflect.Int64:
   611  		i64, _ := ParseInt64(v)
   612  		if !o.OverflowInt(i64) {
   613  			o.SetInt(i64)
   614  		}
   615  	case reflect.Float32:
   616  		fallthrough
   617  	case reflect.Float64:
   618  		f64, _ := ParseFloat64(v)
   619  		if !o.OverflowFloat(f64) {
   620  			o.SetFloat(f64)
   621  		}
   622  	case reflect.Uint8:
   623  		fallthrough
   624  	case reflect.Uint16:
   625  		fallthrough
   626  	case reflect.Uint:
   627  		fallthrough
   628  	case reflect.Uint32:
   629  		fallthrough
   630  	case reflect.Uint64:
   631  		ui64 := StrToUint64(v)
   632  		if !o.OverflowUint(ui64) {
   633  			o.SetUint(ui64)
   634  		}
   635  	case reflect.Ptr:
   636  		if o.IsZero() || o.IsNil() {
   637  			// create object
   638  			baseType, _, _ := DerefPointersZero(o)
   639  			o.Set(reflect.New(baseType.Type()))
   640  		}
   641  
   642  		o2 := o.Elem()
   643  
   644  		if o.IsZero() {
   645  			return nil
   646  		}
   647  
   648  		switch o2.Interface().(type) {
   649  		case int:
   650  			i64, _ := ParseInt64(v)
   651  			if !o2.OverflowInt(i64) {
   652  				o2.SetInt(i64)
   653  			}
   654  		case int8:
   655  			i64, _ := ParseInt64(v)
   656  			if !o2.OverflowInt(i64) {
   657  				o2.SetInt(i64)
   658  			}
   659  		case int16:
   660  			i64, _ := ParseInt64(v)
   661  			if !o2.OverflowInt(i64) {
   662  				o2.SetInt(i64)
   663  			}
   664  		case int32:
   665  			i64, _ := ParseInt64(v)
   666  			if !o2.OverflowInt(i64) {
   667  				o2.SetInt(i64)
   668  			}
   669  		case int64:
   670  			i64, _ := ParseInt64(v)
   671  			if !o2.OverflowInt(i64) {
   672  				o2.SetInt(i64)
   673  			}
   674  		case float32:
   675  			f64, _ := ParseFloat64(v)
   676  			if !o2.OverflowFloat(f64) {
   677  				o2.SetFloat(f64)
   678  			}
   679  		case float64:
   680  			f64, _ := ParseFloat64(v)
   681  			if !o2.OverflowFloat(f64) {
   682  				o2.SetFloat(f64)
   683  			}
   684  		case uint:
   685  			if !o2.OverflowUint(StrToUint64(v)) {
   686  				o2.SetUint(StrToUint64(v))
   687  			}
   688  		case uint64:
   689  			if !o2.OverflowUint(StrToUint64(v)) {
   690  				o2.SetUint(StrToUint64(v))
   691  			}
   692  		case string:
   693  			o2.SetString(v)
   694  		case bool:
   695  			b, _ := ParseBool(v)
   696  			o2.SetBool(b)
   697  		case time.Time:
   698  			if LenTrim(timeFormat) == 0 {
   699  				o2.Set(reflect.ValueOf(ParseDate(v)))
   700  			} else {
   701  				o2.Set(reflect.ValueOf(ParseDateTimeCustom(v, timeFormat)))
   702  			}
   703  		default:
   704  			return fmt.Errorf(o2.Type().Name() + " Unhandled [1]")
   705  		}
   706  	default:
   707  		switch o.Interface().(type) {
   708  		case sql.NullString:
   709  			o.Set(reflect.ValueOf(sql.NullString{String: v, Valid: true}))
   710  		case sql.NullBool:
   711  			b, _ := ParseBool(v)
   712  			o.Set(reflect.ValueOf(sql.NullBool{Bool: b, Valid: true}))
   713  		case sql.NullFloat64:
   714  			f64, _ := ParseFloat64(v)
   715  			o.Set(reflect.ValueOf(sql.NullFloat64{Float64: f64, Valid: true}))
   716  		case sql.NullInt32:
   717  			i32, _ := ParseInt32(v)
   718  			o.Set(reflect.ValueOf(sql.NullInt32{Int32: int32(i32), Valid: true}))
   719  		case sql.NullInt64:
   720  			i64, _ := ParseInt64(v)
   721  			o.Set(reflect.ValueOf(sql.NullInt64{Int64: i64, Valid: true}))
   722  		case sql.NullTime:
   723  			var tv time.Time
   724  
   725  			if LenTrim(timeFormat) == 0 {
   726  				tv = ParseDateTime(v)
   727  			} else {
   728  				tv = ParseDateTimeCustom(v, timeFormat)
   729  			}
   730  
   731  			o.Set(reflect.ValueOf(sql.NullTime{Time: tv, Valid: true}))
   732  		case time.Time:
   733  			if LenTrim(timeFormat) == 0 {
   734  				o.Set(reflect.ValueOf(ParseDateTime(v)))
   735  			} else {
   736  				o.Set(reflect.ValueOf(ParseDateTimeCustom(v, timeFormat)))
   737  			}
   738  		case nil:
   739  			return nil
   740  		default:
   741  			return fmt.Errorf(o.Type().Name() + " Unhandled [2]")
   742  		}
   743  	}
   744  
   745  	return nil
   746  }
   747  
   748  // DerefPointersZero gets pointer base type
   749  func DerefPointersZero(rv reflect.Value) (drv reflect.Value, isPtr bool, isNilPtr bool) {
   750  	for rv.Kind() == reflect.Ptr {
   751  		isPtr = true
   752  		if rv.IsNil() {
   753  			isNilPtr = true
   754  			rt := rv.Type().Elem()
   755  			for rt.Kind() == reflect.Ptr {
   756  				rt = rt.Elem()
   757  			}
   758  			drv = reflect.New(rt).Elem()
   759  			return
   760  		}
   761  		rv = rv.Elem()
   762  	}
   763  	drv = rv
   764  	return
   765  }
   766  
   767  // DerefError dereferences reflect.Value to error object if underlying type was error
   768  func DerefError(v reflect.Value) error {
   769  	if e, ok := v.Interface().(error); ok {
   770  		// v is error, check if error exists
   771  		if e != nil {
   772  			return e
   773  		}
   774  	}
   775  
   776  	return nil
   777  }
   778  
   779  // ReflectGetType returns the type of obj interface{} passed in.
   780  // if obj interface{} is a pointer, then its base type will be returned instead
   781  func ReflectGetType(obj interface{}) reflect.Type {
   782  	if obj == nil {
   783  		return nil
   784  	} else {
   785  		t1 := reflect.TypeOf(obj)
   786  
   787  		if t1.Kind() == reflect.Ptr {
   788  			return t1.Elem()
   789  		} else {
   790  			return t1
   791  		}
   792  	}
   793  }
   794  
   795  // ReflectObjectNewPtr creates a new object ptr for the object type given at parameter.
   796  // the return interface{} represents the actual object ptr created
   797  func ReflectObjectNewPtr(objType reflect.Type) interface{} {
   798  	if objType == nil {
   799  		return nil
   800  	} else {
   801  		return reflect.New(objType).Interface()
   802  	}
   803  }