mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-17 16:38:54 +00:00
The DKVPX record reader set dkvpxReader.Comma = ',' unconditionally,
ignoring the resolved --ifs value; the key-value separator '=' was
likewise hard-coded in the dkvpx parser, ignoring --ips. So e.g.
printf 'a=1;b=2\n' | mlr -i dkvpx --ifs semicolon --ojson cat
produced a single field {"a": "1;b=2"} instead of {"a": 1, "b": 2}.
Fixes:
* pkg/dkvpx.Reader gains an Equals field (default '=') alongside Comma.
* The DKVPX record reader now passes the resolved IFS/IPS through,
validating that each is a single character (mirroring the CSV
reader's "IFS can only be a single character" error) rather than
silently ignoring or truncating them.
* The DKVPX record writer already emitted OFS/OPS, but its quoting
decisions were based on the default separators, so with --ofs
semicolon a value containing ';' went out unquoted (ambiguous) while
a value containing ',' was quoted needlessly. Quoting now keys off
the actual OFS/OPS.
Adds unit tests, regression cases under test/cases/io-dkvpx/, and a
note in the separators reference table.
Discovered while investigating #369; tracked in #2170.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
55 lines
1.4 KiB
Go
55 lines
1.4 KiB
Go
package output
|
|
|
|
import (
|
|
"bufio"
|
|
|
|
"github.com/johnkerl/miller/v6/pkg/cli"
|
|
"github.com/johnkerl/miller/v6/pkg/colorizer"
|
|
"github.com/johnkerl/miller/v6/pkg/dkvpx"
|
|
"github.com/johnkerl/miller/v6/pkg/mlrval"
|
|
"github.com/johnkerl/miller/v6/pkg/types"
|
|
)
|
|
|
|
type RecordWriterDKVPX struct {
|
|
writerOptions *cli.TWriterOptions
|
|
}
|
|
|
|
func NewRecordWriterDKVPX(writerOptions *cli.TWriterOptions) (*RecordWriterDKVPX, error) {
|
|
return &RecordWriterDKVPX{
|
|
writerOptions: writerOptions,
|
|
}, nil
|
|
}
|
|
|
|
func (writer *RecordWriterDKVPX) Write(
|
|
outrec *mlrval.Mlrmap,
|
|
_ *types.Context,
|
|
bufferedOutputStream *bufio.Writer,
|
|
outputIsStdout bool,
|
|
) error {
|
|
if outrec == nil {
|
|
return nil
|
|
}
|
|
|
|
if outrec.IsEmpty() {
|
|
bufferedOutputStream.WriteString(writer.writerOptions.ORS)
|
|
return nil
|
|
}
|
|
|
|
first := true
|
|
for pe := outrec.Head; pe != nil; pe = pe.Next {
|
|
if !first {
|
|
bufferedOutputStream.WriteString(writer.writerOptions.OFS)
|
|
}
|
|
first = false
|
|
|
|
keyStr := dkvpx.FormatFieldWithSeparators(pe.Key, writer.writerOptions.OFS, writer.writerOptions.OPS)
|
|
valStr := dkvpx.FormatFieldWithSeparators(pe.Value.String(), writer.writerOptions.OFS, writer.writerOptions.OPS)
|
|
|
|
bufferedOutputStream.WriteString(colorizer.MaybeColorizeKey(keyStr, outputIsStdout))
|
|
bufferedOutputStream.WriteString(writer.writerOptions.OPS)
|
|
bufferedOutputStream.WriteString(colorizer.MaybeColorizeValue(valStr, outputIsStdout))
|
|
}
|
|
bufferedOutputStream.WriteString(writer.writerOptions.ORS)
|
|
|
|
return nil
|
|
}
|