Class Value (2.22.0)

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 TypeC++ Type T
BOOLbool
INT64std::int64_t
FLOAT64double
STRINGstd::string
BYTESgoogle::cloud::spanner::Bytes
JSONgoogle::cloud::spanner::Json
JSONBgoogle::cloud::spanner::JsonB
NUMERICgoogle::cloud::spanner::Numeric
NUMERIC(PG)google::cloud::spanner::PgNumeric
OID(PG)google::cloud::spanner::PgOid
TIMESTAMPgoogle::cloud::spanner::Timestamp
DATEabsl::CivilDay
ARRAYstd::vector<T> // [1]
STRUCTstd::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:

  1. Passing an absl::optional<T>() with no value to Value's constructor.
  2. 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 &)

Parameter
NameDescription
Value const &

Value(Value &&)

Parameter
NameDescription
Value &&

Value(bool)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v bool

Value(std::int64_t)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v std::int64_t

Value(double)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v double

Value(std::string)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v std::string

Value(Bytes)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v Bytes

Value(Json)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v Json

Value(JsonB)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v JsonB

Value(Numeric)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v Numeric

Value(PgNumeric)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v PgNumeric

Value(PgOid)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v PgOid

Value(Timestamp)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v Timestamp

Value(CommitTimestamp)

Constructs an instance with the specified type and value.

Parameter
NameDescription
v CommitTimestamp

Value(absl::CivilDay)

Constructs an instance with the specified type and value.

Parameter
NameDescription
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>());
Parameter
NameDescription
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>());
Parameter
NameDescription
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.

Parameters
NameDescription
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.

Parameters
NameDescription
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>.

Parameters
NameDescription
tup std::tuple< Ts... >
typename...

Operators

operator=(Value const &)

Parameter
NameDescription
Value const &
Returns
TypeDescription
Value &

operator=(Value &&)

Parameter
NameDescription
Value &&
Returns
TypeDescription
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 an absl::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
Parameter
NameDescription
typename T
Returns
TypeDescription
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 an absl::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
Parameter
NameDescription
typename T
Returns
TypeDescription
StatusOr< T >