Skip to content

Commit

Permalink
Add missing summary for unaligned tables
Browse files Browse the repository at this point in the history
  • Loading branch information
kenshaw committed Apr 1, 2024
1 parent 8ba91cf commit b4e589b
Show file tree
Hide file tree
Showing 14 changed files with 171 additions and 153 deletions.
63 changes: 36 additions & 27 deletions encode.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ type TableEncoder struct {
// skipHeader disables writing header.
skipHeader bool
// summary is the summary map.
summary map[int]func(io.Writer, int) (int, error)
summary Summary
// isCustomSummary when summary has been set via options
isCustomSummary bool
// title is the title value.
Expand Down Expand Up @@ -212,7 +212,7 @@ func (enc *TableEncoder) Encode(w io.Writer) error {
}
}
// add summary
if err := enc.summarize(w); err != nil {
if err := summarize(enc.w, enc.summary, enc.scanCount); err != nil {
return err
}
if err := enc.w.Flush(); err != nil {
Expand Down Expand Up @@ -558,30 +558,6 @@ func (enc *TableEncoder) writeAligned(b, filler []byte, a Align, padding int) {
}
}

// summarize writes the table scan count summary.
func (enc *TableEncoder) summarize(w io.Writer) error {
// do summary
if enc.summary == nil {
return nil
}
var f func(io.Writer, int) (int, error)
if z, ok := enc.summary[-1]; ok {
f = z
}
if z, ok := enc.summary[int(enc.scanCount)]; ok {
f = z
}
if f != nil {
if _, err := f(enc.w, int(enc.scanCount)); err != nil {
return err
}
if _, err := enc.w.Write(enc.newline); err != nil {
return err
}
}
return nil
}

// rowStyle is the row style for a row, as arrays of bytes to print.
type rowStyle struct {
left, right, middle, filler, wrapper []byte
Expand Down Expand Up @@ -671,7 +647,9 @@ func (enc *ExpandedEncoder) Encode(w io.Writer) error {
}
}
// add summary
enc.summarize(w)
if err := summarize(w, enc.summary, enc.scanCount); err != nil {
return err
}
if err := enc.w.Flush(); err != nil {
return checkErr(err, cmd)
}
Expand Down Expand Up @@ -988,6 +966,8 @@ type UnalignedEncoder struct {
formatter Formatter
// skipHeader disables writing header.
skipHeader bool
// summary is the summary map.
summary map[int]func(io.Writer, int) (int, error)
// empty is the empty value.
empty *Value
// lowerColumnNames indicates lower casing the column names when column
Expand All @@ -1007,6 +987,7 @@ func NewUnalignedEncoder(resultSet ResultSet, opts ...Option) (Encoder, error) {
quote: quote,
newline: newline,
formatter: NewEscapeFormatter(WithIsRaw(true, sep, quote)),
summary: DefaultTableSummary(),
empty: &Value{
Tabs: make([][][2]int, 1),
},
Expand All @@ -1031,6 +1012,7 @@ func NewCSVEncoder(resultSet ResultSet, opts ...Option) (Encoder, error) {
quote: quote,
newline: newline,
formatter: NewEscapeFormatter(WithIsRaw(true, sep, quote)),
summary: Summary{},
empty: &Value{
Tabs: make([][][2]int, 1),
},
Expand Down Expand Up @@ -1116,6 +1098,9 @@ func (enc *UnalignedEncoder) Encode(w io.Writer) error {
return err
}
}
if err := summarize(w, enc.summary, count); err != nil {
return err
}
return enc.resultSet.Err()
}

Expand Down Expand Up @@ -1343,3 +1328,27 @@ func buildColumnTypes(resultSet ResultSet, n int, columnTypes func(ResultSet, []
}
return r, nil
}

// summarize writes the table scan count summary.
func summarize(w io.Writer, summary Summary, count int64) error {
// do summary
if summary == nil {
return nil
}
var f func(io.Writer, int) (int, error)
if z, ok := summary[-1]; ok {
f = z
}
if z, ok := summary[int(count)]; ok {
f = z
}
if f != nil {
if _, err := f(w, int(count)); err != nil {
return err
}
if _, err := w.Write(newline); err != nil {
return err
}
}
return nil
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ require (
golang.org/x/text v0.14.0
)

require github.com/rivo/uniseg v0.4.4 // indirect
require github.com/rivo/uniseg v0.4.7 // indirect
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh
github.com/nathan-fiscaletti/consolesize-go v0.0.0-20220204101620-317176b6684d h1:NqRhLdNVlozULwM1B3VaHhcXYSgrOAv8V5BE65om+1Q=
github.com/nathan-fiscaletti/consolesize-go v0.0.0-20220204101620-317176b6684d/go.mod h1:cxIIfNMTwff8f/ZvRouvWYF6wOoO7nj99neWSx2q/Es=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
48 changes: 24 additions & 24 deletions internal/rset.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,26 @@ import (
"time"
)

// Rset is a result set.
type Rset struct {
// RS is a result set.
type RS struct {
rs int
pos int
cols []string
vals [][][]interface{}
}

// NewRset creates a new result set
func NewRset(cols []string, vals ...[][]interface{}) *Rset {
return &Rset{
// New creates a new result set
func New(cols []string, vals ...[][]interface{}) *RS {
return &RS{
cols: cols,
vals: vals,
}
}

// NewRsetMulti creates a result set with multiple result sets.
func NewRsetMulti() *Rset {
// Multi creates a result set with multiple result sets.
func Multi() *RS {
s, t := rset(14), rset(38)
r := &Rset{
r := &RS{
cols: []string{"author_id", "name", "z"},
vals: [][][]interface{}{
s[:2], s[2:], t,
Expand All @@ -35,8 +35,8 @@ func NewRsetMulti() *Rset {
return r
}

// NewRsetBig creates a random, big result set using the provided seed.
func NewRsetBig(seed int64) *Rset {
// Big creates a random, big result set using the provided seed.
func Big(seed int64) *RS {
src := rand.New(rand.NewSource(seed))
count := src.Intn(1000)
// generate rows
Expand All @@ -45,15 +45,15 @@ func NewRsetBig(seed int64) *Rset {
p := newRrow(src)
vals[i] = []interface{}{i + 1, p.name, p.dob, p.f, p.hash, p.char, p.z}
}
return &Rset{
return &RS{
cols: []string{"id", "name", "dob", "float", "hash", "", "z"},
vals: [][][]interface{}{vals},
}
}

// NewRsetTiny creates a tiny result set.
func NewRsetTiny() *Rset {
return &Rset{
// Tiny creates a tiny result set.
func Tiny() *RS {
return &RS{
cols: []string{"z"},
vals: [][][]interface{}{
{
Expand All @@ -63,9 +63,9 @@ func NewRsetTiny() *Rset {
}
}

// NewRsetWide creates a wide result set.
func NewRsetWide() *Rset {
return &Rset{
// Wide creates a wide result set.
func Wide() *RS {
return &RS{
cols: []string{
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
Expand All @@ -87,27 +87,27 @@ func NewRsetWide() *Rset {
}

// Err satisfies the ResultSet interface.
func (*Rset) Err() error {
func (*RS) Err() error {
return nil
}

// Err satisfies the ResultSet interface.
func (*Rset) Close() error {
func (*RS) Close() error {
return nil
}

// Err satisfies the ResultSet interface.
func (r *Rset) Columns() ([]string, error) {
func (r *RS) Columns() ([]string, error) {
return r.cols, nil
}

// Err satisfies the ResultSet interface.
func (r *Rset) Next() bool {
func (r *RS) Next() bool {
return r.pos < len(r.vals[r.rs])
}

// Err satisfies the ResultSet interface.
func (r *Rset) Scan(vals ...interface{}) error {
func (r *RS) Scan(vals ...interface{}) error {
for i := range vals {
x, ok := vals[i].(*interface{})
if !ok {
Expand All @@ -120,13 +120,13 @@ func (r *Rset) Scan(vals ...interface{}) error {
}

// Err satisfies the ResultSet interface.
func (r *Rset) NextResultSet() bool {
func (r *RS) NextResultSet() bool {
r.rs, r.pos = r.rs+1, 0
return r.rs < len(r.vals)
}

// Reset resets the rset so that it can be used repeatedly.
func (r *Rset) Reset() {
func (r *RS) Reset() {
r.pos, r.rs = 0, 0
}

Expand Down
21 changes: 15 additions & 6 deletions opts.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ import (
// Builder is the shared builder interface.
type Builder = func(ResultSet, ...Option) (Encoder, error)

// Summary is the interface for a summary map.
type Summary = map[int]func(io.Writer, int) (int, error)

// Option is a Encoder option.
type Option interface {
apply(interface{}) error
Expand Down Expand Up @@ -92,9 +95,9 @@ func FromMap(opts map[string]string) (Builder, []Option) {
}
case "csv", "unaligned":
// determine separator, quote
sep, quote, field := '|', rune(0), "fieldsep"
enc, sep, quote, field := NewUnalignedEncoder, '|', rune(0), "fieldsep"
if format == "csv" {
sep, quote, field = ',', '"', "csv_fieldsep"
enc, sep, quote, field = NewCSVEncoder, ',', '"', "csv_fieldsep"
}
if s, ok := opts[field]; ok {
r := []rune(s)
Expand All @@ -118,7 +121,7 @@ func FromMap(opts map[string]string) (Builder, []Option) {
if opts["recordsep_zero"] == "on" {
recordsep = []byte{0}
}
return NewUnalignedEncoder, []Option{
tableOpts := []Option{
WithSeparator(sep),
WithQuote(quote),
WithFormatter(NewEscapeFormatter(WithIsRaw(true, sep, quote))),
Expand All @@ -130,6 +133,11 @@ func FromMap(opts map[string]string) (Builder, []Option) {
WithUseColumnTypes(opts["use_column_types"] == "true"),
FormatterOptionFromMap(opts),
}
if s, ok := opts["footer"]; ok && s == "off" {
// use an empty summary map to skip drawing the footer
tableOpts = append(tableOpts, WithSummary(Summary{}))
}
return enc, tableOpts
case "html", "asciidoc", "latex", "latex-longtable", "troff-ms", "vertical":
return NewTemplateEncoder, []Option{
WithTemplate(format),
Expand Down Expand Up @@ -162,7 +170,7 @@ func FromMap(opts map[string]string) (Builder, []Option) {
}
if s, ok := opts["footer"]; ok && s == "off" {
// use an empty summary map to skip drawing the footer
tableOpts = append(tableOpts, WithSummary(map[int]func(io.Writer, int) (int, error){}))
tableOpts = append(tableOpts, WithSummary(Summary{}))
}
if s, ok := opts["linestyle"]; ok {
switch s {
Expand Down Expand Up @@ -328,8 +336,8 @@ func WithFormatterOptions(opts ...EscapeFormatterOption) Option {
}
}

// WithSummary is a encoder option to set a summary map.
func WithSummary(summary map[int]func(io.Writer, int) (int, error)) Option {
// WithSummary is a encoder option to set a table summary.
func WithSummary(summary Summary) Option {
return option{
table: func(enc *TableEncoder) error {
enc.summary = summary
Expand All @@ -346,6 +354,7 @@ func WithSummary(summary map[int]func(io.Writer, int) (int, error)) Option {
return nil
},
unaligned: func(enc *UnalignedEncoder) error {
enc.summary = summary
return nil
},
template: func(enc *TemplateEncoder) error {
Expand Down
10 changes: 5 additions & 5 deletions opts_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func TestFromMap(t *testing.T) {
opts: map[string]string{
"format": "csv",
},
exp: NewUnalignedEncoder,
exp: NewCSVEncoder,
},
"any": {
opts: map[string]string{
Expand Down Expand Up @@ -88,13 +88,13 @@ func TestFromMapFormats(t *testing.T) {
var resultSet ResultSet
switch typ {
case "big":
resultSet = internal.NewRsetBig(1549508725559526476)
resultSet = internal.Big(1549508725559526476)
case "multi":
resultSet = internal.NewRsetMulti()
resultSet = internal.Multi()
case "tiny":
resultSet = internal.NewRsetTiny()
resultSet = internal.Tiny()
case "wide":
resultSet = internal.NewRsetWide()
resultSet = internal.Wide()
}
var optMap map[string]string
var exp []byte
Expand Down
Loading

0 comments on commit b4e589b

Please sign in to comment.