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  }