// Decoder provides some configuration options for the decoders.
type Decoder struct {
+ // Format specifies a specific format to decode from. If empty or
+ // unspecified, it's inferred from the contents or the filename.
+ Format string
+
// Delimiter is the field delimiter. Used in the CSV decoder. Default is
// ','.
Delimiter rune
// OptionsKey is used in cache keys.
func (d Decoder) OptionsKey() string {
var sb strings.Builder
+ sb.WriteString(d.Format)
sb.WriteRune(d.Delimiter)
sb.WriteRune(d.Comment)
sb.WriteString(strconv.FormatBool(d.LazyQuotes))
}
v, err := ns.cacheUnmarshal.GetOrCreate(key, func(string) (*resources.StaleValue[any], error) {
- f := metadecoders.FormatFromStrings(r.MediaType().Suffixes()...)
- if f == "" {
- return nil, fmt.Errorf("MIME %q not supported", r.MediaType())
+ var f metadecoders.Format
+ if decoder.Format != "" {
+ f = metadecoders.FormatFromString(decoder.Format)
+ if f == "" {
+ return nil, fmt.Errorf("format %q not supported", decoder.Format)
+ }
+ } else {
+ f = metadecoders.FormatFromStrings(r.MediaType().Suffixes()...)
+ if f == "" {
+ return nil, fmt.Errorf("MIME %q not supported", r.MediaType())
+ }
}
reader, err := r.ReadSeekCloser()
key := hashing.MD5FromStringHexEncoded(dataStr)
+ if decoder != metadecoders.Default {
+ key += decoder.OptionsKey()
+ }
+
v, err := ns.cacheUnmarshal.GetOrCreate(key, func(string) (*resources.StaleValue[any], error) {
- f := decoder.FormatFromContentString(dataStr)
- if f == "" {
- return nil, errors.New("unknown format")
+ var f metadecoders.Format
+ if decoder.Format != "" {
+ f = metadecoders.FormatFromString(decoder.Format)
+ if f == "" {
+ return nil, fmt.Errorf("format %q not supported", decoder.Format)
+ }
+ } else {
+ f = decoder.FormatFromContentString(dataStr)
+ if f == "" {
+ return nil, errors.New("unknown format")
+ }
}
v, err := decoder.Unmarshal([]byte(dataStr), f)
{testContentResource{key: "r1", content: `a;b;c`, mime: media.Builtin.CSVType}, map[string]any{"delimiter": ";"}, func(r [][]string) {
b.Assert([][]string{{"a", "b", "c"}}, qt.DeepEquals, r)
}},
+ {testContentResource{key: "r1", content: `{p: [a, b]}`, mime: media.Builtin.JSONType}, map[string]any{"format": "yaml"}, func(m map[string]any) {
+ b.Assert(m, qt.DeepEquals, map[string]any{"p": []any{"a", "b"}})
+ }},
{"a,b,c", nil, func(r [][]string) {
b.Assert([][]string{{"a", "b", "c"}}, qt.DeepEquals, r)
}},
}},
{``, nil, nil},
{` `, nil, nil},
+ {`{p: [a, b]}`, map[string]any{"format": "yaml"}, func(m map[string]any) {
+ b.Assert(m, qt.DeepEquals, map[string]any{"p": []any{"a", "b"}})
+ }},
// errors
{"thisisnotavaliddataformat", nil, false},
{testContentResource{key: "r1", content: `invalid&toml"`, mime: media.Builtin.TOMLType}, nil, false},
{"thisisnotavaliddataformat", nil, false},
{`{ notjson }`, nil, false},
{tstNoStringer{}, nil, false},
+ {"<root><a>notjson</a></root>", map[string]any{"format": "json"}, false},
+ {"anything", map[string]any{"format": "invalidformat"}, false},
} {
ns.Reset()