package models import ( "regexp" "strings" "time" "github.com/go-playground/validator/v10" ) // CustomValidator wraps the validator type CustomValidator struct { Validator *validator.Validate } // Validate validates struct func (cv *CustomValidator) Validate(i interface{}) error { return cv.Validator.Struct(i) } // RegisterCustomValidations registers custom validation rules func RegisterCustomValidations(v *validator.Validate) { // Validate Indonesian phone number v.RegisterValidation("indonesian_phone", validateIndonesianPhone) // Validate BPJS card number format v.RegisterValidation("bpjs_card", validateBPJSCard) // Validate Indonesian NIK v.RegisterValidation("indonesian_nik", validateIndonesianNIK) // Validate date format YYYY-MM-DD v.RegisterValidation("date_format", validateDateFormat) // Validate ICD-10 code format v.RegisterValidation("icd10", validateICD10) // Validate ICD-9-CM procedure code v.RegisterValidation("icd9cm", validateICD9CM) } func validateIndonesianPhone(fl validator.FieldLevel) bool { phone := fl.Field().String() if phone == "" { return true // Optional field } // Indonesian phone number pattern: +62, 62, 08, or 8 pattern := `^(\+?62|0?8)[1-9][0-9]{7,11}$` matched, _ := regexp.MatchString(pattern, phone) return matched } func validateBPJSCard(fl validator.FieldLevel) bool { card := fl.Field().String() if len(card) != 13 { return false } // BPJS card should be numeric pattern := `^\d{13}$` matched, _ := regexp.MatchString(pattern, card) return matched } func validateIndonesianNIK(fl validator.FieldLevel) bool { nik := fl.Field().String() if len(nik) != 16 { return false } // NIK should be numeric pattern := `^\d{16}$` matched, _ := regexp.MatchString(pattern, nik) return matched } func validateDateFormat(fl validator.FieldLevel) bool { dateStr := fl.Field().String() _, err := time.Parse("2006-01-02", dateStr) return err == nil } func validateICD10(fl validator.FieldLevel) bool { code := fl.Field().String() if code == "" { return true } // Basic ICD-10 pattern: Letter followed by 2 digits, optional dot and more digits pattern := `^[A-Z]\d{2}(\.\d+)?$` matched, _ := regexp.MatchString(pattern, strings.ToUpper(code)) return matched } func validateICD9CM(fl validator.FieldLevel) bool { code := fl.Field().String() if code == "" { return true } // Basic ICD-9-CM procedure pattern: 2-4 digits with optional decimal pattern := `^\d{2,4}(\.\d+)?$` matched, _ := regexp.MatchString(pattern, code) return matched }