lib/app/service-helpers.go

158 lines
4.0 KiB
Go

package app
import (
"database/sql"
"fmt"
"reflect"
"time"
)
const dateFormat = "2006-01-02"
const dateTimeFormat = "2006-01-02T15:04:05-0800"
// String takes a string and returns a pointer to the string.
func String(s string) *string {
return &s
}
// Bool takes a bool and returns a pointer to the bool.
func Bool(b bool) *bool {
return &b
}
// Int64 takes an int64 and returns a pointer to the int64.
func Int64(i int64) *int64 {
return &i
}
// Int takes an int and returns a pointer to the int.
func Int(i int) *int {
return &i
}
// Time takes a time.Time and returns a pointer to the time.Time.
func Time(t time.Time) *time.Time {
return &t
}
// Float64 takes a float64 and returns a pointer to the float64.
func Float64(f float64) *float64 {
return &f
}
// FieldsAndValues is a struct that holds field names and corresponding values for an object.
type FieldsAndValues struct {
fieldNames []string
fieldValues []interface{}
}
// GetFieldsAndValues takes an object and returns a pointer to a FieldsAndValues struct
// containing the field names and corresponding values for each non-zero field,
// excluding the "ID" field.
func GetFieldsAndValues(obj interface{}) *FieldsAndValues {
result := &FieldsAndValues{
fieldNames: []string{},
fieldValues: []interface{}{},
}
v := reflect.ValueOf(obj).Elem()
t := v.Type()
for i := 0; i < t.NumField(); i++ {
field := t.Field(i)
fieldValue := v.Field(i)
if field.Name != "ID" {
if !IsZero(fieldValue) {
fmt.Printf("DEBUG: Adding field %s with value %v\n", field.Name, fieldValue.Interface())
result.fieldNames = append(result.fieldNames, field.Name)
result.fieldValues = append(result.fieldValues, fieldValue.Interface())
}
}
}
return result
}
// IsZero checks if a value is zero or considered zero-like (e.g., empty arrays or slices, nil pointers).
// Note that strings, including empty strings, are treated as non-zero values.
func IsZero(v reflect.Value) bool {
switch v.Kind() {
case reflect.String:
return false // Treat strings, including empty strings, as non-zero values
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
if !IsZero(v.Field(i)) {
return false
}
}
return true
case reflect.Ptr, reflect.Interface:
if v.IsNil() {
return true
}
return IsZero(v.Elem())
case reflect.Array, reflect.Slice:
return v.Len() == 0
default:
z := reflect.Zero(v.Type())
return v.Interface() == z.Interface()
}
}
// SqlDateToString takes a pointer to a sql.NullTime object and returns a pointer to a string
// representing the date in dateTimeFormat if the sql.NullTime object is valid, otherwise returns nil.
func SqlDateToString(d *sql.NullTime) *string {
if d == nil || !d.Valid {
return nil
}
dateStr := d.Time.Format(dateTimeFormat)
return &dateStr
}
// StringToSqlDate takes a pointer to a string representing a date and returns a pointer to
// a sql.NullTime object containing the parsed date if the string is not nil, otherwise returns nil.
func StringToSqlDate(s *string) *sql.NullTime {
if s == nil {
return nil
}
parsedTime, err := ParseDateTime(s)
if err != nil {
return nil
}
return &sql.NullTime{
Time: *parsedTime,
Valid: true,
}
}
// ParseDateTime takes a pointer to a string representing a date and returns a pointer to
// a time.Time object containing the parsed date if the string is in one of the supported formats.
// If the string is nil or not in a supported format, returns an error.
func ParseDateTime(dateStr *string) (*time.Time, error) {
if dateStr == nil {
return nil, fmt.Errorf("✋members.parseDateTime: dateStr is null")
}
loc, _ := time.LoadLocation("Local")
//
formats := []string{dateFormat, dateTimeFormat, time.RFC1123, time.RFC3339}
var parsedTime *time.Time
for _, format := range formats {
tm, err := time.ParseInLocation(format, *dateStr, loc)
if err == nil {
parsedTime = &tm
break
}
}
if parsedTime == nil {
return nil, fmt.Errorf("✋parseDateTime: input string doesn't match any of the expected formats")
}
return parsedTime, nil
}