Google Cloud Bigtable C++ Client  2.4.0
A C++ Client Library for Google Cloud Bigtable
filters.h
Go to the documentation of this file.
1 // Copyright 2017 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_FILTERS_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_FILTERS_H
17 
18 #include "google/cloud/bigtable/version.h"
19 #include "absl/meta/type_traits.h"
20 #include <google/bigtable/v2/data.pb.h>
21 #include <google/protobuf/util/message_differencer.h>
22 #include <chrono>
23 #include <string>
24 
25 namespace google {
26 namespace cloud {
27 namespace bigtable {
29 
30 /**
31  * Define the interfaces to create filter expressions.
32  *
33  * Example:
34  * @code
35  * // Get only data from the "fam" column family, and only the latest value.
36  * auto filter = Filter::Chain(Filter::Family("fam"), Filter::Latest(1));
37  * table->ReadRow("foo", std::move(filter));
38  * @endcode
39  *
40  * Those filters that use regular expressions, expect the patterns to be in
41  * the [RE2](https://github.com/google/re2/wiki/Syntax) syntax.
42  *
43  * @note Special care need be used with the expression used. Some of the
44  * filtered values (column names, row keys, cell values) are byte sequences,
45  * and can contain arbitrary bytes, the `\C` escape sequence must be used
46  * if a true wildcard is desired. The `.` character will not match the new
47  * line character `\n`, because `.` means `[^\n]` in RE2. As new line
48  * characters may be present in a binary value, you may need to explicitly
49  * match it using "\\n". The double escape is necessary because RE2 needs
50  * to get the escape sequence.
51  */
52 class Filter {
53  public:
54  explicit Filter(::google::bigtable::v2::RowFilter rhs)
55  : filter_(std::move(rhs)) {}
56 
57  Filter(Filter&&) = default;
58  Filter& operator=(Filter&&) = default;
59  Filter(Filter const&) = default;
60  Filter& operator=(Filter const&) = default;
61 
62  friend bool operator==(Filter const& a, Filter const& b) noexcept {
63  return google::protobuf::util::MessageDifferencer::Equivalent(a.filter_,
64  b.filter_);
65  }
66  friend bool operator!=(Filter const& a, Filter const& b) noexcept {
67  return !(a == b);
68  }
69 
70  /// Return a filter that passes on all data.
71  static Filter PassAllFilter() {
72  Filter tmp;
73  tmp.filter_.set_pass_all_filter(true);
74  return tmp;
75  }
76 
77  /// Return a filter that blocks all data.
79  Filter tmp;
80  tmp.filter_.set_block_all_filter(true);
81  return tmp;
82  }
83 
84  /**
85  * Return a filter that accepts only the last @p n values of each column.
86  *
87  * The server rejects filters where @p n <= 0, any ReadRows() request
88  * containing such a filter fails with `grpc::StatusCode::INVALID_ARGUMENT`.
89  * This function does not perform any local validation of @p n.
90  */
91  static Filter Latest(std::int32_t n) {
92  Filter result;
93  result.filter_.set_cells_per_column_limit_filter(n);
94  return result;
95  }
96 
97  /**
98  * Return a filter that matches column families matching the given regexp.
99  *
100  * @param pattern the regular expression. It must be a valid
101  * [RE2](https://github.com/google/re2/wiki/Syntax) pattern. For
102  * technical reasons, the regex must not contain the ':' character, even
103  * if it is not being used as a literal. The server rejects filters with
104  * invalid patterns, including patterns containing the ':' character.
105  * The server fails the ReadRows() request with a
106  * `grpc::StatusCode::INVALID_ARGUMENT` status code. This function makes
107  * no attempt to validate the pattern before sending it to the server.
108  */
109  static Filter FamilyRegex(std::string pattern) {
110  Filter tmp;
111  tmp.filter_.set_family_name_regex_filter(std::move(pattern));
112  return tmp;
113  }
114 
115  /**
116  * Return a filter that accepts only columns matching the given regexp.
117  *
118  * @param pattern the regular expression. It must be a valid
119  * [RE2](https://github.com/google/re2/wiki/Syntax) pattern. The server
120  * rejects filters with an invalid pattern with a
121  * `grpc::StatusCode::INVALID_ARGUMENT` status code. This function makes
122  * no attempt to validate the pattern before sending it to the server.
123  *
124  * @note Special care need be used with the expression used. A column name
125  * is a byte sequence, and can contain arbitrary bytes, the `\C` escape
126  * sequence must be used if a true wildcard is desired. The `.` character
127  * will not match the new line character `\n`, because `.` means `[^\n]`
128  * in RE2. As new line characters may be present in a binary value, you
129  * may need to explicitly match it using "\\n". The double escape is
130  * necessary because RE2 needs to get the escape sequence.
131  */
132  static Filter ColumnRegex(std::string pattern) {
133  Filter tmp;
134  tmp.filter_.set_column_qualifier_regex_filter(std::move(pattern));
135  return tmp;
136  }
137 
138  /**
139  * Return a filter that accepts columns in the range [@p start, @p end)
140  * within the @p family column family.
141  *
142  * The column range must be non-empty, i.e., @p start must be strictly
143  * smaller than @p end. The server will reject empty ranges with a
144  * `grpc::StatusCode::INVALID_ARGUMENT` status code. This function makes no
145  * attempt to validate the column family or column range before sending them
146  * to the server.
147  */
148  static Filter ColumnRange(std::string family, std::string start,
149  std::string end) {
150  return ColumnRangeRightOpen(std::move(family), std::move(start),
151  std::move(end));
152  }
153 
154  /**
155  * Return the filter that accepts the named @p column within the @p family
156  * column family.
157  *
158  * This function makes no attempt to validate the column family or column
159  * range before sending them to the server.
160  */
161  static Filter ColumnName(std::string family, std::string column) {
162  std::string end = column;
163  return ColumnRangeClosed(std::move(family), std::move(column),
164  std::move(end));
165  }
166 
167  /**
168  * Return a filter that accepts cells with timestamps in the range
169  * [@p start, @p end).
170  *
171  * The timestamp range must be non-empty, i.e. @p start must be strictly
172  * smaller than @p end. The server will reject empty ranges with a
173  * `grpc::StatusCode::INVALID_ARGUMENT` status code. This function makes no
174  * attempt to validate the timestamp range before sending it to the server.
175  */
176  static Filter TimestampRangeMicros(std::int64_t start, std::int64_t end) {
177  Filter tmp;
178  auto& range = *tmp.filter_.mutable_timestamp_range_filter();
179  range.set_start_timestamp_micros(start);
180  range.set_end_timestamp_micros(end);
181  return tmp;
182  }
183 
184  /**
185  * Return a filter that accepts cells with timestamps in the range
186  * [@p start, @p end).
187  *
188  * The function accepts any instantiation of `std::chrono::duration<>` for the
189  * @p start and @p end parameters. For example:
190  *
191  * @code
192  * using namespace std::chrono_literals; // C++14
193  * auto r1 = bigtable::Filter::TimestampRange(10ms, 500ms);
194  * auto r2 = bigtable::Filter::TimestampRange(10min, 10min + 2s);
195  * @endcode
196  *
197  * The timestamp range must be non-empty, i.e. @p start must be strictly
198  * smaller than @p end. The server will reject empty ranges with a
199  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
200  * attempt to validate the timestamp range before sending it to the server.
201  *
202  * @tparam Rep1 a placeholder to match the Rep tparam for @p start type,
203  * the semantics of this template parameter are documented in
204  * `std::chrono::duration<>` (in brief, the underlying arithmetic type
205  * used to store the number of ticks), for our purposes it is simply a
206  * formal parameter.
207  * @tparam Rep2 similar formal parameter for the type of @p end.
208  * @tparam Period1 a placeholder to match the Period tparam for @p start
209  * type, the semantics of this template parameter are documented in
210  * `std::chrono::duration<>` (in brief, the length of the tick in seconds,
211  * expressed as a `std::ratio<>`), for our purposes it is simply a formal
212  * parameter.
213  * @tparam Period2 similar formal parameter for the type of @p end.
214  *
215  * @see
216  * [std::chrono::duration<>](http://en.cppreference.com/w/cpp/chrono/duration)
217  * for more details.
218  */
219  template <typename Rep1, typename Period1, typename Rep2, typename Period2>
220  static Filter TimestampRange(std::chrono::duration<Rep1, Period1> start,
221  std::chrono::duration<Rep2, Period2> end) {
222  return TimestampRangeMicros(
223  std::chrono::duration_cast<std::chrono::microseconds>(start).count(),
224  std::chrono::duration_cast<std::chrono::microseconds>(end).count());
225  }
226 
227  /**
228  * Return a filter that matches keys matching the given regexp.
229  *
230  * @param pattern the regular expression. It must be a valid RE2 pattern.
231  * More details at https://github.com/google/re2/wiki/Syntax
232  *
233  * @note Special care need be used with the expression used. A row key
234  * is a byte sequence, and can contain arbitrary bytes, the `\C` escape
235  * sequence must be used if a true wildcard is desired. The `.` character
236  * will not match the new line character `\n`, because `.` means `[^\n]`
237  * in RE2. As new line characters may be present in a binary value, you
238  * may need to explicitly match it using "\\n". The double escape is
239  * necessary because RE2 needs to get the escape sequence.
240  */
241  static Filter RowKeysRegex(std::string pattern) {
242  Filter tmp;
243  tmp.filter_.set_row_key_regex_filter(std::move(pattern));
244  return tmp;
245  }
246 
247  /**
248  * Return a filter that matches cells with values matching the given regexp.
249  *
250  * @param pattern the regular expression. It must be a valid
251  * [RE2](https://github.com/google/re2/wiki/Syntax) pattern. The server
252  * rejects filters with an invalid pattern with a
253  * `grpc::StatusCode::INVALID_ARGUMENT` status code. This function makes
254  * no attempt to validate the timestamp range before sending it to
255  * the server.
256  *
257  * @note Special care need be used with the expression used. A cell value
258  * is a byte sequence, and can contain arbitrary bytes, the `\C` escape
259  * sequence must be used if a true wildcard is desired. The `.` character
260  * will not match the new line character `\n`, because `.` means `[^\n]`
261  * in RE2. As new line characters may be present in a binary value, you
262  * may need to explicitly match it using "\\n". The double escape is
263  * necessary because RE2 needs to get the escape sequence.
264  */
265  static Filter ValueRegex(std::string pattern) {
266  Filter tmp;
267  tmp.filter_.set_value_regex_filter(std::move(pattern));
268  return tmp;
269  }
270 
271  /**
272  * Return filter matching values in the range [@p start, @p end).
273  *
274  * @see ValueRangeRightOpen() for more details.
275  */
276  static Filter ValueRange(std::string start, std::string end) {
277  return ValueRangeRightOpen(std::move(start), std::move(end));
278  }
279 
280  /**
281  * Return a filter that only accepts the first @p n cells in a row.
282  *
283  * Note that cells might be repeated, such as when interleaving the results
284  * of multiple filters via the `Interleave()` function. Furthermore, this
285  * filter apples to the cells within a row; if there are multiple column
286  * families and/or columns in a row, the order is:
287  * - All the cells for a column family appear together, but there is no
288  * guarantee on the order of the column families. Furthermore, column
289  * families may appear in different orders in different rows.
290  * - Within a column family, the cells are ordered by column name, where
291  * column names are sorted lexicographically.
292  * - Within a column, the cells appear in descending order by timestamp.
293  *
294  * The server rejects filters where @p n <= 0, any ReadRows() request
295  * containing such a filter fails with `grpc::StatusCode::INVALID_ARGUMENT`.
296  * This function does not perform any local validation of @p n.
297  */
298  static Filter CellsRowLimit(std::int32_t n) {
299  Filter tmp;
300  tmp.filter_.set_cells_per_row_limit_filter(n);
301  return tmp;
302  }
303 
304  /**
305  * Return a filter that skips the first @p n cells in a row.
306  *
307  * Note that cells might be repeated, such as when interleaving the results
308  * of multiple filters via the `Interleave()` function. Furthermore, this
309  * filter apples to the cells within a row; if there are multiple column
310  * families and/or columns in a row, the order is:
311  * - All the cells for a column family appear together, but there is no
312  * guarantee on the order of the column families. Furthermore, column
313  * families may appear in different orders in different rows.
314  * - Within a column family, the cells are ordered by column name, where
315  * column names are sorted lexicographically.
316  * - Within a column, the cells appear in descending order by timestamp.
317  *
318  * The server rejects filters where @p n <= 0, any ReadRows() request
319  * containing such a filter fails with `grpc::StatusCode::INVALID_ARGUMENT`.
320  * This function does not perform any local validation of @p n.
321  */
322  static Filter CellsRowOffset(std::int32_t n) {
323  Filter tmp;
324  tmp.filter_.set_cells_per_row_offset_filter(n);
325  return tmp;
326  }
327 
328  /**
329  * Return a filter that samples rows with a given probability.
330  *
331  * The server rejects filters where @p probability is outside the range
332  * (0.0, 1.0). Any ReadRows() request containing such a filter fails with
333  * `grpc::StatusCode::INVALID_ARGUMENT`. This function does not perform any
334  * local validation of @p probability.
335  *
336  * @param probability the probability that any row will be selected. It
337  * must be in the range (0.0, 1.0).
338  */
339  static Filter RowSample(double probability) {
340  Filter tmp;
341  tmp.filter_.set_row_sample_filter(probability);
342  return tmp;
343  }
344 
345  //@{
346  /**
347  * @name Less common range filters.
348  *
349  * Cloud Bigtable range filters can include or exclude the limits of the
350  * range. In most cases applications use [@p start, @p end) ranges, and the
351  * ValueRange() and ColumnRange() functions are offered to support the
352  * common case. For the less common cases where the application needs
353  * different ranges, the following functions are available.
354  */
355  /**
356  * Return a filter that accepts values in the range [@p start, @p end).
357  *
358  * The range must be non-empty. The server will reject empty ranges with a
359  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
360  * attempt to validate the timestamp range before sending it to the server.
361  */
362  static Filter ValueRangeLeftOpen(std::string start, std::string end) {
363  Filter tmp;
364  auto& range = *tmp.filter_.mutable_value_range_filter();
365  range.set_start_value_open(std::move(start));
366  range.set_end_value_closed(std::move(end));
367  return tmp;
368  }
369 
370  /**
371  * Return a filter that accepts values in the range [@p start, @p end].
372  *
373  * The range must be non-empty. The server will reject empty ranges with a
374  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
375  * attempt to validate the timestamp range before sending it to the server.
376  */
377  static Filter ValueRangeRightOpen(std::string start, std::string end) {
378  Filter tmp;
379  auto& range = *tmp.filter_.mutable_value_range_filter();
380  range.set_start_value_closed(std::move(start));
381  range.set_end_value_open(std::move(end));
382  return tmp;
383  }
384 
385  /**
386  * Return a filter that accepts values in the range [@p start, @p end].
387  *
388  * The range must be non-empty. The server will reject empty ranges with a
389  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
390  * attempt to validate the timestamp range before sending it to the server.
391  */
392  static Filter ValueRangeClosed(std::string start, std::string end) {
393  Filter tmp;
394  auto& range = *tmp.filter_.mutable_value_range_filter();
395  range.set_start_value_closed(std::move(start));
396  range.set_end_value_closed(std::move(end));
397  return tmp;
398  }
399 
400  /**
401  * Return a filter that accepts values in the range (@p start, @p end).
402  *
403  * The range must be non-empty. The server will reject empty ranges with a
404  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
405  * attempt to validate the timestamp range before sending it to the server.
406  */
407  static Filter ValueRangeOpen(std::string start, std::string end) {
408  Filter tmp;
409  auto& range = *tmp.filter_.mutable_value_range_filter();
410  range.set_start_value_open(std::move(start));
411  range.set_end_value_open(std::move(end));
412  return tmp;
413  }
414 
415  /**
416  * Return a filter that accepts columns in the range [@p start, @p end)
417  * within the @p column_family.
418  *
419  * The range must be non-empty. The server will reject empty ranges with a
420  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
421  * attempt to validate the timestamp range before sending it to the server.
422  */
423  static Filter ColumnRangeRightOpen(std::string column_family,
424  std::string start, std::string end) {
425  Filter tmp;
426  auto& range = *tmp.filter_.mutable_column_range_filter();
427  range.set_family_name(std::move(column_family));
428  range.set_start_qualifier_closed(std::move(start));
429  range.set_end_qualifier_open(std::move(end));
430  return tmp;
431  }
432 
433  /**
434  * Return a filter that accepts columns in the range (@p start, @p end]
435  * within the @p column_family.
436  *
437  * The range must be non-empty. The server will reject empty ranges with a
438  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
439  * attempt to validate the timestamp range before sending it to the server.
440  */
441  static Filter ColumnRangeLeftOpen(std::string column_family,
442  std::string start, std::string end) {
443  Filter tmp;
444  auto& range = *tmp.filter_.mutable_column_range_filter();
445  range.set_family_name(std::move(column_family));
446  range.set_start_qualifier_open(std::move(start));
447  range.set_end_qualifier_closed(std::move(end));
448  return tmp;
449  }
450 
451  /**
452  * Return a filter that accepts columns in the range [@p start, @p end]
453  * within the @p column_family.
454  *
455  * The range must be non-empty. The server will reject empty ranges with a
456  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
457  * attempt to validate the timestamp range before sending it to the server.
458  */
459  static Filter ColumnRangeClosed(std::string column_family, std::string start,
460  std::string end) {
461  Filter tmp;
462  auto& range = *tmp.filter_.mutable_column_range_filter();
463  range.set_family_name(std::move(column_family));
464  range.set_start_qualifier_closed(std::move(start));
465  range.set_end_qualifier_closed(std::move(end));
466  return tmp;
467  }
468 
469  /**
470  * Return a filter that accepts columns in the range (@p start, @p end)
471  * within the @p column_family.
472  *
473  * The range must be non-empty. The server will reject empty ranges with a
474  * `grpc::StatusCode::INVALID_ARGUMENT` error. This function makes no
475  * attempt to validate the timestamp range before sending it to the server.
476  */
477  static Filter ColumnRangeOpen(std::string column_family, std::string start,
478  std::string end) {
479  Filter tmp;
480  auto& range = *tmp.filter_.mutable_column_range_filter();
481  range.set_family_name(std::move(column_family));
482  range.set_start_qualifier_open(std::move(start));
483  range.set_end_qualifier_open(std::move(end));
484  return tmp;
485  }
486  //@}
487 
488  /**
489  * Return a filter that transforms any values into the empty string.
490  *
491  * As the name indicates, this acts as a transformer on the data, replacing
492  * any values with the empty string.
493  */
495  Filter tmp;
496  tmp.filter_.set_strip_value_transformer(true);
497  return tmp;
498  }
499 
500  /**
501  * Returns a filter that applies a label to each value.
502  *
503  * Each value accepted by previous filters in modified to include the @p
504  * label.
505  *
506  * @note Currently, it is not possible to apply more than one label in a
507  * filter expression, that is, a chain can only contain a single
508  * ApplyLabelTransformer() filter. This limitation may be lifted in
509  * the future. It is possible to have multiple ApplyLabelTransformer
510  * filters in a Union() filter, though in this case, each copy of a cell
511  * gets a different label.
512  *
513  * @param label the label applied to each cell. The labels must be at most 15
514  * characters long, and must match the `[a-z0-9\\-]+` pattern. The server
515  * validates the filter and will return a
516  * `grpc::StatusCode::INVALID_ARGUMENT` if the label does not meet these
517  * requirements. This function makes no attempt to validate the @p label
518  * parameter before sending it to the server.
519  */
520  static Filter ApplyLabelTransformer(std::string label) {
521  Filter tmp;
522  tmp.filter_.set_apply_label_transformer(std::move(label));
523  return tmp;
524  }
525  //@}
526 
527  //@{
528  /**
529  * @name Compound filters.
530  *
531  * These filters compose several filters to build complex filter expressions.
532  */
533  /**
534  * Returns a per-row conditional filter expression.
535  *
536  * For each row the @p predicate filter is evaluated, if it returns any
537  * cells, then the cells returned by @p true_filter are returned, otherwise
538  * the cells from @p false_filter are returned.
539  *
540  * The server validates the tree of filters, and rejects them if any contain
541  * invalid values. The server may impose additional restrictions on the
542  * resulting collection of filters. This function makes no attempt to
543  * validate the input before sending it to the server.
544  */
545  static Filter Condition(Filter predicate, Filter true_filter,
546  Filter false_filter) {
547  Filter tmp;
548  auto& condition = *tmp.filter_.mutable_condition();
549  condition.mutable_predicate_filter()->Swap(&predicate.filter_);
550  condition.mutable_true_filter()->Swap(&true_filter.filter_);
551  condition.mutable_false_filter()->Swap(&false_filter.filter_);
552  return tmp;
553  }
554 
555  /**
556  * Return a chain filter.
557  *
558  * The filter returned by this function acts like a pipeline. The output
559  * row from each stage is passed on as input for the next stage.
560  *
561  * @tparam FilterTypes the type of the filter arguments. They must all be
562  * convertible to Filter.
563  * @param stages the filter stages. The filter must contain at least two
564  * stages. The server validates each stage, and will reject them as
565  * described in their corresponding function. The server may also impose
566  * additional restrictions on the composition of the Chain. This function
567  * makes no attempt at validating the stages locally, the Chain filter is
568  * sent as-is it to the server.
569  */
570  template <typename... FilterTypes>
571  static Filter Chain(FilterTypes&&... stages) {
572  // This ugly thing provides a better compile-time error message than
573  // just letting the compiler figure things out 3 levels deep
574  // as it recurses on append_types().
575  static_assert(
576  absl::conjunction<std::is_convertible<FilterTypes, Filter>...>::value,
577  "The arguments passed to Chain(...) must be convertible to Filter");
578  Filter tmp;
579  auto& chain = *tmp.filter_.mutable_chain();
580  std::initializer_list<Filter> list{std::forward<FilterTypes>(stages)...};
581  for (Filter const& f : list) {
582  *chain.add_filters() = f.as_proto();
583  }
584  return tmp;
585  }
586 
587  /**
588  * Return a chain filter.
589  *
590  * The filter returned by this function acts like a pipeline. The output
591  * row from each stage is passed on as input for the next stage.
592  *
593  * @tparam Iterator an InputIterator whose `value_type` is `Filter`.
594  * @param begin the start of the range.
595  * @param end the end of the range.
596  */
597  template <typename Iterator>
598  static Filter ChainFromRange(Iterator begin, Iterator end) {
599  static_assert(
600  std::is_convertible<typename std::iterator_traits<Iterator>::value_type,
601  Filter>::value,
602  "The value type of the Iterator arguments passed to"
603  " InterleaveFromRange(...) must be convertible to Filter");
604  Filter tmp;
605  auto& chain = *tmp.filter_.mutable_chain();
606  for (auto it = begin; it != end; ++it) {
607  *chain.add_filters() = it->as_proto();
608  }
609  return tmp;
610  }
611 
612  /**
613  * Return a filter that interleaves the results of many other filters.
614  *
615  * This filter executes each stream in parallel and then merges the results by
616  * interleaving the output from each stream. The
617  * [proto
618  * file](https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/data.proto)
619  * has a nice illustration in the documentation of
620  * `google.bigtable.v2.RowFilter.Interleave`.
621  *
622  * In brief, if the input cells are c1, c2, c3, ..., and you have three
623  * subfilters S1, S2, and S3, the output of Interleave(S1, S2, S3) is:
624  * S1(c1), S2(c1), S3(c1), S1(d2), S2(d2), S3(c2), S1(c3), S2(c3), S3(c2), ...
625  * where some of the Si(c_j) values may be empty if the filter discards the
626  * cell altogether.
627  *
628  * @tparam FilterTypes the type of the filter arguments. They must all be
629  * convertible for Filter.
630  * @param streams the filters to interleave. The filter must contain at least
631  * two streams. The server validates each stream, and will reject them as
632  * described in their corresponding function. The server may also impose
633  * additional restrictions on the overall composition of the Interleave
634  * filter. This function makes no attempt at validating the streams
635  * locally, the Interleave filter is sent as-is to the server.
636  */
637  template <typename... FilterTypes>
638  static Filter Interleave(FilterTypes&&... streams) {
639  static_assert(
640  absl::conjunction<std::is_convertible<FilterTypes, Filter>...>::value,
641  "The arguments passed to Interleave(...) must be convertible"
642  " to Filter");
643  Filter tmp;
644  auto& interleave = *tmp.filter_.mutable_interleave();
645  std::initializer_list<Filter> list{std::forward<FilterTypes>(streams)...};
646  for (Filter const& f : list) {
647  *interleave.add_filters() = f.as_proto();
648  }
649  return tmp;
650  }
651 
652  /**
653  * Return a filter that interleaves the results of a range of filters.
654  *
655  * Similar to #Interleave(), except this function accepts a pair of
656  * Iterators.
657  *
658  * @param begin the begin iterator of the range.
659  * @param end the end iterator of the range.
660  */
661  template <typename Iterator>
662  static Filter InterleaveFromRange(Iterator begin, Iterator end) {
663  static_assert(
664  std::is_convertible<typename std::iterator_traits<Iterator>::value_type,
665  Filter>::value,
666  "The value type of the Iterator arguments passed to"
667  " InterleaveFromRange(...) must be convertible to Filter");
668  Filter tmp;
669  auto& interleave = *tmp.filter_.mutable_interleave();
670  for (auto it = begin; it != end; ++it) {
671  *interleave.add_filters() = it->as_proto();
672  }
673  return tmp;
674  }
675 
676  /**
677  * Return a filter that outputs all cells ignoring intermediate filters.
678  *
679  * Please read the documentation in the
680  * [proto
681  * file](https://github.com/googleapis/googleapis/blob/master/google/bigtable/v2/data.proto)
682  * for a detailed description. In short, this is an advanced filter to
683  * facilitate debugging. You can explore the intermediate results of a
684  * complex filter expression by injecting a filter of this type.
685  */
686  static Filter Sink() {
687  Filter tmp;
688  tmp.filter_.set_sink(true);
689  return tmp;
690  }
691  //@}
692 
693  /// Return the filter expression as a protobuf.
694  ::google::bigtable::v2::RowFilter const& as_proto() const& { return filter_; }
695 
696  /// Move out the underlying protobuf value.
697  ::google::bigtable::v2::RowFilter&& as_proto() && {
698  return std::move(filter_);
699  }
700 
701  private:
702  /// An empty filter, discards all data.
703  Filter() = default;
704 
705  google::bigtable::v2::RowFilter filter_;
706 };
707 
709 } // namespace bigtable
710 } // namespace cloud
711 } // namespace google
712 
713 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_BIGTABLE_FILTERS_H