github.com/ravendb/ravendb-go-client@v0.0.0-20240229102137-4474ee7aa0fa/reflect.go (about) 1 package ravendb 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 ) 8 9 // functionality related to reflection 10 11 func isPtrStruct(t reflect.Type) (reflect.Type, bool) { 12 if t.Kind() == reflect.Ptr && t.Elem() != nil && t.Elem().Kind() == reflect.Struct { 13 return t, true 14 } 15 return nil, false 16 } 17 18 func isPtrMapStringToPtrStruct(tp reflect.Type) (reflect.Type, bool) { 19 if tp.Kind() != reflect.Ptr { 20 return nil, false 21 } 22 tp = tp.Elem() 23 if tp.Kind() != reflect.Map { 24 return nil, false 25 } 26 if tp.Key().Kind() != reflect.String { 27 return nil, false 28 } 29 return isPtrStruct(tp.Elem()) 30 } 31 32 func isMapStringToPtrStruct(tp reflect.Type) (reflect.Type, bool) { 33 if tp.Kind() != reflect.Map { 34 return nil, false 35 } 36 if tp.Key().Kind() != reflect.String { 37 return nil, false 38 } 39 return isPtrStruct(tp.Elem()) 40 } 41 42 // Go port of com.google.common.base.Defaults to make porting Java easier 43 func getDefaultValueForType(clazz reflect.Type) interface{} { 44 rv := reflect.Zero(clazz) 45 return rv.Interface() 46 } 47 48 // GetFullTypeName returns fully qualified (including package) name of the type, 49 // after traversing pointers. 50 // e.g. for struct Foo in main package, the type of Foo and *Foo is main.Foo 51 func getFullTypeName(v interface{}) string { 52 rv := reflect.ValueOf(v) 53 for rv.Kind() == reflect.Ptr { 54 rv = rv.Elem() 55 } 56 typ := rv.Type() 57 return typ.String() 58 } 59 60 // getShortTypeName returns a short (not including package) name of the type, 61 // after traversing pointers. 62 // e.g. for struct Foo, the type of Foo and *Foo is "Foo" 63 // Note: this emulates Java's operator over-loading to support 64 // DefaultGetCollectionName. 65 func getShortTypeNameForEntityOrType(v interface{}) string { 66 if typ, ok := v.(reflect.Type); ok { 67 return getShortTypeNameForType(typ) 68 } 69 return getShortTypeNameForEntity(v) 70 } 71 72 func getShortTypeNameForEntity(v interface{}) string { 73 rv := reflect.ValueOf(v) 74 for rv.Kind() == reflect.Ptr { 75 rv = rv.Elem() 76 } 77 typ := rv.Type() 78 return getShortTypeNameForType(typ) 79 } 80 81 func getShortTypeNameForType(typ reflect.Type) string { 82 // for *Foo and **Foo the name we want to return is Foo 83 for typ.Kind() == reflect.Ptr { 84 typ = typ.Elem() 85 } 86 return typ.Name() 87 } 88 89 // identity property is field of type string with name ID 90 func getIdentityProperty(typ reflect.Type) string { 91 for typ.Kind() == reflect.Ptr { 92 typ = typ.Elem() 93 } 94 if typ.Kind() != reflect.Struct { 95 return "" 96 } 97 field, ok := typ.FieldByName("ID") 98 if !ok || field.Type.Kind() != reflect.String { 99 return "" 100 } 101 return "ID" 102 } 103 104 func isTypePrimitive(t reflect.Type) bool { 105 kind := t.Kind() 106 switch kind { 107 case reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, 108 reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, 109 reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, 110 reflect.Float32, reflect.Float64, reflect.String: 111 return true 112 case reflect.Ptr: 113 return false 114 // TODO: not all of those we should support 115 case reflect.Array, reflect.Interface, reflect.Map, reflect.Slice, reflect.Struct: 116 panic("NYI") 117 } 118 return false 119 } 120 121 func getStructTypeOfReflectValue(rv reflect.Value) (reflect.Type, bool) { 122 if rv.Type().Kind() == reflect.Ptr { 123 rv = rv.Elem() 124 } 125 typ := rv.Type() 126 if typ.Kind() == reflect.Struct { 127 return typ, true 128 } 129 return typ, false 130 } 131 132 func getStructTypeOfValue(v interface{}) (reflect.Type, bool) { 133 rv := reflect.ValueOf(v) 134 return getStructTypeOfReflectValue(rv) 135 } 136 137 // if typ is ptr-to-struct, return as is 138 // if typ is ptr-to-ptr-to-struct, returns ptr-to-struct 139 // otherwise returns nil 140 func fixUpStructType(typ reflect.Type) reflect.Type { 141 if typ.Kind() != reflect.Ptr { 142 return nil 143 } 144 subtype := typ.Elem() 145 if subtype.Kind() == reflect.Struct { 146 return typ 147 } 148 if subtype.Kind() != reflect.Ptr { 149 return nil 150 } 151 if subtype.Elem().Kind() == reflect.Struct { 152 return subtype 153 } 154 return nil 155 } 156 157 func convertFloat64ToType(v float64, typ reflect.Type) interface{} { 158 switch typ.Kind() { 159 case reflect.Float32: 160 return float32(v) 161 case reflect.Float64: 162 return v 163 case reflect.Int: 164 return int(v) 165 case reflect.Int8: 166 return int8(v) 167 case reflect.Int16: 168 return int16(v) 169 case reflect.Int32: 170 return int32(v) 171 case reflect.Int64: 172 return int64(v) 173 case reflect.Uint: 174 return uint(v) 175 case reflect.Uint8: 176 return uint8(v) 177 case reflect.Uint16: 178 return uint16(v) 179 case reflect.Uint32: 180 return uint32(v) 181 case reflect.Uint64: 182 return uint64(v) 183 } 184 panicIf(true, "don't know how to convert value of type %T to reflect type %s", v, typ.Name()) 185 return int(0) 186 } 187 188 func treeToValue(typ reflect.Type, js interface{}) (interface{}, error) { 189 // TODO: should also handle primitive types 190 switch v := js.(type) { 191 case string: 192 if typ.Kind() == reflect.String { 193 return js, nil 194 } 195 panicIf(true, "don't know how to convert value of type %T to reflect type %s", js, typ.Name()) 196 case float64: 197 return convertFloat64ToType(v, typ), nil 198 case bool: 199 panicIf(true, "don't know how to convert value of type %T to reflect type %s", js, typ.Name()) 200 case []interface{}: 201 panicIf(true, "don't know how to convert value of type %T to reflect type %s", js, typ.Name()) 202 case map[string]interface{}: 203 return makeStructFromJSONMap(typ, v) 204 } 205 panicIf(true, "don't know how to convert value of type %v to reflect type %s", js, typ.Name()) 206 return nil, fmt.Errorf("don't know how to convert value of type %v to reflect type %s", js, typ.Name()) 207 } 208 209 // get name of struct field for json serialization 210 // empty string means we should skip this field 211 func getJSONFieldName(field reflect.StructField) string { 212 // skip unexported fields 213 if field.PkgPath != "" { 214 return "" 215 } 216 217 tag := field.Tag.Get("json") 218 // if no tag, use field name 219 if tag == "" { 220 return field.Name 221 } 222 // skip if explicitly marked as non-json serializable 223 // TODO: write tests for this 224 if tag == "-" { 225 return "" 226 } 227 // this could be "name,omitempty" etc.; extract just the name 228 if idx := strings.IndexByte(tag, ','); idx != -1 { 229 name := tag[:idx-1] 230 // if it's sth. like ",omitempty", use field name 231 // TODO: write tests for this 232 if name == "" { 233 return field.Name 234 } 235 return name 236 } 237 return tag 238 } 239 240 // FieldsFor returns names of all fields for the value of a struct type. 241 // They can be used in e.g. DocumentQuery.SelectFields: 242 // fields := ravendb.FieldsFor(&MyType{}) 243 // q = q.SelectFields(fields...) 244 func FieldsFor(s interface{}) []string { 245 v := reflect.ValueOf(s) 246 // if pointer get the underlying element≤ 247 for v.Kind() == reflect.Ptr { 248 v = v.Elem() 249 } 250 panicIf(v.Kind() != reflect.Struct, "argument must be struct, we got %T", s) 251 t := v.Type() 252 var res []string 253 for i := 0; i < t.NumField(); i++ { 254 if name := getJSONFieldName(t.Field(i)); name != "" { 255 res = append(res, name) 256 } 257 } 258 return res 259 } 260 261 // given js value (most likely as map[string]interface{}) decode into res 262 func decodeJSONAsStruct(js interface{}, res interface{}) error { 263 d, err := jsonMarshal(js) 264 if err != nil { 265 return err 266 } 267 return jsonUnmarshal(d, res) 268 } 269 270 // given a json represented as map and type of a struct 271 func makeStructFromJSONMap(typ reflect.Type, js map[string]interface{}) (interface{}, error) { 272 if typ == reflect.TypeOf(map[string]interface{}{}) { 273 return js, nil 274 } 275 typ2 := fixUpStructType(typ) 276 if typ2 == nil { 277 return nil, newIllegalArgumentError("typ should be *<type> or *(*<type> but is %s", typ.String()) 278 } 279 280 typ = typ2 281 // reflect.New() creates a pointer to type. if typ is already a pointer, 282 // we undo one level 283 if typ.Kind() == reflect.Ptr { 284 typ = typ.Elem() 285 } 286 rvNew := reflect.New(typ) 287 d, err := jsonMarshal(js) 288 if err != nil { 289 return nil, err 290 } 291 v := rvNew.Interface() 292 err = jsonUnmarshal(d, v) 293 if err != nil { 294 return nil, err 295 } 296 return v, nil 297 } 298 299 func dbglog(format string, args ...interface{}) string { 300 s := fmt.Sprintf(format, args...) 301 fmt.Println(s) 302 return s 303 } 304 305 // corresponds to ObjectMapper.convertValue() 306 // val is coming from JSON, so it can be string, bool, float64, []interface{} 307 // or map[string]interface{} 308 // TODO: not sure about nil 309 // for simple types (int, bool, string) it should be just pass-through 310 // for structs decode map[string]interface{} => struct using MakeStructFromJSONMap 311 func convertValue(val interface{}, clazz reflect.Type) (interface{}, error) { 312 // TODO: implement every possible type. Need more comprehensive tests 313 // to exercise those code paths 314 switch clazz.Kind() { 315 case reflect.String: 316 switch v := val.(type) { 317 case string: 318 return v, nil 319 default: 320 panicIf(true, "%s", dbglog("converting of type %T to string NYI", val)) 321 } 322 case reflect.Int: 323 switch v := val.(type) { 324 case int: 325 return v, nil 326 case float64: 327 res := int(v) 328 return res, nil 329 default: 330 panicIf(true, "%s", dbglog("converting of type %T to reflect.Int NYI", val)) 331 } 332 case reflect.Ptr: 333 clazz2 := clazz.Elem() 334 switch clazz2.Kind() { 335 case reflect.Struct: 336 valIn, ok := val.(map[string]interface{}) 337 if !ok { 338 return nil, newRavenError("can't convert value of type '%s' to a struct", val) 339 } 340 v, err := makeStructFromJSONMap(clazz, valIn) 341 return v, err 342 default: 343 panicIf(true, "%s", dbglog("converting to pointer of '%s' NYI", clazz.Kind().String())) 344 } 345 default: 346 panicIf(true, "%s", dbglog("converting to %s NYI", clazz.Kind().String())) 347 } 348 return nil, newNotImplementedError("convertValue: NYI") 349 } 350 351 // m is a single-element map[string]*struct 352 // returns single map value 353 func getSingleMapValue(results interface{}) (interface{}, error) { 354 m := reflect.ValueOf(results) 355 if m.Type().Kind() != reflect.Map { 356 return nil, fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String()) 357 } 358 mapKeyType := m.Type().Key() 359 if mapKeyType != stringType { 360 return nil, fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String()) 361 } 362 mapElemPtrType := m.Type().Elem() 363 if mapElemPtrType.Kind() != reflect.Ptr { 364 return nil, fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String()) 365 } 366 367 mapElemType := mapElemPtrType.Elem() 368 if mapElemType.Kind() != reflect.Struct { 369 return nil, fmt.Errorf("results should be a map[string]*struct, is %s. tp: %s", m.Type().String(), m.Type().String()) 370 } 371 keys := m.MapKeys() 372 if len(keys) == 0 { 373 return nil, nil 374 } 375 if len(keys) != 1 { 376 return nil, fmt.Errorf("expected results to have only one element, has %d", len(keys)) 377 } 378 v := m.MapIndex(keys[0]) 379 return v.Interface(), nil 380 } 381 382 func checkIsPtrSlice(v interface{}, argName string) error { 383 if v == nil { 384 return newIllegalArgumentError("%s can't be nil", argName) 385 } 386 tp := reflect.TypeOf(v) 387 if tp.Kind() == reflect.Slice { 388 // more specific error message for common error of passing 389 // []<type> instead of *[]<type> 390 return newIllegalArgumentError("%s can't be of type %T, try *%T", argName, v, v) 391 } 392 if tp.Kind() != reflect.Ptr { 393 return newIllegalArgumentError("%s can't be of type %T", argName, v) 394 } 395 if tp.Elem().Kind() != reflect.Slice { 396 return newIllegalArgumentError("%s can't be of type %T", argName, v) 397 } 398 return nil 399 } 400 401 func checkIsPtrPtrStruct(v interface{}, argName string) error { 402 if v == nil { 403 return newIllegalArgumentError("%s can't be nil", argName) 404 } 405 tp := reflect.TypeOf(v) 406 407 if tp.Kind() == reflect.Struct { 408 // possibly a common mistake, so try to provide a helpful error message 409 typeGot := fmt.Sprintf("%T", v) 410 typeExpect := "**" + typeGot 411 return newIllegalArgumentError("%s can't be of type %s, try passing %s", argName, typeGot, typeExpect) 412 } 413 414 if tp.Kind() != reflect.Ptr { 415 return newIllegalArgumentError("%s can't be of type %T", argName, v) 416 } 417 418 if tp.Elem().Kind() == reflect.Struct { 419 // possibly a common mistake, so try to provide a helpful error message 420 typeGot := fmt.Sprintf("%T", v) 421 typeExpect := "*" + typeGot 422 return newIllegalArgumentError("%s can't be of type %s, try passing %s", argName, typeGot, typeExpect) 423 } 424 425 if tp.Elem().Kind() != reflect.Ptr { 426 return newIllegalArgumentError("%s can't be of type %T", argName, v) 427 } 428 429 // we only allow pointer to struct 430 if tp.Elem().Elem().Kind() == reflect.Struct { 431 return nil 432 } 433 return newIllegalArgumentError("%s can't be of type %T", argName, v) 434 }