github.com/angryronald/go-kit@v0.0.0-20240505173814-ff2bd9c79dbf/generic/repository/generic.utils.go (about) 1 package repository 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "strings" 8 "unicode" 9 10 "github.com/google/uuid" 11 ) 12 13 func IsValidOperations(conditionalOperations []ConditionalOperation, relationalOperations []RelationalOperation, params map[string]interface{}) bool { 14 if (len(params) == len(conditionalOperations) && len(conditionalOperations)-len(relationalOperations) == 1) || (len(conditionalOperations) == 0 && len(relationalOperations) == 0 && len(params) == 0) { 15 return true 16 } 17 18 return false 19 } 20 21 // func ToSnakeCase(s string) string { 22 // var result []string 23 // for i, r := range s { 24 // if i > 0 && unicode.IsUpper(r) { 25 // result = append(result, "_") 26 // } 27 // result = append(result, strings.ToLower(string(r))) 28 // } 29 // return strings.Join(result, "") 30 // } 31 func ToSnakeCase(s string) string { 32 var result strings.Builder 33 34 for i, r := range s { 35 if i > 0 && unicode.IsUpper(r) { 36 nextIsLower := i < len(s)-1 && unicode.IsLower(rune(s[i+1])) 37 if nextIsLower { 38 result.WriteByte('_') 39 } 40 } 41 result.WriteRune(unicode.ToLower(r)) 42 } 43 return result.String() 44 } 45 46 func GetTableName(model interface{}) string { 47 // typeName := reflect.TypeOf(model).Elem().Name() 48 t := reflect.TypeOf(model) 49 for t.Kind() == reflect.Ptr || t.Kind() == reflect.Slice || t.Kind() == reflect.Array { 50 t = t.Elem() 51 } 52 typeName := t.Name() 53 return ToSnakeCase(typeName) + "s" 54 } 55 56 func IsMapStringInterface(obj interface{}) bool { 57 // Use reflection to check the type of the object. 58 objType := reflect.TypeOf(obj) 59 return objType.Kind() == reflect.Map && objType.Key().Kind() == reflect.String && objType.Elem().Kind() == reflect.Interface 60 } 61 62 // GetStructPropertyAsString retrieves the value of a specific property from a struct 63 // and converts it to a string. If the property is of type uuid.UUID, it's converted to a string. 64 func GetStructPropertyAsString(inputStruct interface{}, propertyName string) (string, error) { 65 if IsMapStringInterface(inputStruct) { 66 result, ok := inputStruct.(map[string]interface{}) 67 if !ok { 68 return "", fmt.Errorf("input is not a map[string]interface{}") 69 } 70 return fmt.Sprint(result[propertyName]), nil 71 } 72 valueOfData := reflect.ValueOf(inputStruct) 73 74 // Ensure obj is a pointer to a struct 75 if valueOfData.Kind() != reflect.Ptr || valueOfData.Elem().Kind() != reflect.Struct { 76 return "", errors.New("object must be a pointer to a struct") 77 } 78 79 valueOfData = valueOfData.Elem() 80 81 t := valueOfData.Type() 82 83 for i := 0; i < t.NumField(); i++ { 84 field := t.Field(i) 85 fieldValue := valueOfData.Field(i) 86 87 if strings.ToUpper(field.Name) == propertyName { 88 // break 89 if fieldValue.Type() == reflect.TypeOf(uuid.UUID{}) { 90 uuidValue, ok := fieldValue.Interface().(uuid.UUID) 91 if !ok { 92 return "", fmt.Errorf("failed to convert field '%s' to UUID", propertyName) 93 } 94 return uuidValue.String(), nil 95 } else { 96 return fmt.Sprintf("%v", fieldValue.Interface()), nil 97 } 98 } 99 } 100 101 return "", fmt.Errorf("field '%s' does not exist in the struct", propertyName) 102 } 103 104 // CopyObject creates a new object with the same field values as the source object. 105 func CopyObject(src interface{}) (interface{}, error) { 106 // Ensure src is a pointer to a struct. 107 srcValue := reflect.ValueOf(src) 108 109 if srcValue.Kind() != reflect.Ptr { 110 return nil, fmt.Errorf("src must be a pointer") 111 } 112 113 srcElem := srcValue.Elem() 114 115 if srcElem.Kind() != reflect.Struct { 116 return nil, fmt.Errorf("src must point to a struct") 117 } 118 119 // Create a new object of the same type as src. 120 dest := reflect.New(srcElem.Type()).Interface() 121 122 // Get the value of the destination object. 123 destValue := reflect.ValueOf(dest).Elem() 124 125 // Copy the fields from src to dest. 126 for i := 0; i < srcElem.NumField(); i++ { 127 srcField := srcElem.Field(i) 128 destField := destValue.Field(i) 129 130 // Check if the field is exported (starts with an uppercase letter). 131 if srcField.CanInterface() { 132 // Set the value of the destination field to the value of the source field. 133 destField.Set(srcField) 134 } 135 } 136 137 return dest, nil 138 } 139 140 func CopySliceOfPointers(slice interface{}) (interface{}, error) { 141 // Ensure that the input is a slice. 142 sliceValue := reflect.ValueOf(slice) 143 if sliceValue.Kind() != reflect.Slice { 144 return nil, fmt.Errorf("input must be a slice") 145 } 146 147 // Create a new slice of the same type. 148 newSlice := reflect.MakeSlice(sliceValue.Type(), sliceValue.Len(), sliceValue.Cap()) 149 150 // Copy each element from the source slice to the new slice. 151 for i := 0; i < sliceValue.Len(); i++ { 152 srcElement := sliceValue.Index(i) 153 if srcElement.Kind() != reflect.Ptr || srcElement.Elem().Kind() != reflect.Struct { 154 return nil, fmt.Errorf("element at index %d is not a struct pointer", i) 155 } 156 157 // Create a new instance of the struct type and copy the field values. 158 destElement := reflect.New(srcElement.Elem().Type()).Elem() 159 destElement.Set(srcElement.Elem()) 160 161 newSlice.Index(i).Set(destElement.Addr()) 162 } 163 164 return newSlice.Interface(), nil 165 } 166 167 func CopySliceOfPointersWithIdentitySeparated(sourceSlice interface{}, slice []interface{}) (interface{}, error) { 168 // Ensure that the input is a slice. 169 sliceValue := reflect.ValueOf(sourceSlice) 170 if sliceValue.Kind() != reflect.Slice { 171 return nil, fmt.Errorf("input must be a slice") 172 } 173 174 // Create a new slice of the same type. 175 newSlice := reflect.MakeSlice(sliceValue.Type(), 0, 0) 176 177 for _, s := range slice { 178 sWithIdentity := reflect.ValueOf(s) 179 newSlice = reflect.Append(newSlice, sWithIdentity) 180 } 181 182 return newSlice.Interface(), nil 183 } 184 185 func AreAllNumbers(arr []interface{}) bool { 186 for _, elem := range arr { 187 switch elem.(type) { 188 case int, int8, int16, int32, int64, 189 uint, uint8, uint16, uint32, uint64, 190 float32, float64: 191 // Do nothing, element is a number 192 break 193 default: 194 return false // Element is not a number 195 } 196 } 197 return true // All elements are numbers 198 } 199 200 func StringJoin(arr []interface{}, encapsulation string) string { 201 result := "" 202 for _, elem := range arr { 203 result = fmt.Sprintf(`%s%s%v%s,`, result, encapsulation, elem, encapsulation) 204 } 205 return result[:len(result)-1] 206 } 207 208 func UpdatePropertyValue(obj interface{}, propertyName string, newValue interface{}) error { 209 // Make sure the input is a pointer to a struct. 210 val := reflect.ValueOf(obj) 211 if val.Kind() != reflect.Ptr || val.Elem().Kind() != reflect.Struct { 212 return fmt.Errorf("input must be a pointer to a struct") 213 } 214 215 // Get the value of the ID field. 216 idField := val.Elem().FieldByName(propertyName) 217 if !idField.IsValid() { 218 return ErrPropertyNotFound 219 } 220 221 // Check if the newID has the same type as the ID field. 222 if idField.Type() != reflect.TypeOf(newValue) { 223 return ErrPropertyTypeNotMatch 224 } 225 226 // Update the ID field with the new value. 227 idField.Set(reflect.ValueOf(newValue)) 228 229 return nil 230 } 231 232 func AreAllUUIDs(arr []interface{}) bool { 233 for _, elem := range arr { 234 switch elem.(type) { 235 case uuid.UUID: 236 // Do nothing, element is a number 237 break 238 default: 239 return false // Element is not a number 240 } 241 } 242 return true 243 }