github.com/angryronald/go-kit@v0.0.0-20240505173814-ff2bd9c79dbf/generic/repository/memcached/generic.utils.go (about) 1 package memcached 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "strings" 8 9 "github.com/angryronald/go-kit/cast" 10 "github.com/angryronald/go-kit/generic/repository" 11 ) 12 13 func checkRelationalOperation(prev bool, current bool, relationalOperation repository.RelationalOperation) (bool, error) { 14 switch relationalOperation { 15 case repository.AND: 16 return prev && current, nil 17 18 case repository.OR: 19 return prev || current, nil 20 21 default: 22 return false, repository.ErrNotImplement 23 } 24 } 25 26 func checkConditionalOperation(expected interface{}, actual interface{}, conditionalOperations repository.ConditionalOperation) (bool, error) { 27 switch conditionalOperations { 28 case repository.EQUAL_WITH: 29 return expected == actual, nil 30 31 case repository.GREATER_THAN: 32 return actual.(int) > expected.(int), nil 33 34 case repository.GREATER_THAN_EQUAL: 35 return actual.(int) >= expected.(int), nil 36 37 case repository.LESS_THAN: 38 return actual.(int) < expected.(int), nil 39 40 case repository.LESS_THAN_EQUAL: 41 return actual.(int) <= expected.(int), nil 42 43 case repository.LIKE: 44 if expected.(string)[0] == '%' && expected.(string)[len(expected.(string))-1] != '%' { 45 return strings.HasSuffix(actual.(string), expected.(string)[1:]), nil 46 } 47 if expected.(string)[0] != '%' && expected.(string)[len(expected.(string))-1] == '%' { 48 return strings.HasPrefix(actual.(string), expected.(string)[:len(expected.(string))-1]), nil 49 } 50 return strings.Contains(actual.(string), expected.(string)[1:len(expected.(string))-1]), nil 51 52 case repository.ILIKE: 53 expected = strings.ToLower(expected.(string)) 54 actual = strings.ToLower(actual.(string)) 55 if expected.(string)[0] == '%' && expected.(string)[len(expected.(string))-1] != '%' { 56 return strings.HasSuffix(actual.(string), expected.(string)[1:]), nil 57 } 58 if expected.(string)[0] != '%' && expected.(string)[len(expected.(string))-1] == '%' { 59 return strings.HasPrefix(actual.(string), expected.(string)[:len(expected.(string))-1]), nil 60 } 61 return strings.Contains(actual.(string), expected.(string)[1:len(expected.(string))-1]), nil 62 case repository.IS: 63 return false, repository.ErrNotImplement 64 65 case repository.NOT: 66 return false, repository.ErrNotImplement 67 68 case repository.IS_NOT: 69 return false, repository.ErrNotImplement 70 71 case repository.IN: 72 return false, repository.ErrNotImplement 73 74 default: 75 return false, repository.ErrNotImplement 76 } 77 } 78 79 func extractObjectAndCheckConditions(object interface{}, params map[string]interface{}, conditionalOperations []repository.ConditionalOperation, relationalOperations []repository.RelationalOperation) (bool, error) { 80 var result bool 81 var prevResult bool 82 var isPrevResultNotSet bool = true 83 var err error 84 index := 0 85 86 if repository.IsMapStringInterface(object) { 87 objectInMap, ok := object.(map[string]interface{}) 88 if !ok { 89 return false, fmt.Errorf("input is not a map[string]interface{}") 90 } 91 92 for k, paramValue := range params { 93 var foundValue interface{} 94 isFound := false 95 for propertyName, propertyValue := range objectInMap { 96 if strings.ToUpper(propertyName) == k { 97 foundValue = propertyValue 98 isFound = true 99 } 100 } 101 if !isFound { 102 return false, repository.ErrNotFound 103 } 104 if result, err = checkConditionalOperation(paramValue, foundValue, conditionalOperations[index]); err != nil { 105 return false, err 106 } 107 108 if isPrevResultNotSet { 109 prevResult = result 110 isPrevResultNotSet = false 111 } else { 112 if prevResult, err = checkRelationalOperation(prevResult, result, relationalOperations[index-1]); err != nil { 113 return false, err 114 } 115 } 116 index++ 117 } 118 119 return prevResult, nil 120 } 121 122 t := reflect.TypeOf(object) 123 v := reflect.ValueOf(object) 124 125 // Iterate through the struct fields 126 index = 0 127 isPrevResultNotSet = true 128 for i := 0; i < t.NumField(); i++ { 129 field := t.Field(i) 130 value := v.Field(i).Interface() 131 132 for k, paramValue := range params { 133 if strings.EqualFold(field.Name, k) && value == paramValue { 134 if result, err = checkConditionalOperation(paramValue, value, conditionalOperations[index]); err != nil { 135 return false, err 136 } 137 138 if isPrevResultNotSet { 139 prevResult = result 140 isPrevResultNotSet = false 141 } else { 142 if prevResult, err = checkRelationalOperation(prevResult, result, relationalOperations[index-1]); err != nil { 143 return false, err 144 } 145 } 146 index++ 147 } 148 } 149 } 150 151 return prevResult, nil 152 } 153 154 // CreateStructPointerSlice creates a slice of struct pointers with the same type as the input struct. 155 // func CreateStructPointerSlice(inputStruct interface{}, numElements int) interface{} { 156 // // Check if the input is already a slice 157 // if reflect.TypeOf(inputStruct).Kind() == reflect.Slice { 158 // return inputStruct 159 // } 160 161 // // Get the type of the input struct. 162 // structType := reflect.TypeOf(inputStruct) 163 164 // // Create a new slice with the same type as a pointer to the input struct. 165 // sliceType := reflect.SliceOf(reflect.PtrTo(structType)) 166 // newSlice := reflect.MakeSlice(sliceType, numElements, numElements) 167 168 // // Create instances of the input struct and store them as pointers in the slice. 169 // for i := 0; i < numElements; i++ { 170 // structPtr := reflect.New(structType).Elem() 171 // newSlice.Index(i).Set(structPtr.Addr()) 172 // } 173 174 // return newSlice.Interface() 175 // } 176 177 // CreateStructPointerSlice creates a slice of struct pointers with the same type as the input struct. 178 func CreateStructPointerSlice(inputStruct interface{}, numElements int) interface{} { 179 // Get the type of the input struct. 180 structType := reflect.TypeOf(inputStruct) 181 182 // Create a new slice with the same type as a pointer to the input struct. 183 sliceType := reflect.SliceOf(reflect.PtrTo(structType)) 184 newSlice := reflect.MakeSlice(sliceType, numElements, numElements) 185 186 // Create instances of the input struct and store them as pointers in the slice. 187 for i := 0; i < numElements; i++ { 188 structPtr := reflect.New(structType).Elem() 189 newSlice.Index(i).Set(structPtr.Addr()) 190 } 191 192 return newSlice.Interface() 193 } 194 195 // CreateNewStructObject takes a struct pointer as a parameter and returns a new object of the same struct type. 196 func CreateNewStructObject(inputStruct interface{}) interface{} { 197 // Get the concrete type of the inputStruct 198 structType := reflect.TypeOf(inputStruct) 199 200 // Create a new instance of the struct type. 201 newStruct := reflect.New(structType).Elem() 202 203 // Copy the values from inputStruct to copiedStruct 204 newStruct.Set(reflect.ValueOf(inputStruct)) 205 206 // Return the new object as an interface{}. 207 return newStruct.Interface() 208 } 209 210 func findItemByID(collection interface{}, data interface{}) (int, error) { 211 resultInArray := cast.StructPointerArrayToInterfacePointerArray(collection) 212 for i, singleResult := range resultInArray { 213 sourceID, err := repository.GetStructPropertyAsString(singleResult, defaultIDPropertyName) 214 if err != nil { 215 return -1, err 216 } 217 218 targetID, err := repository.GetStructPropertyAsString(data, defaultIDPropertyName) 219 if err != nil { 220 return -1, err 221 } 222 223 if sourceID == targetID { 224 return i, nil 225 } 226 } 227 228 return -1, repository.ErrNotFound 229 } 230 231 func UpdateCollection(collection interface{}, data interface{}) ([]interface{}, error) { 232 index, err := findItemByID(collection, data) 233 if err != nil { 234 return nil, err 235 } 236 237 resultInArray := cast.StructPointerArrayToInterfacePointerArray(collection) 238 resultInArray[index] = data 239 return resultInArray, nil 240 } 241 242 func DeleteCollection(collection interface{}, data interface{}) ([]interface{}, error) { 243 index, err := findItemByID(collection, data) 244 if err != nil { 245 return nil, err 246 } 247 248 resultInArray := cast.StructPointerArrayToInterfacePointerArray(collection) 249 return append(resultInArray[:index], resultInArray[index+1:]...), nil 250 } 251 252 // // CreateStructPointerSlice takes an interface{} and returns a slice of struct pointers 253 // func CreateStructPointerSlice(input interface{}) interface{} { 254 // inputType := reflect.TypeOf(input) 255 256 // // Check if the input is a slice 257 // if inputType.Kind() == reflect.Slice { 258 // sliceType := inputType.Elem() 259 // // Check if the slice's element type is a struct 260 // if sliceType.Kind() == reflect.Struct { 261 // // Create a slice of struct pointers 262 // slicePtrType := reflect.SliceOf(reflect.PtrTo(sliceType)) 263 // slicePtr := reflect.New(slicePtrType).Elem() 264 // // Loop through the elements of the input slice and convert them to pointers 265 // for i := 0; i < reflect.ValueOf(input).Len(); i++ { 266 // elem := reflect.ValueOf(input).Index(i) 267 // ptr := reflect.New(sliceType) 268 // ptr.Elem().Set(elem) 269 // slicePtr = reflect.Append(slicePtr, ptr) 270 // } 271 // return slicePtr.Interface() 272 // } 273 // } 274 275 // // Check if the input is a single struct 276 // if inputType.Kind() == reflect.Struct { 277 // // Create a slice with a single struct pointer 278 // slicePtrType := reflect.SliceOf(reflect.PtrTo(inputType)) 279 // slicePtr := reflect.New(slicePtrType).Elem() 280 // ptr := reflect.New(inputType) 281 // ptr.Elem().Set(reflect.ValueOf(input)) 282 // slicePtr = reflect.Append(slicePtr, ptr) 283 // return slicePtr.Interface() 284 // } 285 286 // // Return nil if the input is not a valid type 287 // return nil 288 // } 289 290 // // AreStructsEqual compares two struct objects for equality. 291 // func AreStructsEqual(a, b interface{}) bool { 292 // valA := reflect.ValueOf(a) 293 // valB := reflect.ValueOf(b) 294 295 // // Check if both values are of struct type. 296 // if valA.Kind() != reflect.Struct || valB.Kind() != reflect.Struct { 297 // return false 298 // } 299 300 // // Get the number of fields in each struct. 301 // numFieldsA := valA.NumField() 302 // numFieldsB := valB.NumField() 303 304 // // If the number of fields is different, the structs are not equal. 305 // if numFieldsA != numFieldsB { 306 // return false 307 // } 308 309 // // Compare each field. 310 // for i := 0; i < numFieldsA; i++ { 311 // fieldA := valA.Field(i) 312 // fieldB := valB.Field(i) 313 314 // // Compare field values. 315 // if !reflect.DeepEqual(fieldA.Interface(), fieldB.Interface()) { 316 // return false 317 // } 318 // } 319 320 // // All fields are equal, so the structs are equal. 321 // return true 322 // } 323 324 func AreStructsEqual(struct1, struct2 interface{}) bool { 325 val1 := reflect.Indirect(reflect.ValueOf(struct1)) 326 val2 := reflect.Indirect(reflect.ValueOf(struct2)) 327 328 if val1.Kind() != val2.Kind() { 329 return false 330 } 331 332 if val1.Type() != val2.Type() { 333 return false 334 } 335 336 return reflect.DeepEqual(val1.Interface(), val2.Interface()) 337 } 338 339 // GetPropertyNameToUpperCaseMapping returns a map of property names in upper case for the given struct. 340 func GetPropertyNameToUpperCaseMapping(obj interface{}) (map[string]string, error) { 341 objValue := reflect.ValueOf(obj) 342 if objValue.Kind() != reflect.Struct { 343 return nil, errors.New("input must be a struct") 344 } 345 346 mapping := make(map[string]string) 347 objType := objValue.Type() 348 349 for i := 0; i < objValue.NumField(); i++ { 350 field := objType.Field(i) 351 fieldName := field.Name 352 upperCaseFieldName := strings.ToUpper(fieldName) 353 mapping[fieldName] = upperCaseFieldName 354 } 355 356 return mapping, nil 357 }