123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578 |
- package array
- import (
- "errors"
- "fmt"
- "reflect"
- "regexp"
- )
- var simpleTypes = []string{
- "bool", "int", "int8", "int16", "int32", "int64", "uint", "uint8",
- "uint16", "uint32", "uint64", "uintptr", "float32", "float64", "string",
- }
- func Column(dest, input interface{}, columnKey, indexKey string) {
-
- if columnKey == "" && indexKey == "" {
- panic("columnKey or indexKey must be at least one has value")
- }
-
- dValue := reflect.ValueOf(dest)
- if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
- panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
- }
- dType, dElemType, dKeyType := indirectForArr(dValue)
- if !In(dKeyType, simpleTypes) {
-
- panic("haystack: dest key type must be 'simpleType'")
- }
- if indexKey != "" {
- if dType != reflect.Map {
- panic("haystack: dest type must be map")
- }
- } else {
- if dType != reflect.Slice && dType != reflect.Array {
- panic("haystack: dest type must be slice or array ")
- }
- }
-
- inValue := reflect.ValueOf(input)
- inPrtEValue, inType := indirectSimple(inValue)
- inElemKind, inKeyType, inElemType := columnElemType(inPrtEValue, inType, columnKey, indexKey)
- if inElemKind == reflect.Struct && ((columnKey != "" && !isFirstLetterUp(columnKey)) ||
- (indexKey != "" && !isFirstLetterUp(indexKey))) {
- panic("columnKey or indexKey must be public field")
- }
-
- if inKeyType != dKeyType {
- panic("'dest' key type does not consist with 'input[indexKey]' type")
- }
-
- if inElemType != dElemType {
- panic("'dest' elem type does not consist with 'input[columnKey]' type")
- }
-
- dValueElem := ptrToElem(dValue)
- var tempKey, tempColumn reflect.Value
- switch inValue.Kind() {
- case reflect.Slice, reflect.Array:
- for i := 0; i < inValue.Len(); i++ {
- tempColumn = inValue.Index(i)
- if inElemKind == reflect.Struct {
- if indexKey != "" {
- tempKey = tempColumn.FieldByName(indexKey)
- }
- if columnKey != "" {
- tempColumn = tempColumn.FieldByName(columnKey)
- }
- } else {
- if indexKey != "" {
- tempKey = tempColumn.MapIndex(reflect.ValueOf(indexKey))
- }
- if columnKey != "" {
- tempColumn = tempColumn.MapIndex(reflect.ValueOf(columnKey))
- }
- }
- dValueElem = columnSetValue(dType, dValueElem, tempColumn, tempKey)
- }
- case reflect.Map:
- for _, k := range inValue.MapKeys() {
- tempColumn = inValue.MapIndex(k)
- if inElemKind == reflect.Struct {
- if indexKey != "" {
- tempKey = tempColumn.FieldByName(indexKey)
- }
- if columnKey != "" {
- tempColumn = tempColumn.FieldByName(columnKey)
- }
- } else {
- if indexKey != "" {
- tempKey = tempColumn.MapIndex(reflect.ValueOf(indexKey))
- }
- if columnKey != "" {
- tempColumn = tempColumn.MapIndex(reflect.ValueOf(columnKey))
- }
- }
- dValueElem = columnSetValue(dType, dValueElem, tempColumn, tempKey)
- }
- }
-
- dValue.Elem().Set(dValueElem)
- }
- func columnSetValue(rKind reflect.Kind, rv, column, key reflect.Value) reflect.Value {
- switch rKind {
- case reflect.Slice, reflect.Array:
- rv = reflect.Append(rv, column)
- case reflect.Map:
- if rv.IsNil() {
- panic("columnSetValue: reflect.Value is nil")
- }
- rv.SetMapIndex(key, column)
- }
- return rv
- }
- func columnElemType(rv reflect.Value, rt reflect.Type, columnKey, indexKey string) (reflect.Kind, string, string) {
- var err error
- var elemKind reflect.Kind
- var keyType, elemType string
- switch rv.Kind() {
- case reflect.Slice, reflect.Array, reflect.Map:
-
- if indexKey == "" {
- keyType = reflect.Int.String()
- } else {
- elemKind, keyType, err = fieldElemType(rt.Elem(), indexKey)
- if err != nil {
- panic(err.Error())
- }
- }
-
- if columnKey == "" {
- elemType = rt.Elem().String()
- } else {
- elemKind, elemType, err = fieldElemType(rt.Elem(), columnKey)
- if err != nil {
- panic(err.Error())
- }
- }
- default:
- panic("haystack: v type must be slice, array or map")
- }
- return elemKind, keyType, elemType
- }
- func fieldElemType(elemRt reflect.Type, key string) (reflect.Kind, string, error) {
- var err error
- var elemType string
- elemKind := elemRt.Kind()
- switch elemKind {
- case reflect.Struct:
- field, isExist := elemRt.FieldByName(key)
- if !isExist {
- err = errors.New(fmt.Sprintf("input map has no column[%s]", key))
- return elemKind, elemType, err
- }
- elemType = field.Type.String()
- case reflect.Map:
- elemType = elemRt.Elem().String()
- default:
- panic("haystack: elemRt type must be map or struct")
- }
- return elemKind, elemType, err
- }
- type setOps bool
- const (
-
- instOps setOps = true
- diffOps setOps = false
-
- uniqueOps bool = false
- )
- func Diff(d interface{}, dArr ...interface{}) {
-
- dValue := reflect.ValueOf(d)
- if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
- panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
- }
-
- diffValue := operateSetValue(dValue, diffOps, dArr...)
-
- dValue.Elem().Set(diffValue)
- }
- func Intersect(d interface{}, dArr ...interface{}) {
-
- dValue := reflect.ValueOf(d)
- if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
- panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
- }
-
- instValue := operateSetValue(dValue, instOps, dArr...)
-
- dValue.Elem().Set(instValue)
- }
- func operateSetValue(dv reflect.Value, ops setOps, dArr ...interface{}) reflect.Value {
-
- if dv.Kind() == reflect.Ptr {
- dv = dv.Elem()
- }
-
- var newValue reflect.Value
- dType, _ := indirect(dv)
- indirectStr := reflect.Indirect(dv)
- for _, arr := range dArr {
-
- arrValue := reflect.ValueOf(arr)
- if arrValue.Kind() == reflect.Ptr && arrValue.IsNil() {
- continue
- }
-
- switch dType {
- case reflect.Slice, reflect.Array:
- newValue = reflect.MakeSlice(indirectStr.Type(), 0, dv.Len())
- for i := 0; i < dv.Len(); i++ {
- if inByRValue(dv.Index(i), arrValue) == bool(ops) {
- newValue = reflect.Append(newValue, dv.Index(i))
- }
- }
- case reflect.Map:
- newValue = reflect.MakeMap(indirectStr.Type())
- for _, k := range dv.MapKeys() {
- if inByRValue(dv.MapIndex(k), arrValue) == bool(ops) {
- newValue.SetMapIndex(k, dv.MapIndex(k))
- }
- }
- }
-
- dv.Set(newValue)
- }
- return dv
- }
- func In(d interface{}, arr interface{}) bool {
- dValue := reflect.ValueOf(d)
- arrValue := reflect.ValueOf(arr)
- return inByRValue(dValue, arrValue)
- }
- func inByRValue(dV reflect.Value, arrV reflect.Value) bool {
- dVKind, dvType := indirect(dV)
- arrType, arrElemType, _ := indirectForArr(arrV)
- if dvType != arrElemType {
-
- return false
- }
- isExist := false
- switch dVKind {
- case reflect.Map, reflect.Array, reflect.Slice, reflect.Struct:
- isExist = inDeepEqual(dV, arrV, arrType)
- default:
- isExist = inEqual(dV, arrV, arrType)
- }
- return isExist
- }
- func inEqual(dV reflect.Value, arrV reflect.Value, arrT reflect.Kind) bool {
- isExist := false
- dV = ptrToElem(dV)
- arrV = ptrToElem(arrV)
- switch arrT {
- case reflect.Slice, reflect.Array:
- for i := 0; i < arrV.Len(); i++ {
- if isExist = dV.Interface() == arrV.Index(i).Interface(); isExist {
- break
- }
- }
- case reflect.Map:
- for _, k := range arrV.MapKeys() {
- if isExist = dV.Interface() == arrV.MapIndex(k).Interface(); isExist {
- break
- }
- }
- default:
- panic("haystack: arrV type must be slice, array or map")
- }
- return isExist
- }
- func inDeepEqual(dV reflect.Value, arrV reflect.Value, arrT reflect.Kind) bool {
- isExist := false
- dV = ptrToElem(dV)
- arrV = ptrToElem(arrV)
- switch arrT {
- case reflect.Slice, reflect.Array:
- for i := 0; i < arrV.Len(); i++ {
- if isExist = reflect.DeepEqual(dV.Interface(), arrV.Index(i).Interface()); isExist {
- break
- }
- }
- case reflect.Map:
- for _, k := range arrV.MapKeys() {
- if isExist = reflect.DeepEqual(dV.Interface(), arrV.MapIndex(k).Interface()); isExist {
- break
- }
- }
- default:
- panic("haystack: d type must be slice, array or map")
- }
- return isExist
- }
- func Merge(d interface{}, dArr ...interface{}) {
-
- dValue := reflect.ValueOf(d)
- if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
- panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dValue)))
- }
-
- dValueElem := ptrToElem(dValue)
- dType, dElemType, dKeyType := indirectForArr(dValue)
- for _, arr := range dArr {
-
- arrValue := reflect.ValueOf(arr)
- if dValue.Kind() != reflect.Ptr || dValue.IsNil() {
- continue
- }
- arrType, arrElemType, arrKeyType := indirectForArr(arrValue)
- if arrType != dType {
- panic("'dArr' type does not consist with 'd' type")
- }
- if arrElemType != dElemType {
- panic("'dArr' elem type does not consist with 'd' elem type")
- }
- if dKeyType != arrKeyType {
- panic("'dArr' key type does not consist with 'd' key type")
- }
-
- arrValue = ptrToElem(arrValue)
- switch dType {
- case reflect.Slice, reflect.Array:
- for i := 0; i < arrValue.Len(); i++ {
- dValueElem = reflect.Append(dValueElem, arrValue.Index(i))
- }
- case reflect.Map:
- for _, k := range arrValue.MapKeys() {
- dValueElem.SetMapIndex(k, arrValue.MapIndex(k))
- }
- default:
- panic("haystack: d type must be slice, array or map")
- }
- }
-
- dValue.Elem().Set(dValueElem)
- }
- func Values(d interface{}, values interface{}) {
-
- vValue := reflect.ValueOf(values)
- if vValue.Kind() != reflect.Ptr || vValue.IsNil() {
- panic(fmt.Sprintf("haystack: values type[%T] error", reflect.TypeOf(vValue)))
- }
- vType, vElemType, _ := indirectForArr(vValue)
- if vType != reflect.Slice && vType != reflect.Array {
- panic("haystack: values type must be slice or array")
- }
-
- dValue := reflect.ValueOf(d)
- dType, dElemType, _ := indirectForArr(dValue)
- if vElemType != dElemType {
- panic("'d' key type does not consist with 'keys' elem type")
- }
- vValueElem := ptrToElem(vValue)
- switch dType {
- case reflect.Slice, reflect.Array:
- for i := 0; i < dValue.Len(); i++ {
- vValueElem = reflect.Append(vValueElem, dValue.Index(i))
- }
- case reflect.Map:
- for _, k := range dValue.MapKeys() {
- vValueElem = reflect.Append(vValueElem, dValue.MapIndex(k))
- }
- default:
- panic("haystack: d type must be slice, array or map")
- }
-
- vValue.Elem().Set(vValueElem)
- }
- func Keys(d interface{}, keys interface{}) {
-
- keysValue := reflect.ValueOf(keys)
- if keysValue.Kind() != reflect.Ptr || keysValue.IsNil() {
- panic(fmt.Sprintf("haystack: keys type[%T] error", reflect.TypeOf(keysValue)))
- }
- keysType, keysElemType, _ := indirectForArr(keysValue)
- if keysType != reflect.Slice && keysType != reflect.Array {
- panic("haystack: keys type must be slice or array")
- }
-
- dValue := reflect.ValueOf(d)
- dType, _, dKeyType := indirectForArr(dValue)
- if keysElemType != dKeyType {
- panic("'keys' key type does not consist with 'd' elem type")
- }
- keysElem := ptrToElem(keysValue)
- switch dType {
- case reflect.Slice, reflect.Array:
- for i := 0; i < dValue.Len(); i++ {
- keysElem = reflect.Append(keysElem, reflect.ValueOf(i))
- }
- case reflect.Map:
- for _, k := range dValue.MapKeys() {
- keysElem = reflect.Append(keysElem, k)
- }
- default:
- panic("haystack: d type must be slice, array or map")
- }
-
- keysValue.Elem().Set(keysElem)
- }
- func Unique(d interface{}) {
-
- dv := reflect.ValueOf(d)
- if dv.Kind() != reflect.Ptr || dv.IsNil() {
- panic(fmt.Sprintf("haystack: d type[%T] error", reflect.TypeOf(dv)))
- }
- dvElem := ptrToElem(dv)
-
- var newValue reflect.Value
- dType, _ := indirect(dv)
- indirectStr := reflect.Indirect(dv)
- switch dType {
- case reflect.Slice, reflect.Array:
- newValue = reflect.MakeSlice(indirectStr.Type(), 0, dvElem.Len())
- for i := 0; i < dvElem.Len(); i++ {
- if inByRValue(dvElem.Index(i), newValue) == uniqueOps {
- newValue = reflect.Append(newValue, dvElem.Index(i))
- }
- }
- case reflect.Map:
- newValue = reflect.MakeMap(indirectStr.Type())
- for _, k := range dvElem.MapKeys() {
- if inByRValue(dvElem.MapIndex(k), newValue) == uniqueOps {
- newValue.SetMapIndex(k, dvElem.MapIndex(k))
- }
- }
- }
-
- dv.Elem().Set(newValue)
- }
- func indirect(rv reflect.Value) (reflect.Kind, string) {
-
- rvValue, rvType := indirectSimple(rv)
- return rvValue.Kind(), rvType.String()
- }
- func indirectForArr(rv reflect.Value) (reflect.Kind, string, string) {
-
- rvValue, rvType := indirectSimple(rv)
- vType := rvValue.Kind()
- var vKeyType, vElemType string
- switch vType {
- case reflect.Slice, reflect.Array:
- vKeyType = reflect.Int.String()
- vElemType = rvType.Elem().String()
- case reflect.Map:
- vKeyType = rvType.Key().String()
- vElemType = rvType.Elem().String()
- default:
- panic("haystack: v type must be slice, array or map")
- }
- return vType, vElemType, vKeyType
- }
- func indirectSimple(rv reflect.Value) (reflect.Value, reflect.Type) {
-
- if !rv.IsValid() {
- panic("indirectSimple: reflect.Value is nil")
- }
-
- var rvValue reflect.Value
- var rvType reflect.Type
- switch rv.Kind() {
- case reflect.Ptr:
- rvValue = rv.Elem()
- rvType = rv.Type().Elem()
- default:
- rvValue = rv
- rvType = rv.Type()
- }
- return rvValue, rvType
- }
- func ptrToElem(v reflect.Value) reflect.Value {
- if v.Kind() == reflect.Ptr {
- v = v.Elem()
- }
- return v
- }
- func isFirstLetterUp(s string) bool {
- regObj, _ := regexp.Compile("^[A-Z].*")
- return regObj.MatchString(s)
- }
|