diff --git a/database/csvx/boolish.go b/database/csvx/boolish.go index 757e192..f295888 100644 --- a/database/csvx/boolish.go +++ b/database/csvx/boolish.go @@ -9,14 +9,23 @@ import ( // BoolishTimestamp accepts optional true/false-like values and dates or // timestamps from human-edited CSV/TSV data. Valid reports that a value was // supplied; Bool reports its true-like meaning. Error records an unrecognized -// non-empty value without making the CSV decoder reject the row. +// non-empty value without making the CSV decoder reject the row. Raw reports +// the trimmed original value for unrecognized values so callers can apply +// their own column-specific word policy (e.g. reading "disabled" as true in +// a Disabled column). type BoolishTimestamp struct { Valid bool Bool bool Timestamp time.Time Error error + + raw string } +// Raw returns the trimmed original value that was parsed, retained for +// unrecognized values so callers can apply their own word policy. +func (v BoolishTimestamp) Raw() string { return v.raw } + // UnmarshalCSV parses a human value. Recognized true-like values and dates // set Bool; recognized false-like values leave it unset. Unrecognized // non-empty values are conservatively false with the error retained so the @@ -46,8 +55,10 @@ func (v *BoolishTimestamp) UnmarshalCSV(data []byte) error { } } // Unrecognized: valid but false, error recorded (Bool must not default - // to true for values this type does not understand). + // to true for values this type does not understand). The original value + // is retained for caller-side word policy. v.Bool = false + v.raw = raw v.Error = fmt.Errorf("unrecognized boolish timestamp %q", raw) return nil } diff --git a/database/csvx/csvx_test.go b/database/csvx/csvx_test.go index 481cb64..2100065 100644 --- a/database/csvx/csvx_test.go +++ b/database/csvx/csvx_test.go @@ -223,6 +223,9 @@ func TestBoolishTimestamp(t *testing.T) { if !v.Valid || v.Bool || v.Error == nil { t.Fatalf("%q: expected valid+false+error, got %+v", word, v) } + if v.Raw() != word { + t.Fatalf("%q: Raw() = %q, want the original word retained", word, v.Raw()) + } } // Empty / null sentinels: `\N` exact; word forms any case. The full