mirror of
https://github.com/therootcompany/golib.git
synced 2026-11-04 06:55:00 +00:00
feat: add permissive text and list values
This commit is contained in:
parent
ca6e271f66
commit
bd03bfb769
@ -4,6 +4,7 @@
|
||||
// can be read from a sheet, written to a file, and scanned from a database.
|
||||
//
|
||||
// It also provides generic Parse/Serialize functions for CSV, TSV, JSON,
|
||||
// and JSONL, delimiter-specific string and integer slices, plus text
|
||||
// normalization helpers (NormalizeEmail, NormalizePhone).
|
||||
// and JSONL, delimiter-specific string and integer slices, and permissive
|
||||
// text/list value types, plus normalization helpers (NormalizeEmail,
|
||||
// NormalizePhone).
|
||||
package csvx
|
||||
|
||||
26
database/csvx/listish.go
Normal file
26
database/csvx/listish.go
Normal file
@ -0,0 +1,26 @@
|
||||
package csvx
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Listish is a list encoded as comma- or whitespace-delimited text.
|
||||
type Listish []string
|
||||
|
||||
// UnmarshalCSV parses comma- or whitespace-delimited values.
|
||||
func (s *Listish) UnmarshalCSV(data []byte) error {
|
||||
if len(data) == 0 {
|
||||
*s = Listish{}
|
||||
return nil
|
||||
}
|
||||
parts := strings.FieldsFunc(string(data), func(r rune) bool {
|
||||
return r == ',' || unicode.IsSpace(r)
|
||||
})
|
||||
if len(parts) == 0 {
|
||||
*s = Listish{}
|
||||
return nil
|
||||
}
|
||||
*s = Listish(parts)
|
||||
return nil
|
||||
}
|
||||
31
database/csvx/listish_test.go
Normal file
31
database/csvx/listish_test.go
Normal file
@ -0,0 +1,31 @@
|
||||
package csvx
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestListishUnmarshalCSV(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
in string
|
||||
want Listish
|
||||
}{
|
||||
{name: "comma", in: "admin,hr,pm", want: Listish{"admin", "hr", "pm"}},
|
||||
{name: "whitespace", in: "admin hr\tpm", want: Listish{"admin", "hr", "pm"}},
|
||||
{name: "mixed", in: " admin, hr\npm ", want: Listish{"admin", "hr", "pm"}},
|
||||
{name: "empty", in: " , \t", want: Listish{}},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
var got Listish
|
||||
if err := got.UnmarshalCSV([]byte(tt.in)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Fatalf("got %#v, want %#v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
60
database/csvx/textish.go
Normal file
60
database/csvx/textish.go
Normal file
@ -0,0 +1,60 @@
|
||||
package csvx
|
||||
|
||||
import (
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Textish is text with common explicit-empty words normalized to an empty value.
|
||||
type Textish string
|
||||
|
||||
func (t Textish) Empty() bool { return string(t) == "" }
|
||||
|
||||
func (t Textish) String() string { return string(t) }
|
||||
|
||||
func normalizeTextish(value string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(value)) {
|
||||
case "", "none", "disable", "disabled":
|
||||
return ""
|
||||
default:
|
||||
return strings.TrimSpace(value)
|
||||
}
|
||||
}
|
||||
|
||||
func (t Textish) Value() (driver.Value, error) { return string(t), nil }
|
||||
|
||||
func (t *Textish) Scan(value any) error {
|
||||
if value == nil {
|
||||
*t = ""
|
||||
return nil
|
||||
}
|
||||
switch v := value.(type) {
|
||||
case string:
|
||||
*t = Textish(normalizeTextish(v))
|
||||
case []byte:
|
||||
*t = Textish(normalizeTextish(string(v)))
|
||||
default:
|
||||
return fmt.Errorf("csvx.Textish: cannot scan %T", value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t Textish) MarshalCSV() ([]byte, error) { return []byte(t), nil }
|
||||
|
||||
func (t *Textish) UnmarshalCSV(data []byte) error {
|
||||
*t = Textish(normalizeTextish(string(data)))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t Textish) MarshalJSON() ([]byte, error) { return json.Marshal(string(t)) }
|
||||
|
||||
func (t *Textish) UnmarshalJSON(data []byte) error {
|
||||
var value string
|
||||
if err := json.Unmarshal(data, &value); err != nil {
|
||||
return err
|
||||
}
|
||||
*t = Textish(normalizeTextish(value))
|
||||
return nil
|
||||
}
|
||||
22
database/csvx/textish_test.go
Normal file
22
database/csvx/textish_test.go
Normal file
@ -0,0 +1,22 @@
|
||||
package csvx
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestTextishNormalizesExplicitEmptyValues(t *testing.T) {
|
||||
for _, value := range []string{"", "none", "disable", "disabled", " NONE "} {
|
||||
var got Textish
|
||||
if err := got.UnmarshalCSV([]byte(value)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !got.Empty() {
|
||||
t.Fatalf("Textish(%q) = %q, want empty", value, got)
|
||||
}
|
||||
}
|
||||
var got Textish
|
||||
if err := got.UnmarshalCSV([]byte("https://hooks.example.test/enrich")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got.String() != "https://hooks.example.test/enrich" {
|
||||
t.Fatalf("Textish URL = %q", got)
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user