| /* | 
 | Copyright 2015 Google LLC | 
 |  | 
 | Licensed under the Apache License, Version 2.0 (the "License"); | 
 | you may not use this file except in compliance with the License. | 
 | You may obtain a copy of the License at | 
 |  | 
 |     http://www.apache.org/licenses/LICENSE-2.0 | 
 |  | 
 | Unless required by applicable law or agreed to in writing, software | 
 | distributed under the License is distributed on an "AS IS" BASIS, | 
 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | See the License for the specific language governing permissions and | 
 | limitations under the License. | 
 | */ | 
 |  | 
 | package bigtable | 
 |  | 
 | import ( | 
 | 	"fmt" | 
 | 	"strings" | 
 | 	"time" | 
 |  | 
 | 	btpb "google.golang.org/genproto/googleapis/bigtable/v2" | 
 | ) | 
 |  | 
 | // A Filter represents a row filter. | 
 | type Filter interface { | 
 | 	String() string | 
 | 	proto() *btpb.RowFilter | 
 | } | 
 |  | 
 | // ChainFilters returns a filter that applies a sequence of filters. | 
 | func ChainFilters(sub ...Filter) Filter { return chainFilter{sub} } | 
 |  | 
 | type chainFilter struct { | 
 | 	sub []Filter | 
 | } | 
 |  | 
 | func (cf chainFilter) String() string { | 
 | 	var ss []string | 
 | 	for _, sf := range cf.sub { | 
 | 		ss = append(ss, sf.String()) | 
 | 	} | 
 | 	return "(" + strings.Join(ss, " | ") + ")" | 
 | } | 
 |  | 
 | func (cf chainFilter) proto() *btpb.RowFilter { | 
 | 	chain := &btpb.RowFilter_Chain{} | 
 | 	for _, sf := range cf.sub { | 
 | 		chain.Filters = append(chain.Filters, sf.proto()) | 
 | 	} | 
 | 	return &btpb.RowFilter{ | 
 | 		Filter: &btpb.RowFilter_Chain_{Chain: chain}, | 
 | 	} | 
 | } | 
 |  | 
 | // InterleaveFilters returns a filter that applies a set of filters in parallel | 
 | // and interleaves the results. | 
 | func InterleaveFilters(sub ...Filter) Filter { return interleaveFilter{sub} } | 
 |  | 
 | type interleaveFilter struct { | 
 | 	sub []Filter | 
 | } | 
 |  | 
 | func (ilf interleaveFilter) String() string { | 
 | 	var ss []string | 
 | 	for _, sf := range ilf.sub { | 
 | 		ss = append(ss, sf.String()) | 
 | 	} | 
 | 	return "(" + strings.Join(ss, " + ") + ")" | 
 | } | 
 |  | 
 | func (ilf interleaveFilter) proto() *btpb.RowFilter { | 
 | 	inter := &btpb.RowFilter_Interleave{} | 
 | 	for _, sf := range ilf.sub { | 
 | 		inter.Filters = append(inter.Filters, sf.proto()) | 
 | 	} | 
 | 	return &btpb.RowFilter{ | 
 | 		Filter: &btpb.RowFilter_Interleave_{Interleave: inter}, | 
 | 	} | 
 | } | 
 |  | 
 | // RowKeyFilter returns a filter that matches cells from rows whose | 
 | // key matches the provided RE2 pattern. | 
 | // See https://github.com/google/re2/wiki/Syntax for the accepted syntax. | 
 | func RowKeyFilter(pattern string) Filter { return rowKeyFilter(pattern) } | 
 |  | 
 | type rowKeyFilter string | 
 |  | 
 | func (rkf rowKeyFilter) String() string { return fmt.Sprintf("row(%s)", string(rkf)) } | 
 |  | 
 | func (rkf rowKeyFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_RowKeyRegexFilter{RowKeyRegexFilter: []byte(rkf)}} | 
 | } | 
 |  | 
 | // FamilyFilter returns a filter that matches cells whose family name | 
 | // matches the provided RE2 pattern. | 
 | // See https://github.com/google/re2/wiki/Syntax for the accepted syntax. | 
 | func FamilyFilter(pattern string) Filter { return familyFilter(pattern) } | 
 |  | 
 | type familyFilter string | 
 |  | 
 | func (ff familyFilter) String() string { return fmt.Sprintf("col(%s:)", string(ff)) } | 
 |  | 
 | func (ff familyFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_FamilyNameRegexFilter{FamilyNameRegexFilter: string(ff)}} | 
 | } | 
 |  | 
 | // ColumnFilter returns a filter that matches cells whose column name | 
 | // matches the provided RE2 pattern. | 
 | // See https://github.com/google/re2/wiki/Syntax for the accepted syntax. | 
 | func ColumnFilter(pattern string) Filter { return columnFilter(pattern) } | 
 |  | 
 | type columnFilter string | 
 |  | 
 | func (cf columnFilter) String() string { return fmt.Sprintf("col(.*:%s)", string(cf)) } | 
 |  | 
 | func (cf columnFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_ColumnQualifierRegexFilter{ColumnQualifierRegexFilter: []byte(cf)}} | 
 | } | 
 |  | 
 | // ValueFilter returns a filter that matches cells whose value | 
 | // matches the provided RE2 pattern. | 
 | // See https://github.com/google/re2/wiki/Syntax for the accepted syntax. | 
 | func ValueFilter(pattern string) Filter { return valueFilter(pattern) } | 
 |  | 
 | type valueFilter string | 
 |  | 
 | func (vf valueFilter) String() string { return fmt.Sprintf("value_match(%s)", string(vf)) } | 
 |  | 
 | func (vf valueFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_ValueRegexFilter{ValueRegexFilter: []byte(vf)}} | 
 | } | 
 |  | 
 | // LatestNFilter returns a filter that matches the most recent N cells in each column. | 
 | func LatestNFilter(n int) Filter { return latestNFilter(n) } | 
 |  | 
 | type latestNFilter int32 | 
 |  | 
 | func (lnf latestNFilter) String() string { return fmt.Sprintf("col(*,%d)", lnf) } | 
 |  | 
 | func (lnf latestNFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerColumnLimitFilter{CellsPerColumnLimitFilter: int32(lnf)}} | 
 | } | 
 |  | 
 | // LabelFilter returns a filter that applies the | 
 | // given label to all cells in the output row. | 
 | func LabelFilter(label string) Filter { return labelFilter(label) } | 
 |  | 
 | type labelFilter string | 
 |  | 
 | func (lf labelFilter) String() string { return fmt.Sprintf("apply_label(%s)", string(lf)) } | 
 |  | 
 | func (lf labelFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_ApplyLabelTransformer{ApplyLabelTransformer: string(lf)}} | 
 | } | 
 |  | 
 | // StripValueFilter returns a filter that replaces each value with the empty string. | 
 | func StripValueFilter() Filter { return stripValueFilter{} } | 
 |  | 
 | type stripValueFilter struct{} | 
 |  | 
 | func (stripValueFilter) String() string { return "strip_value()" } | 
 | func (stripValueFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_StripValueTransformer{StripValueTransformer: true}} | 
 | } | 
 |  | 
 | // TimestampRangeFilter returns a filter that matches any cells whose timestamp is within the given time bounds.  A zero | 
 | // time means no bound. | 
 | // The timestamp will be truncated to millisecond granularity. | 
 | func TimestampRangeFilter(startTime time.Time, endTime time.Time) Filter { | 
 | 	trf := timestampRangeFilter{} | 
 | 	if !startTime.IsZero() { | 
 | 		trf.startTime = Time(startTime) | 
 | 	} | 
 | 	if !endTime.IsZero() { | 
 | 		trf.endTime = Time(endTime) | 
 | 	} | 
 | 	return trf | 
 | } | 
 |  | 
 | // TimestampRangeFilterMicros returns a filter that matches any cells whose timestamp is within the given time bounds, | 
 | // specified in units of microseconds since 1 January 1970. A zero value for the end time is interpreted as no bound. | 
 | // The timestamp will be truncated to millisecond granularity. | 
 | func TimestampRangeFilterMicros(startTime Timestamp, endTime Timestamp) Filter { | 
 | 	return timestampRangeFilter{startTime, endTime} | 
 | } | 
 |  | 
 | type timestampRangeFilter struct { | 
 | 	startTime Timestamp | 
 | 	endTime   Timestamp | 
 | } | 
 |  | 
 | func (trf timestampRangeFilter) String() string { | 
 | 	return fmt.Sprintf("timestamp_range(%v,%v)", trf.startTime, trf.endTime) | 
 | } | 
 |  | 
 | func (trf timestampRangeFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{ | 
 | 		Filter: &btpb.RowFilter_TimestampRangeFilter{TimestampRangeFilter: &btpb.TimestampRange{ | 
 | 			StartTimestampMicros: int64(trf.startTime.TruncateToMilliseconds()), | 
 | 			EndTimestampMicros:   int64(trf.endTime.TruncateToMilliseconds()), | 
 | 		}, | 
 | 		}} | 
 | } | 
 |  | 
 | // ColumnRangeFilter returns a filter that matches a contiguous range of columns within a single | 
 | // family, as specified by an inclusive start qualifier and exclusive end qualifier. | 
 | func ColumnRangeFilter(family, start, end string) Filter { | 
 | 	return columnRangeFilter{family, start, end} | 
 | } | 
 |  | 
 | type columnRangeFilter struct { | 
 | 	family string | 
 | 	start  string | 
 | 	end    string | 
 | } | 
 |  | 
 | func (crf columnRangeFilter) String() string { | 
 | 	return fmt.Sprintf("columnRangeFilter(%s,%s,%s)", crf.family, crf.start, crf.end) | 
 | } | 
 |  | 
 | func (crf columnRangeFilter) proto() *btpb.RowFilter { | 
 | 	r := &btpb.ColumnRange{FamilyName: crf.family} | 
 | 	if crf.start != "" { | 
 | 		r.StartQualifier = &btpb.ColumnRange_StartQualifierClosed{StartQualifierClosed: []byte(crf.start)} | 
 | 	} | 
 | 	if crf.end != "" { | 
 | 		r.EndQualifier = &btpb.ColumnRange_EndQualifierOpen{EndQualifierOpen: []byte(crf.end)} | 
 | 	} | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_ColumnRangeFilter{ColumnRangeFilter: r}} | 
 | } | 
 |  | 
 | // ValueRangeFilter returns a filter that matches cells with values that fall within | 
 | // the given range, as specified by an inclusive start value and exclusive end value. | 
 | func ValueRangeFilter(start, end []byte) Filter { | 
 | 	return valueRangeFilter{start, end} | 
 | } | 
 |  | 
 | type valueRangeFilter struct { | 
 | 	start []byte | 
 | 	end   []byte | 
 | } | 
 |  | 
 | func (vrf valueRangeFilter) String() string { | 
 | 	return fmt.Sprintf("valueRangeFilter(%s,%s)", vrf.start, vrf.end) | 
 | } | 
 |  | 
 | func (vrf valueRangeFilter) proto() *btpb.RowFilter { | 
 | 	r := &btpb.ValueRange{} | 
 | 	if vrf.start != nil { | 
 | 		r.StartValue = &btpb.ValueRange_StartValueClosed{StartValueClosed: vrf.start} | 
 | 	} | 
 | 	if vrf.end != nil { | 
 | 		r.EndValue = &btpb.ValueRange_EndValueOpen{EndValueOpen: vrf.end} | 
 | 	} | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_ValueRangeFilter{ValueRangeFilter: r}} | 
 | } | 
 |  | 
 | // ConditionFilter returns a filter that evaluates to one of two possible filters depending | 
 | // on whether or not the given predicate filter matches at least one cell. | 
 | // If the matched filter is nil then no results will be returned. | 
 | // IMPORTANT NOTE: The predicate filter does not execute atomically with the | 
 | // true and false filters, which may lead to inconsistent or unexpected | 
 | // results. Additionally, condition filters have poor performance, especially | 
 | // when filters are set for the false condition. | 
 | func ConditionFilter(predicateFilter, trueFilter, falseFilter Filter) Filter { | 
 | 	return conditionFilter{predicateFilter, trueFilter, falseFilter} | 
 | } | 
 |  | 
 | type conditionFilter struct { | 
 | 	predicateFilter Filter | 
 | 	trueFilter      Filter | 
 | 	falseFilter     Filter | 
 | } | 
 |  | 
 | func (cf conditionFilter) String() string { | 
 | 	return fmt.Sprintf("conditionFilter(%s,%s,%s)", cf.predicateFilter, cf.trueFilter, cf.falseFilter) | 
 | } | 
 |  | 
 | func (cf conditionFilter) proto() *btpb.RowFilter { | 
 | 	var tf *btpb.RowFilter | 
 | 	var ff *btpb.RowFilter | 
 | 	if cf.trueFilter != nil { | 
 | 		tf = cf.trueFilter.proto() | 
 | 	} | 
 | 	if cf.falseFilter != nil { | 
 | 		ff = cf.falseFilter.proto() | 
 | 	} | 
 | 	return &btpb.RowFilter{ | 
 | 		Filter: &btpb.RowFilter_Condition_{Condition: &btpb.RowFilter_Condition{ | 
 | 			PredicateFilter: cf.predicateFilter.proto(), | 
 | 			TrueFilter:      tf, | 
 | 			FalseFilter:     ff, | 
 | 		}}} | 
 | } | 
 |  | 
 | // CellsPerRowOffsetFilter returns a filter that skips the first N cells of each row, matching all subsequent cells. | 
 | func CellsPerRowOffsetFilter(n int) Filter { | 
 | 	return cellsPerRowOffsetFilter(n) | 
 | } | 
 |  | 
 | type cellsPerRowOffsetFilter int32 | 
 |  | 
 | func (cof cellsPerRowOffsetFilter) String() string { | 
 | 	return fmt.Sprintf("cells_per_row_offset(%d)", cof) | 
 | } | 
 |  | 
 | func (cof cellsPerRowOffsetFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowOffsetFilter{CellsPerRowOffsetFilter: int32(cof)}} | 
 | } | 
 |  | 
 | // CellsPerRowLimitFilter returns a filter that matches only the first N cells of each row. | 
 | func CellsPerRowLimitFilter(n int) Filter { | 
 | 	return cellsPerRowLimitFilter(n) | 
 | } | 
 |  | 
 | type cellsPerRowLimitFilter int32 | 
 |  | 
 | func (clf cellsPerRowLimitFilter) String() string { | 
 | 	return fmt.Sprintf("cells_per_row_limit(%d)", clf) | 
 | } | 
 |  | 
 | func (clf cellsPerRowLimitFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_CellsPerRowLimitFilter{CellsPerRowLimitFilter: int32(clf)}} | 
 | } | 
 |  | 
 | // RowSampleFilter returns a filter that matches a row with a probability of p (must be in the interval (0, 1)). | 
 | func RowSampleFilter(p float64) Filter { | 
 | 	return rowSampleFilter(p) | 
 | } | 
 |  | 
 | type rowSampleFilter float64 | 
 |  | 
 | func (rsf rowSampleFilter) String() string { | 
 | 	return fmt.Sprintf("filter(%f)", rsf) | 
 | } | 
 |  | 
 | func (rsf rowSampleFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_RowSampleFilter{RowSampleFilter: float64(rsf)}} | 
 | } | 
 |  | 
 | // PassAllFilter returns a filter that matches everything. | 
 | func PassAllFilter() Filter { return passAllFilter{} } | 
 |  | 
 | type passAllFilter struct{} | 
 |  | 
 | func (paf passAllFilter) String() string { return "passAllFilter()" } | 
 |  | 
 | func (paf passAllFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_PassAllFilter{PassAllFilter: true}} | 
 | } | 
 |  | 
 | // BlockAllFilter returns a filter that matches nothing. | 
 | func BlockAllFilter() Filter { return blockAllFilter{} } | 
 |  | 
 | type blockAllFilter struct{} | 
 |  | 
 | func (baf blockAllFilter) String() string { return "blockAllFilter()" } | 
 |  | 
 | func (baf blockAllFilter) proto() *btpb.RowFilter { | 
 | 	return &btpb.RowFilter{Filter: &btpb.RowFilter_BlockAllFilter{BlockAllFilter: true}} | 
 | } |