package validators import ( "fmt" "github.com/go-playground/validator/v10" "reflect" "regexp" "strconv" "strings" "time" ) var Validate *validator.Validate func init() { Validate = validator.New() Validate.RegisterTagNameFunc(func(fld reflect.StructField) string { name := strings.SplitN(fld.Tag.Get("json"), ",", 2)[0] if name == "-" { return "" } return name }) } // ID format: 12-character hexadecimal string (from gen_random_bytes(6) encoded as hex) var validIDRegex = regexp.MustCompile(`^[0-9a-fA-F]{12}$`) // IsValidID checks if an ID is valid based on the database constraint (CHAR(12) hex string) // Valid IDs are exactly 12 hexadecimal characters (0-9, a-f) func IsValidID(id string) bool { if id == "" { return false } return validIDRegex.MatchString(id) } // ParseCursor splits a "createdAt|id" cursor string into its components. func ParseCursor(cursor string) (time.Time, string, error) { parts := strings.SplitN(cursor, "|", 2) if len(parts) != 2 { return time.Time{}, "", fmt.Errorf("invalid cursor format") } t, err := time.Parse(time.RFC3339, parts[0]) if err != nil { return time.Time{}, "", fmt.Errorf("invalid cursor created_at: %w", err) } return t, parts[1], nil } func ParseCursor3(cursor string) (int, time.Time, string, error) { parts := strings.SplitN(cursor, "|", 3) if len(parts) != 3 { return 0, time.Time{}, "", fmt.Errorf("invalid cursor format") } count, err := strconv.Atoi(parts[0]) if err != nil { return 0, time.Time{}, "", fmt.Errorf("invalid cursor completed_count: %w", err) } t, err := time.Parse(time.RFC3339, parts[1]) if err != nil { return 0, time.Time{}, "", fmt.Errorf("invalid cursor created_at: %w", err) } return count, t, parts[2], nil }