Google Cloud Spanner C++ Client  1.32.0
A C++ Client Library for Google Cloud Spanner
row.h
Go to the documentation of this file.
1 // Copyright 2019 Google LLC
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 // http://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_SPANNER_ROW_H
16 #define GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_ROW_H
17 
18 #include "google/cloud/spanner/internal/tuple_utils.h"
19 #include "google/cloud/spanner/value.h"
20 #include "google/cloud/spanner/version.h"
21 #include "google/cloud/status.h"
22 #include "google/cloud/status_or.h"
23 #include <functional>
24 #include <iterator>
25 #include <memory>
26 #include <string>
27 #include <tuple>
28 #include <type_traits>
29 #include <utility>
30 #include <vector>
31 
32 namespace google {
33 namespace cloud {
34 namespace spanner {
35 inline namespace SPANNER_CLIENT_NS {
36 class Row;
37 } // namespace SPANNER_CLIENT_NS
38 } // namespace spanner
39 
40 namespace spanner_internal {
41 inline namespace SPANNER_CLIENT_NS {
42 spanner::Row MakeRow(std::vector<spanner::Value>,
43  std::shared_ptr<std::vector<std::string> const>);
44 } // namespace SPANNER_CLIENT_NS
45 } // namespace spanner_internal
46 
47 namespace spanner {
48 inline namespace SPANNER_CLIENT_NS {
49 
50 /**
51  * A `Row` is a sequence of columns each with a name and an associated `Value`.
52  *
53  * The `Row` class is a regular value type that may be copied, moved, assigned,
54  * compared for equality, etc. Instances may be large if they hold lots of
55  * `Value` data, so copy only when necessary.
56  *
57  * `Row` instances are typically returned as the result of queries or reads of
58  * a Cloud Spanner table (see `Client::Read` and `Client::ExecuteQuery`). Users
59  * will mostly just use the accessor methods on `Row, and will rarely (if ever)
60  * need to construct a `Row` of their own.
61  *
62  * The number of columns in a `Row` can be obtained from the `size()` member
63  * function. The `Value`s can be obtained using the `values()` accessor. The
64  * names of each column in the row can be obtained using the `columns()`
65  * accessor.
66  *
67  * Perhaps the most convenient way to access the `Values` in a row is through
68  * the variety of "get" accessors. A user may access a column's `Value' by
69  * calling `get` with a `std::size_t` 0-indexed position, or a `std::string`
70  * column name. Furthermore, callers may directly extract the native C++ type
71  * by specifying the C++ type along with the column's position or name.
72  *
73  * @par Example
74  *
75  * @code
76  * Row row = ...;
77  * if (StatusOr<std::string> x = row.get<std::string>("LastName")) {
78  * std::cout << "LastName=" << *x << "\n";
79  * }
80  * @endcode
81  *
82  * @note There is a helper function defined below named `MakeTestRow()` to make
83  * creating `Row` instances for testing easier.
84  */
85 class Row {
86  public:
87  /// Default constructs an empty row with no columns nor values.
88  Row();
89 
90  /// @name Copy and move.
91  ///@{
92  Row(Row const&) = default;
93  Row& operator=(Row const&) = default;
94  Row(Row&&) = default;
95  Row& operator=(Row&&) = default;
96  ///@}
97 
98  /// Returns the number of columns in the row.
99  std::size_t size() const { return columns_->size(); }
100 
101  /// Returns the column names for the row.
102  std::vector<std::string> const& columns() const { return *columns_; }
103 
104  /// Returns the `Value` objects in the given row.
105  std::vector<Value> const& values() const& { return values_; }
106 
107  /// Returns the `Value` objects in the given row.
108  std::vector<Value>&& values() && { return std::move(values_); }
109 
110  /// Returns the `Value` at the given @p pos.
111  StatusOr<Value> get(std::size_t pos) const;
112 
113  /// Returns the `Value` in the column with @p name
114  StatusOr<Value> get(std::string const& name) const;
115 
116  /**
117  * Returns the native C++ value at the given position or column name.
118  *
119  * @tparam T the native C++ type, e.g., std::int64_t or std::string
120  * @tparam Arg a deduced parameter convertible to a std::size_t or std::string
121  */
122  template <typename T, typename Arg>
123  StatusOr<T> get(Arg&& arg) const {
124  auto v = get(std::forward<Arg>(arg));
125  if (v) return v->template get<T>();
126  return v.status();
127  }
128 
129  /**
130  * Returns all the native C++ values for the whole row in a `std::tuple` with
131  * the specified type.
132  *
133  * @tparam Tuple the `std::tuple` type that the whole row must unpack into.
134  */
135  template <typename Tuple>
136  StatusOr<Tuple> get() const& {
137  if (size() != std::tuple_size<Tuple>::value) {
138  auto constexpr kMsg = "Tuple has the wrong number of elements";
140  }
141  Tuple tup;
142  auto it = values_.begin();
143  Status status;
144  spanner_internal::ForEach(tup, ExtractValue{status}, it);
145  if (!status.ok()) return status;
146  return tup;
147  }
148 
149  /**
150  * Returns all the native C++ values for the whole row in a `std::tuple` with
151  * the specified type.
152  *
153  * @tparam Tuple the `std::tuple` type that the whole row must unpack into.
154  */
155  template <typename Tuple>
156  StatusOr<Tuple> get() && {
157  if (size() != std::tuple_size<Tuple>::value) {
158  auto constexpr kMsg = "Tuple has the wrong number of elements";
160  }
161  Tuple tup;
162  auto it = std::make_move_iterator(values_.begin());
163  Status status;
164  spanner_internal::ForEach(tup, ExtractValue{status}, it);
165  if (!status.ok()) return status;
166  return tup;
167  }
168 
169  /// @name Equality
170  ///@{
171  friend bool operator==(Row const& a, Row const& b);
172  friend bool operator!=(Row const& a, Row const& b) { return !(a == b); }
173  ///@}
174 
175  private:
176  friend Row spanner_internal::SPANNER_CLIENT_NS::MakeRow(
177  std::vector<spanner::Value>,
178  std::shared_ptr<std::vector<std::string> const>);
179  struct ExtractValue {
180  Status& status;
181  template <typename T, typename It>
182  void operator()(T& t, It& it) const {
183  auto x = it++->template get<T>();
184  if (!x) {
185  status = std::move(x).status();
186  } else {
187  t = *std::move(x);
188  }
189  }
190  };
191 
192  /**
193  * Constructs a `Row` with the given @p values and @p columns.
194  *
195  * @note columns must not be nullptr
196  * @note columns.size() must equal values.size()
197  */
198  Row(std::vector<Value> values,
199  std::shared_ptr<const std::vector<std::string>> columns);
200 
201  std::vector<Value> values_;
202  std::shared_ptr<const std::vector<std::string>> columns_;
203 };
204 
205 /**
206  * Creates a `Row` with the specified column names and values.
207  *
208  * This overload accepts a vector of pairs, allowing the caller to specify both
209  * the column names and the `Value` that goes in each column.
210  *
211  * This function is intended for application developers who are mocking the
212  * results of a `Client::ExecuteQuery` call.
213  */
214 Row MakeTestRow(std::vector<std::pair<std::string, Value>> pairs);
215 
216 /**
217  * Creates a `Row` with `Value`s created from the given arguments and with
218  * auto-generated column names.
219  *
220  * This overload accepts a variadic list of arguments that will be used to
221  * create the `Value`s in the row. The column names will be implicitly
222  * generated, the first column being "0", the second "1", and so on,
223  * corresponding to the argument's position.
224  *
225  * This function is intended for application developers who are mocking the
226  * results of a `Client::ExecuteQuery` call.
227  */
228 template <typename... Ts>
229 Row MakeTestRow(Ts&&... ts) {
230  auto columns = std::make_shared<std::vector<std::string>>();
231  for (std::size_t i = 0; i < sizeof...(ts); ++i) {
232  columns->emplace_back(std::to_string(i));
233  }
234  std::vector<Value> v{Value(std::forward<Ts>(ts))...};
235  return spanner_internal::MakeRow(std::move(v), std::move(columns));
236 }
237 
238 /**
239  * A `RowStreamIterator` is an _Input Iterator_ (see below) that returns a
240  * sequence of `StatusOr<Row>` objects.
241  *
242  * As an [Input Iterator][input-iterator], the sequence may only be consumed
243  * once. Default constructing a `RowStreamIterator` creates an instance that
244  * represents "end".
245  *
246  * @note The term "stream" in this name refers to the general nature
247  * of the the data source, and is not intended to suggest any similarity to
248  * C++'s I/O streams library. Syntactically, this class is an "iterator".
249  *
250  * [input-iterator]: https://en.cppreference.com/w/cpp/named_req/InputIterator
251  */
253  public:
254  /**
255  * A function that returns a sequence of `StatusOr<Row>` objects. Returning
256  * an empty `Row` indicates that there are no more rows to be returned.
257  */
258  using Source = std::function<StatusOr<Row>()>;
259 
260  /// @name Iterator type aliases
261  ///@{
262  using iterator_category = std::input_iterator_tag;
263  using value_type = StatusOr<Row>;
264  using difference_type = std::ptrdiff_t;
265  using pointer = value_type*;
266  using reference = value_type&;
267  using const_pointer = value_type const*;
268  using const_reference = value_type const&;
269  ///@}
270 
271  /// Default constructs an "end" iterator.
273 
274  /**
275  * Constructs a `RowStreamIterator` that will consume rows from the given
276  * @p source, which must not be `nullptr`.
277  */
278  explicit RowStreamIterator(Source source);
279 
280  reference operator*() { return row_; }
281  pointer operator->() { return &row_; }
282 
283  const_reference operator*() const { return row_; }
284  const_pointer operator->() const { return &row_; }
285 
288 
289  friend bool operator==(RowStreamIterator const&, RowStreamIterator const&);
290  friend bool operator!=(RowStreamIterator const&, RowStreamIterator const&);
291 
292  private:
293  value_type row_;
294  Source source_; // nullptr means "end"
295 };
296 
297 /**
298  * A `TupleStreamIterator<Tuple>` is an "Input Iterator" that wraps a
299  * `RowStreamIterator`, parsing its elements into a sequence of
300  * `StatusOr<Tuple>` objects.
301  *
302  * As an Input Iterator, the sequence may only be consumed once. See
303  * https://en.cppreference.com/w/cpp/named_req/InputIterator for more details.
304  *
305  * Default constructing this object creates an instance that represents "end".
306  *
307  * Each `Row` returned by the wrapped `RowStreamIterator` must be convertible
308  * to the specified `Tuple` template parameter.
309  *
310  * @note The term "stream" in this name refers to the general nature
311  * of the the data source, and is not intended to suggest any similarity to
312  * C++'s I/O streams library. Syntactically, this class is an "iterator".
313  *
314  * @tparam Tuple the std::tuple<...> to parse each `Row` into.
315  */
316 template <typename Tuple>
318  public:
319  /// @name Iterator type aliases
320  ///@{
321  using iterator_category = std::input_iterator_tag;
322  using value_type = StatusOr<Tuple>;
323  using difference_type = std::ptrdiff_t;
324  using pointer = value_type*;
325  using reference = value_type&;
326  using const_pointer = value_type const*;
327  using const_reference = value_type const&;
328  ///@}
329 
330  /// Default constructs an "end" iterator.
331  TupleStreamIterator() = default;
332 
333  /// Creates an iterator that wraps the given `RowStreamIterator` range.
335  : it_(std::move(begin)), end_(std::move(end)) {
336  ParseTuple();
337  }
338 
339  reference operator*() { return tup_; }
340  pointer operator->() { return &tup_; }
341 
342  const_reference operator*() const { return tup_; }
343  const_pointer operator->() const { return &tup_; }
344 
346  if (!tup_) {
347  it_ = end_;
348  return *this;
349  }
350  ++it_;
351  ParseTuple();
352  return *this;
353  }
354 
356  auto const old = *this;
357  ++*this;
358  return old;
359  }
360 
361  friend bool operator==(TupleStreamIterator const& a,
362  TupleStreamIterator const& b) {
363  return a.it_ == b.it_;
364  }
365 
366  friend bool operator!=(TupleStreamIterator const& a,
367  TupleStreamIterator const& b) {
368  return !(a == b);
369  }
370 
371  private:
372  void ParseTuple() {
373  if (it_ == end_) return;
374  tup_ = *it_ ? std::move(*it_)->template get<Tuple>() : it_->status();
375  }
376 
377  value_type tup_;
378  RowStreamIterator it_;
379  RowStreamIterator end_;
380 };
381 
382 /**
383  * A `TupleStream<Tuple>` defines a range that parses `Tuple` objects from the
384  * given range of `RowStreamIterator`s.
385  *
386  * Users create instances using the `StreamOf<T>(range)` non-member factory
387  * function (defined below). The following is a typical usage of this class in
388  * a range-for loop.
389  *
390  * @code
391  * auto row_range = ...
392  * using RowType = std::tuple<std::int64_t, std::string, bool>;
393  * for (auto const& row : StreamOf<RowType>(row_range)) {
394  * if (!row) {
395  * // Handle error;
396  * }
397  * std::int64_t x = std::get<0>(*row);
398  * ...
399  * }
400  * @endcode
401  *
402  * @note The term "stream" in this name refers to the general nature
403  * of the the data source, and is not intended to suggest any similarity to
404  * C++'s I/O streams library. Syntactically, this class is a "range"
405  * defined by two "iterator" objects of type `TupleStreamIterator<Tuple>`.
406  *
407  * @tparam Tuple the std::tuple<...> to parse each `Row` into.
408  */
409 template <typename Tuple>
410 class TupleStream {
411  public:
412  using iterator = TupleStreamIterator<Tuple>;
413  static_assert(spanner_internal::IsTuple<Tuple>::value,
414  "TupleStream<T> requires a std::tuple parameter");
415 
416  iterator begin() const { return begin_; }
417  iterator end() const { return end_; }
418 
419  private:
420  template <typename T, typename RowRange>
421  friend TupleStream<T> StreamOf(RowRange&& range);
422 
423  template <typename It>
424  explicit TupleStream(It&& start, It&& end)
425  : begin_(std::forward<It>(start), std::forward<It>(end)) {}
426 
427  iterator begin_;
428  iterator end_;
429 };
430 
431 /**
432  * A factory that creates a `TupleStream<Tuple>` by wrapping the given @p
433  * range. The `RowRange` must be a range defined by `RowStreamIterator`
434  * objects.
435  *
436  * @snippet samples.cc stream-of
437  *
438  * @note Ownership of the @p range is not transferred, so it must outlive the
439  * returned `TupleStream`.
440  *
441  * @tparam RowRange must be a range defined by `RowStreamIterator`s.
442  */
443 template <typename Tuple, typename RowRange>
444 TupleStream<Tuple> StreamOf(RowRange&& range) {
445  static_assert(std::is_lvalue_reference<decltype(range)>::value,
446  "range must be an lvalue since it must outlive StreamOf");
447  return TupleStream<Tuple>(std::begin(std::forward<RowRange>(range)),
448  std::end(std::forward<RowRange>(range)));
449 }
450 
451 /**
452  * Returns the only row from a range that contains exactly one row.
453  *
454  * An error is returned if the given range does not contain exactly one row.
455  * This is a convenience function that may be useful when the caller knows that
456  * a range should contain exactly one row, such as when `LIMIT 1` is used in an
457  * SQL query, or when a read is performed on a guaranteed unique key such that
458  * only a single row could possibly match. In cases where the caller does not
459  * know how many rows may be returned, they should instead consume the range in
460  * a loop.
461  *
462  * @snippet samples.cc get-singular-row
463  *
464  * @warning Due to the fact that a `RowStreamIterator` is an input iterator,
465  * this function may consume the first element in the range, even in cases
466  * where an error is returned. But again, this function should not be used
467  * if @p range might contain multiple rows.
468  */
469 template <typename RowRange>
470 auto GetSingularRow(RowRange&& range) -> typename std::decay<
471  decltype(*std::forward<RowRange>(range).begin())>::type {
472  auto const e = std::forward<RowRange>(range).end();
473  auto it = std::forward<RowRange>(range).begin();
474  if (it == e) return Status(StatusCode::kInvalidArgument, "no rows");
475  auto row = std::move(*it);
476  if (++it != e) return Status(StatusCode::kInvalidArgument, "too many rows");
477  return row;
478 }
479 
480 } // namespace SPANNER_CLIENT_NS
481 } // namespace spanner
482 } // namespace cloud
483 } // namespace google
484 
485 #endif // GOOGLE_CLOUD_CPP_GOOGLE_CLOUD_SPANNER_ROW_H