package proto import ( "fmt" "math" "reflect" ) func GetMax[T float64 | float32 | int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64](a, b T) T { if a > b { return a } return b } func GetMin[T float64 | float32 | int | uint | int8 | uint8 | int16 | uint16 | int32 | uint32 | int64 | uint64](a, b T) T { if a < b { return a } return b } type EmployeeField string const ( FieldEmpID EmployeeField = "EmpId" FieldNamePrefix = "NamePrefix" FieldFirstName = "FirstName" FieldMiddleInitial = "MiddleInitial" FieldLastName = "LastName" FieldGender = "Gender" FieldEmail = "Email" FieldFathersName = "FathersName" FieldMothersName = "MothersName" FieldMothersMaidenName = "MothersMaidenName" FieldBirthdate = "Birthdate" FieldBirthTime = "BirthTime" FieldWeightKg = "WeightKg" FieldJoiningDate = "JoiningDate" FieldJoiningQuarter = "JoiningQuarter" FieldJoiningHalf = "JoiningHalf" FieldJoiningYear = "JoiningYear" FieldJoiningMonth = "JoiningMonth" FieldJoiningMonthName = "JoiningMonthName" FieldJoiningMonthNameShort = "JoiningMonthNameShort" FieldJoiningMonthDay = "JoiningMonthDay" FieldJoiningWeekDay = "JoiningWeekDay" FieldJoiningWeekDayShort = "JoiningWeekDayShort" FieldYearsOfService = "YearsOfService" FieldSalary = "Salary" FieldLatestHikePercentage = "LatestHikePercentage" FieldSsn = "Ssn" FieldPhoneNumber = "PhoneNumber" FieldPlaceName = "PlaceName" FieldCounty = "County" FieldCity = "City" FieldState = "State" FieldZip = "Zip" FieldRegion = "Region" FieldUsername = "Username" FieldPassword = "Password" ) func (e *Employee) Copy() Employee { return Employee{ EmpId: e.GetEmpId(), NamePrefix: e.GetNamePrefix(), FirstName: e.GetFirstName(), MiddleInitial: e.GetMiddleInitial(), LastName: e.GetLastName(), Gender: e.GetGender(), Email: e.GetEmail(), FathersName: e.GetFathersName(), MothersName: e.GetMothersName(), MothersMaidenName: e.GetMothersMaidenName(), Birthdate: e.GetBirthdate(), BirthTime: e.GetBirthTime(), WeightKg: e.GetWeightKg(), JoiningDate: e.GetJoiningDate(), JoiningQuarter: e.GetJoiningQuarter(), JoiningHalf: e.GetJoiningHalf(), JoiningYear: e.GetJoiningYear(), JoiningMonth: e.GetJoiningMonth(), JoiningMonthName: e.GetJoiningMonthName(), JoiningMonthNameShort: e.GetJoiningMonthNameShort(), JoiningMonthDay: e.GetJoiningMonthDay(), JoiningWeekDay: e.GetJoiningWeekDay(), JoiningWeekDayShort: e.GetJoiningWeekDayShort(), YearsOfService: e.GetYearsOfService(), Salary: e.GetSalary(), LatestHikePercentage: e.GetLatestHikePercentage(), Ssn: e.GetSsn(), PhoneNumber: e.GetPhoneNumber(), PlaceName: e.GetPlaceName(), County: e.GetCounty(), City: e.GetCity(), State: e.GetState(), Zip: e.GetZip(), Region: e.GetRegion(), Username: e.GetUsername(), Password: e.GetPassword(), } } func (el *EmployeeList) QueryEmployeesByColumn(column EmployeeField, query string) ([]*Employee, error) { employees := make([]*Employee, 0) for _, employee := range el.GetEmployees() { value := reflect.ValueOf(employee).Elem().FieldByName(string(column)) if fmt.Sprintf("%v", value) == query { employees = append(employees, employee) } } return employees, nil } type Groups map[string][]*Employee func (el *EmployeeList) GroupByColumn(column EmployeeField) Groups { groups := make(map[string][]*Employee) for _, employee := range el.GetEmployees() { value := reflect.ValueOf(employee).Elem().FieldByName(string(column)) formattedValue := fmt.Sprintf("%v", value) groups[formattedValue] = append(groups[formattedValue], employee) } return groups } type FilterFunction func(*Employee) bool func (grps Groups) HavingByColumn(cb FilterFunction) Groups { newGrps := make(map[string][]*Employee) for groupName, group := range grps { for _, employee := range group { if cb(employee) { newGrps[groupName] = append(newGrps[groupName], employee) } } } return newGrps } func ForEachGroup[T any](grps Groups, cb func(ep EmployeePList) T) map[string]T { g := make(map[string]T) for groupName, group := range grps { g[groupName] = cb(group) } return g } func AggregateByColumn[T any](el *EmployeeList, column EmployeeField, cb func(ep EmployeePList) T) map[string]T { grps := el.GroupByColumn(column) res := ForEachGroup(grps, cb) return res } type EmployeePList []*Employee func Sum(ep EmployeePList, column EmployeeField) float64 { sum := 0.0 _, fieldFound := reflect.TypeOf(Employee{}).FieldByName(string(column)) if !fieldFound { return sum } for _, employee := range ep { value := reflect.ValueOf(employee).Elem().FieldByName(string(column)) switch value.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: sum += float64(value.Int()) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: sum += float64(value.Uint()) case reflect.Float64, reflect.Float32: sum += value.Float() default: return sum } } return sum } func Average(ep EmployeePList, column EmployeeField) float64 { return Sum(ep, column) / float64(len(ep)) } func Max(ep EmployeePList, column EmployeeField) float64 { max := 0.0 _, fieldFound := reflect.TypeOf(Employee{}).FieldByName(string(column)) if !fieldFound { return max } for _, employee := range ep { value := reflect.ValueOf(employee).Elem().FieldByName(string(column)) switch value.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: max = GetMax(max, float64(value.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: max = GetMax(max, float64(value.Uint())) case reflect.Float64, reflect.Float32: max = GetMax(max, value.Float()) default: return max } } return max } func Min(ep EmployeePList, column EmployeeField) float64 { min := math.MaxFloat64 _, fieldFound := reflect.TypeOf(Employee{}).FieldByName(string(column)) if !fieldFound { return min } for _, employee := range ep { value := reflect.ValueOf(employee).Elem().FieldByName(string(column)) switch value.Kind() { case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: min = GetMin(min, float64(value.Int())) case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: min = GetMin(min, float64(value.Uint())) case reflect.Float64, reflect.Float32: min = GetMin(min, value.Float()) default: return min } } return min }