The Value class represents a type-safe, nullable Spanner value.
It is conceptually similar to a std::any
except the only allowed types are those supported by Spanner, and a "null" value (similar to a std::any
without a value) still has an associated type. The supported types are shown in the following table along with how they map to the Spanner types ( https://cloud.google.com/spanner/docs/data-types
):
Spanner Type | C++ Type T
|
---|---|
BOOL | bool
|
INT64 | std::int64_t
|
FLOAT64 | double
|
STRING | std::string
|
BYTES | google::cloud::spanner::Bytes
|
JSON | google::cloud::spanner::Json
|
JSONB | google::cloud::spanner::JsonB
|
NUMERIC | google::cloud::spanner::Numeric
|
NUMERIC(PG) | google::cloud::spanner::PgNumeric
|
TIMESTAMP | google::cloud::spanner::Timestamp
|
DATE | absl::CivilDay
|
ARRAY | std::vector<T>
// [1] |
STRUCT | std::tuple<Ts...>
|
[1] The type T
may be any of the other supported types, except for ARRAY/ std::vector
.
Value is a regular C++ value type with support for copy, move, equality, etc. A default-constructed Value represents an empty value with no type.
See Also
https://cloud.google.com/spanner/docs/commit-timestamp
Callers may create instances by passing any of the supported values (shown in the table above) to the constructor. "Null" values are created using the MakeNullValue<T>()
factory function or by passing an empty absl::optional<T>
to the Value
constructor..
Example
Using a non-null value.
std::string msg = "hello";
spanner::Value v(msg);
StatusOr<std::string> copy = v.get<std::string>();
if (copy) {
std::cout << *copy; // prints "hello"
}
Example
Using a null value.
spanner::Value v = spanner::MakeNullValue<std::int64_t>();
StatusOr<std::int64_t> i = v.get<std::int64_t>();
assert(!i.ok()); // Can't get the value because v is null
StatusOr < absl::optional<std::int64_t> j =
v.get<absl::optional<std::int64_t>>();
assert(j.ok()); // OK because an empty option can represent the null
assert(!j->has_value()); // v held no value.
Nullness
All of the supported types (above) are "nullable". A null is created in one of two ways:
- Passing an
absl::optional<T>()
with no value toValue
's constructor. - Using the
MakeNullValue<T>()
helper function (defined below).
Nulls can be retrieved from a Value::get
<T>
by specifying the type T
as an absl::optional<U>
. The returned optional will either be empty (indicating null) or it will contain the actual value. See the documentation for Value::get
<T>
below for more details.
Spanner Arrays
Spanner arrays are represented in C++ as a std::vector<T>
, where the type T
may be any of the other allowed Spanner types, such as bool
, std::int64_t
, etc. The only exception is that arrays may not directly contain another array; to achieve a similar result you could create an array of a 1-element struct holding an array. The following examples show usage of arrays.
std::vector<std::int64_t> vec = {1, 2, 3, 4, 5};
spanner::Value v(vec);
auto copy = *v.get<std::vector<std::int64_t>>();
assert(vec == copy);
Spanner Structs
Spanner structs are represented in C++ as instances of std::tuple
holding zero or more of the allowed Spanner types, such as bool
, std::int64_t
, std::vector
, and even other std::tuple
objects. Each tuple element corresponds to a single field in a Spanner STRUCT.
Spanner STRUCT fields may optionally contain a string indicating the field's name. Fields names may be empty, unique, or repeated. A named field may be specified as a tuple element of type std::pair<std::string, T>
, where the pair's .first
member indicates the field's name, and the .second
member is any valid Spanner type T
.
using Struct = std::tuple<bool, std::pair<std::string, std::int64_t>>;
Struct s = {true, {"Foo", 42}};
spanner::Value v(s);
assert(s == *v.get<Struct>());
Constructors
Value()
Constructs a Value
that holds nothing.
All calls to get<T>()
will return an error.
Value(Value const &)
Value const &
Value(Value &&)
Value &&
Value(bool)
Constructs an instance with the specified type and value.
v
bool
Value(std::int64_t)
Constructs an instance with the specified type and value.
v
std::int64_t
Value(double)
Constructs an instance with the specified type and value.
v
double
Value(std::string)
Constructs an instance with the specified type and value.
v
std::string
Value(Bytes)
Constructs an instance with the specified type and value.
v
Bytes
Value(Json)
Constructs an instance with the specified type and value.
v
Json
Value(JsonB)
Constructs an instance with the specified type and value.
v
JsonB
Value(Numeric)
Constructs an instance with the specified type and value.
v
Numeric
Value(PgNumeric)
Constructs an instance with the specified type and value.
v
PgNumeric
Value(Timestamp)
Constructs an instance with the specified type and value.
v
Timestamp
Value(CommitTimestamp)
Constructs an instance with the specified type and value.
v
CommitTimestamp
Value(absl::CivilDay)
Constructs an instance with the specified type and value.
v
absl::CivilDay
Value(int)
Constructs an instance from common C++ literal types that closely, though not exactly, match supported Spanner types.
An integer literal in C++ is of type int
, which is not exactly an allowed Spanner type. This will be allowed but it will be implicitly up converted to a std::int64_t
. Similarly, a C++ string literal will be implicitly converted to a std::string
. For example:
spanner::Value v1(42);
assert(42 == *v1.get<std::int64_t>());
spanner::Value v2("hello");
assert("hello" == *v2.get<std::string>());
v
int
Value(char const *)
Constructs an instance from common C++ literal types that closely, though not exactly, match supported Spanner types.
An integer literal in C++ is of type int
, which is not exactly an allowed Spanner type. This will be allowed but it will be implicitly up converted to a std::int64_t
. Similarly, a C++ string literal will be implicitly converted to a std::string
. For example:
spanner::Value v1(42);
assert(42 == *v1.get<std::int64_t>());
spanner::Value v2("hello");
assert("hello" == *v2.get<std::string>());
v
char const *
Value(absl::optional< T >)
Constructs a non-null instance if opt
has a value, otherwise constructs a null instance with the specified type T
.
opt
absl::optional< T >
typename T
Value(std::vector< T >)
Constructs an instance from a Spanner ARRAY of the specified type and values.
The type T
may be any valid type shown above, except vectors of vectors are not allowed.
v
std::vector< T >
typename T
Value(std::tuple< Ts... >)
Constructs an instance from a Spanner STRUCT with a type and values matching the given std::tuple
.
Any STRUCT field may optionally have a name, which is specified as std::pair<std::string, T>
.
tup
std::tuple< Ts... >
typename...
Operators
operator=(Value const &)
Value const &
Value &
operator=(Value &&)
Value &&
Value &
Functions
get() const &
Returns the contained value wrapped in a google::cloud::StatusOr
<T>
.
Returns a non-OK status IFF:
- The contained value is "null", and
T
is not anabsl::optional
. - There is an error converting the contained value to
T
.
Example
spanner::Value v{3.14};
StatusOr<double> d = v.get<double>();
if (d) {
std::cout << "d=" << *d;
}
// Now using a "null" std::int64_t
v = spanner::MakeNullValue<std::int64_t>();
StatusOr<std::int64_t> i = v.get<std::int64_t>();
if (!i) {
std::cerr << "Could not get integer: " << i.status();
}
StatusOr<absl::optional<std::int64_t>> j =
v.get<absl::optional<std::int64_t>>();
assert(j.ok()); // Since we know the types match in this example
assert(!v->has_value()); // Since we know v was null in this example
typename T
StatusOr< T >
get() &&
Returns the contained value wrapped in a google::cloud::StatusOr
<T>
.
Returns a non-OK status IFF:
- The contained value is "null", and
T
is not anabsl::optional
. - There is an error converting the contained value to
T
.
Example
spanner::Value v{3.14};
StatusOr<double> d = v.get<double>();
if (d) {
std::cout << "d=" << *d;
}
// Now using a "null" std::int64_t
v = spanner::MakeNullValue<std::int64_t>();
StatusOr<std::int64_t> i = v.get<std::int64_t>();
if (!i) {
std::cerr << "Could not get integer: " << i.status();
}
StatusOr<absl::optional<std::int64_t>> j =
v.get<absl::optional<std::int64_t>>();
assert(j.ok()); // Since we know the types match in this example
assert(!v->has_value()); // Since we know v was null in this example
typename T
StatusOr< T >