From 68484ef9545c139622f2dced89723501bcf1b965 Mon Sep 17 00:00:00 2001 From: Jaeyeol Shin Date: Fri, 2 Jan 2026 20:44:21 +0900 Subject: [PATCH 1/2] fix: allow colon in column qualifier --- cbt.go | 58 ++++++++++++++++++----------------------------------- cbt_test.go | 30 ++++++++++----------------- 2 files changed, 31 insertions(+), 57 deletions(-) diff --git a/cbt.go b/cbt.go index d38d8b5..ce0f273 100755 --- a/cbt.go +++ b/cbt.go @@ -1393,10 +1393,7 @@ func doLookup(ctx context.Context, args ...string) { filters = append(filters, bigtable.LatestNFilter(n)) } if columns := parsed["columns"]; columns != "" { - columnFilters, err := parseColumnsFilter(columns) - if err != nil { - log.Fatal(err) - } + columnFilters := parseColumnsFilter(columns) filters = append(filters, columnFilters) } @@ -1636,10 +1633,7 @@ func doRead(ctx context.Context, args ...string) { filters = append(filters, bigtable.RowKeyFilter(regex)) } if columns := parsed["columns"]; columns != "" { - columnFilters, err := parseColumnsFilter(columns) - if err != nil { - log.Fatal(err) - } + columnFilters := parseColumnsFilter(columns) filters = append(filters, columnFilters) } var keysOnly bool @@ -1761,10 +1755,7 @@ func doCheckAndMutate(ctx context.Context, args ...string) { // Parse the lookup test. filter := bigtable.LatestNFilter(1) if arg, ok := parsed["columns"]; ok { - var err error - if filter, err = parseColumnsFilter(arg); err != nil { - log.Fatalf("While parsing columns=...: %v", err) - } + filter = parseColumnsFilter(arg) } // Parse mutations. @@ -2680,44 +2671,35 @@ func stringInSlice(s string, list []string) bool { return false } -func parseColumnsFilter(columns string) (bigtable.Filter, error) { +func parseColumnsFilter(columns string) bigtable.Filter { splitColumns := strings.FieldsFunc(columns, func(c rune) bool { return c == ',' }) if len(splitColumns) == 1 { - filter, err := columnFilter(splitColumns[0]) - if err != nil { - return nil, err - } - return filter, nil + filter := columnFilter(splitColumns[0]) + return filter } var columnFilters []bigtable.Filter for _, column := range splitColumns { - filter, err := columnFilter(column) - if err != nil { - return nil, err - } + filter := columnFilter(column) columnFilters = append(columnFilters, filter) } - return bigtable.InterleaveFilters(columnFilters...), nil + return bigtable.InterleaveFilters(columnFilters...) } -func columnFilter(column string) (bigtable.Filter, error) { - splitColumn := strings.Split(column, ":") +func columnFilter(column string) bigtable.Filter { + splitColumn := strings.SplitN(column, ":", 2) if len(splitColumn) == 1 { - return bigtable.ColumnFilter(splitColumn[0]), nil - } else if len(splitColumn) == 2 { - if strings.HasSuffix(column, ":") { - return bigtable.FamilyFilter(splitColumn[0]), nil - } else if strings.HasPrefix(column, ":") { - return bigtable.ColumnFilter(splitColumn[1]), nil - } else { - familyFilter := bigtable.FamilyFilter(splitColumn[0]) - qualifierFilter := bigtable.ColumnFilter(splitColumn[1]) - return bigtable.ChainFilters(familyFilter, qualifierFilter), nil - } - } else { - return nil, fmt.Errorf("bad format for column %q", column) + return bigtable.ColumnFilter(splitColumn[0]) + } + + family, qualifier := splitColumn[0], splitColumn[1] + if family == "" { + return bigtable.ColumnFilter(qualifier) + } + if qualifier == "" { + return bigtable.FamilyFilter(family) } + return bigtable.ChainFilters(bigtable.FamilyFilter(family), bigtable.ColumnFilter(qualifier)) } func parseProfileRoute(str string) (routingPolicy, clusterID string, err error) { diff --git a/cbt_test.go b/cbt_test.go index af99081..7708c16 100644 --- a/cbt_test.go +++ b/cbt_test.go @@ -178,29 +178,21 @@ func TestParseColumnsFilter(t *testing.T) { ), }, { - in: "familyA:columnA:cellA", - fail: true, + in: "familyA:columnA:cellA", + out: bigtable.ChainFilters(bigtable.FamilyFilter("familyA"), bigtable.ColumnFilter("columnA:cellA")), }, { - in: "familyA::columnA", - fail: true, + in: "familyA::columnA", + out: bigtable.ChainFilters(bigtable.FamilyFilter("familyA"), bigtable.ColumnFilter(":columnA")), + }, + { + in: ":", + out: bigtable.ColumnFilter(""), }, } for _, tc := range tests { - got, err := parseColumnsFilter(tc.in) - - if !tc.fail && err != nil { - t.Errorf("parseColumnsFilter(%q) unexpectedly failed: %v", tc.in, err) - continue - } - if tc.fail && err == nil { - t.Errorf("parseColumnsFilter(%q) did not fail", tc.in) - continue - } - if tc.fail { - continue - } + got := parseColumnsFilter(tc.in) var cmpOpts cmp.Options cmpOpts = @@ -482,14 +474,14 @@ func TestPrintRowWithHighTimestamp(t *testing.T) { mut := bigtable.NewMutation() loc, err := time.LoadLocation("US/Pacific") - if (err != nil) { + if err != nil { t.Fatalf("Failed to load timezone: %v", err) } // a timestamp that is just over int64 max in nanoseconds mut.Set("my-family", "foo", 9223372036855000, []byte("bar")) err = tbl.Apply(ctx, "my-key", mut) - if (err != nil) { + if err != nil { t.Fatalf("Could not write some rows to prepare the test.") } row, err := tbl.ReadRow(ctx, "my-key") From 797d12a1ce2d9fc232d110f67ce36652c82e3233 Mon Sep 17 00:00:00 2001 From: Jaeyeol Shin Date: Fri, 2 Jan 2026 23:42:24 +0900 Subject: [PATCH 2/2] remove unused var --- cbt_test.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cbt_test.go b/cbt_test.go index 7708c16..f2142f1 100644 --- a/cbt_test.go +++ b/cbt_test.go @@ -125,9 +125,8 @@ func TestParseArgs(t *testing.T) { func TestParseColumnsFilter(t *testing.T) { tests := []struct { - in string - out bigtable.Filter - fail bool + in string + out bigtable.Filter }{ { in: "columnA",