1
0
mirror of https://github.com/ManyakRus/crud_generator.git synced 2024-12-22 00:36:41 +02:00
crud_generator/vendor/github.com/ompluscator/dynamic-struct/reader.go
Nikitin Aleksandr a6ea64ee3e новый
2023-10-24 18:03:04 +03:00

590 lines
14 KiB
Go

package dynamicstruct
import (
"errors"
"fmt"
"reflect"
"time"
)
type (
// Reader is helper interface which provides possibility to
// access struct's fields' values, reads and provides theirs values.
Reader interface {
// HasField checks if struct instance has a field with a given name.
//
// if reader.HasField("SomeFloatField") { ...
//
HasField(name string) bool
// GetField returns struct instance's field value.
// If there is no such field, it returns nil.
// Usable to edit existing struct's field.
//
// field := reader.GetField("SomeFloatField")
//
GetField(name string) Field
// GetAllFields returns a list of all struct instance's fields.
//
// for _, field := range reader.GetAllFields() { ...
//
GetAllFields() []Field
// ToStruct maps all read values to passed instance of struct, by setting
// all its values for fields with same names.
// It returns an error if argument is not a pointer to a struct.
//
// err := reader.ToStruct(&instance)
//
ToStruct(value interface{}) error
// ToSliceOfReaders returns a list of Reader interfaces if value is representation
// of slice itself.
//
// readers := reader.ToReaderSlice()
//
ToSliceOfReaders() []Reader
// ToMapReaderOfReaders returns a map of Reader interfaces if value is representation
// of map itself with some key type.
//
// readers := reader.ToReaderMap()
//
ToMapReaderOfReaders() map[interface{}]Reader
// GetValue returns original value used in reader.
//
// instance := reader.GetValue()
//
GetValue() interface{}
}
// Field is a wrapper for struct's field's value.
// It provides methods for easier field's value reading.
Field interface {
// GetName returns field's name in struct.
//
// name := field.GetName()
//
Name() string
// PointerInt returns a pointer for instance of int type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").PointerInt()
//
PointerInt() *int
// Int returns an instance of int type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").Int()
//
Int() int
// PointerInt8 returns a pointer for instance of int8 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").PointerInt8()
//
PointerInt8() *int8
// Int8 returns aan instance of int8 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").Int8()
//
Int8() int8
// PointerInt16 returns a pointer for instance of int16 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").PointerInt16()
//
PointerInt16() *int16
// Int16 returns an instance of int16 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").Int16()
//
Int16() int16
// PointerInt32 returns a pointer for instance of int32 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").PointerInt32()
//
PointerInt32() *int32
// Int32 returns an instance of int32 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").Int32()
//
Int32() int32
// PointerInt64 returns a pointer for instance of int64 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").PointerInt64()
//
PointerInt64() *int64
// Int64 returns an instance of int64 type.
// It panics if field's value can't be casted to desired type.
//
// number := reader.GetField("SomeField").Int64()
//
Int64() int64
// PointerUint returns a pointer for instance of uint type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").PointerUint()
//
PointerUint() *uint
// Uint returns an instance of uint type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").Uint()
//
Uint() uint
// PointerUint8 returns a pointer for instance of uint8 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").PointerUint8()
//
PointerUint8() *uint8
// Uint8 returns an instance of uint8 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").Uint8()
//
Uint8() uint8
// PointerUint16 returns a pointer for instance of uint16 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").PointerUint16()
//
PointerUint16() *uint16
// Uint16 returns an instance of uint16 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").Uint16()
//
Uint16() uint16
// PointerUint32 returns a pointer for instance of uint32 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").PointerUint32()
//
PointerUint32() *uint32
// Uint32 returns an instance of uint32 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").Uint32()
//
Uint32() uint32
// PointerUint64 returns a pointer for instance of uint64 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").PointerUint64()
//
PointerUint64() *uint64
// Uint64 returns an instance of uint64 type.
// It panics if field's value can't be casted to desired type.
//
// unsigned := reader.GetField("SomeField").Uint64()
//
Uint64() uint64
// PointerFloat32 returns a pointer for instance of float32 type.
// It panics if field's value can't be casted to desired type.
//
// boolean := reader.GetField("SomeField").PointerFloat32()
//
PointerFloat32() *float32
// Float32 returns an of float32 type.
// It panics if field's value can't be casted to desired type.
//
// boolean := reader.GetField("SomeField").Float32()
//
Float32() float32
// PointerFloat64 returns a pointer for instance of float64 type.
// It panics if field's value can't be casted to desired type.
//
// boolean := reader.GetField("SomeField").PointerFloat64()
//
PointerFloat64() *float64
// Float64 returns an instance of float64 type.
// It panics if field's value can't be casted to desired type.
//
// boolean := reader.GetField("SomeField").Float64()
//
Float64() float64
// PointerString returns a pointer for instance of string type.
// It panics if field's value can't be casted to desired type.
//
// text := reader.GetField("SomeField").PointerString()
//
PointerString() *string
// String returns aan instance of string type.
// It panics if field's value can't be casted to desired type.
//
// text := reader.GetField("SomeField").String()
//
String() string
// PointerBool returns a pointer for instance of bool type.
// It panics if field's value can't be casted to desired type.
//
// boolean := reader.GetField("SomeField").PointerBool()
//
PointerBool() *bool
// Bool returns an instance of bool type.
// It panics if field's value can't be casted to desired type.
//
// boolean := reader.GetField("SomeField").Bool()
//
Bool() bool
// PointerTime returns a pointer for instance of time.Time{} type.
// It panics if field's value can't be casted to desired type.
//
// dateTime := reader.GetField("SomeField").PointerTime()
//
PointerTime() *time.Time
// Time returns an instance of time.Time{} type.
// It panics if field's value can't be casted to desired type.
//
// dateTime := reader.GetField("SomeField").Time()
//
Time() time.Time
// Interface returns an interface which represents field's value.
// Useful for casting value into desired type.
//
// slice, ok := reader.GetField("SomeField").Interface().([]int)
//
Interface() interface{}
}
readImpl struct {
fields map[string]fieldImpl
value interface{}
}
fieldImpl struct {
field reflect.StructField
value reflect.Value
}
)
// NewReader reads struct instance and provides instance of
// Reader interface to give possibility to read all fields' values.
func NewReader(value interface{}) Reader {
fields := map[string]fieldImpl{}
valueOf := reflect.Indirect(reflect.ValueOf(value))
typeOf := valueOf.Type()
if typeOf.Kind() == reflect.Struct {
for i := 0; i < valueOf.NumField(); i++ {
field := typeOf.Field(i)
fields[field.Name] = fieldImpl{
field: field,
value: valueOf.Field(i),
}
}
}
return readImpl{
fields: fields,
value: value,
}
}
func (r readImpl) HasField(name string) bool {
_, ok := r.fields[name]
return ok
}
func (r readImpl) GetField(name string) Field {
if !r.HasField(name) {
return nil
}
return r.fields[name]
}
func (r readImpl) GetAllFields() []Field {
var fields []Field
for _, field := range r.fields {
fields = append(fields, field)
}
return fields
}
func (r readImpl) ToStruct(value interface{}) error {
valueOf := reflect.ValueOf(value)
if valueOf.Kind() != reflect.Ptr || valueOf.IsNil() {
return errors.New("ToStruct: expected a pointer as an argument")
}
valueOf = valueOf.Elem()
typeOf := valueOf.Type()
if valueOf.Kind() != reflect.Struct {
return errors.New("ToStruct: expected a pointer to struct as an argument")
}
for i := 0; i < valueOf.NumField(); i++ {
fieldType := typeOf.Field(i)
fieldValue := valueOf.Field(i)
original, ok := r.fields[fieldType.Name]
if !ok {
continue
}
if fieldValue.CanSet() && r.haveSameTypes(original.value.Type(), fieldValue.Type()) {
fieldValue.Set(original.value)
}
}
return nil
}
func (r readImpl) ToSliceOfReaders() []Reader {
valueOf := reflect.Indirect(reflect.ValueOf(r.value))
typeOf := valueOf.Type()
if typeOf.Kind() != reflect.Slice && typeOf.Kind() != reflect.Array {
return nil
}
var readers []Reader
for i := 0; i < valueOf.Len(); i++ {
readers = append(readers, NewReader(valueOf.Index(i).Interface()))
}
return readers
}
func (r readImpl) ToMapReaderOfReaders() map[interface{}]Reader {
valueOf := reflect.Indirect(reflect.ValueOf(r.value))
typeOf := valueOf.Type()
if typeOf.Kind() != reflect.Map {
return nil
}
readers := map[interface{}]Reader{}
for _, keyValue := range valueOf.MapKeys() {
readers[keyValue.Interface()] = NewReader(valueOf.MapIndex(keyValue).Interface())
}
return readers
}
func (r readImpl) GetValue() interface{} {
return r.value
}
func (r readImpl) haveSameTypes(first reflect.Type, second reflect.Type) bool {
if first.Kind() != second.Kind() {
return false
}
switch first.Kind() {
case reflect.Ptr:
return r.haveSameTypes(first.Elem(), second.Elem())
case reflect.Struct:
return first.PkgPath() == second.PkgPath() && first.Name() == second.Name()
case reflect.Slice:
return r.haveSameTypes(first.Elem(), second.Elem())
case reflect.Map:
return r.haveSameTypes(first.Elem(), second.Elem()) && r.haveSameTypes(first.Key(), second.Key())
default:
return first.Kind() == second.Kind()
}
}
func (f fieldImpl) Name() string {
return f.field.Name
}
func (f fieldImpl) PointerInt() *int {
if f.value.IsNil() {
return nil
}
value := f.Int()
return &value
}
func (f fieldImpl) Int() int {
return int(reflect.Indirect(f.value).Int())
}
func (f fieldImpl) PointerInt8() *int8 {
if f.value.IsNil() {
return nil
}
value := f.Int8()
return &value
}
func (f fieldImpl) Int8() int8 {
return int8(reflect.Indirect(f.value).Int())
}
func (f fieldImpl) PointerInt16() *int16 {
if f.value.IsNil() {
return nil
}
value := f.Int16()
return &value
}
func (f fieldImpl) Int16() int16 {
return int16(reflect.Indirect(f.value).Int())
}
func (f fieldImpl) PointerInt32() *int32 {
if f.value.IsNil() {
return nil
}
value := f.Int32()
return &value
}
func (f fieldImpl) Int32() int32 {
return int32(reflect.Indirect(f.value).Int())
}
func (f fieldImpl) PointerInt64() *int64 {
if f.value.IsNil() {
return nil
}
value := f.Int64()
return &value
}
func (f fieldImpl) Int64() int64 {
return reflect.Indirect(f.value).Int()
}
func (f fieldImpl) PointerUint() *uint {
if f.value.IsNil() {
return nil
}
value := f.Uint()
return &value
}
func (f fieldImpl) Uint() uint {
return uint(reflect.Indirect(f.value).Uint())
}
func (f fieldImpl) PointerUint8() *uint8 {
if f.value.IsNil() {
return nil
}
value := f.Uint8()
return &value
}
func (f fieldImpl) Uint8() uint8 {
return uint8(reflect.Indirect(f.value).Uint())
}
func (f fieldImpl) PointerUint16() *uint16 {
if f.value.IsNil() {
return nil
}
value := f.Uint16()
return &value
}
func (f fieldImpl) Uint16() uint16 {
return uint16(reflect.Indirect(f.value).Uint())
}
func (f fieldImpl) PointerUint32() *uint32 {
if f.value.IsNil() {
return nil
}
value := f.Uint32()
return &value
}
func (f fieldImpl) Uint32() uint32 {
return uint32(reflect.Indirect(f.value).Uint())
}
func (f fieldImpl) PointerUint64() *uint64 {
if f.value.IsNil() {
return nil
}
value := f.Uint64()
return &value
}
func (f fieldImpl) Uint64() uint64 {
return reflect.Indirect(f.value).Uint()
}
func (f fieldImpl) PointerFloat32() *float32 {
if f.value.IsNil() {
return nil
}
value := f.Float32()
return &value
}
func (f fieldImpl) Float32() float32 {
return float32(reflect.Indirect(f.value).Float())
}
func (f fieldImpl) PointerFloat64() *float64 {
if f.value.IsNil() {
return nil
}
value := f.Float64()
return &value
}
func (f fieldImpl) Float64() float64 {
return reflect.Indirect(f.value).Float()
}
func (f fieldImpl) PointerString() *string {
if f.value.IsNil() {
return nil
}
value := f.String()
return &value
}
func (f fieldImpl) String() string {
return reflect.Indirect(f.value).String()
}
func (f fieldImpl) PointerBool() *bool {
if f.value.IsNil() {
return nil
}
value := f.Bool()
return &value
}
func (f fieldImpl) Bool() bool {
return reflect.Indirect(f.value).Bool()
}
func (f fieldImpl) PointerTime() *time.Time {
if f.value.IsNil() {
return nil
}
value := f.Time()
return &value
}
func (f fieldImpl) Time() time.Time {
value, ok := reflect.Indirect(f.value).Interface().(time.Time)
if !ok {
panic(fmt.Sprintf(`field "%s" is not instance of time.Time`, f.field.Name))
}
return value
}
func (f fieldImpl) Interface() interface{} {
return f.value.Interface()
}