16 #include "google/cloud/spanner/internal/date.h" 34 bool Equal(google::spanner::v1::Type
const& pt1,
35 google::protobuf::Value
const& pv1,
36 google::spanner::v1::Type
const& pt2,
37 google::protobuf::Value
const& pv2) {
38 if (pt1.code() != pt2.code())
return false;
39 if (pv1.kind_case() != pv2.kind_case())
return false;
41 case google::spanner::v1::TypeCode::BOOL:
42 return pv1.bool_value() == pv2.bool_value();
43 case google::spanner::v1::TypeCode::INT64:
44 return pv1.string_value() == pv2.string_value();
45 case google::spanner::v1::TypeCode::FLOAT64:
47 if (pv1.string_value() ==
"NaN" || pv2.string_value() ==
"NaN") {
50 return pv1.string_value() == pv2.string_value() &&
51 pv1.number_value() == pv2.number_value();
52 case google::spanner::v1::TypeCode::STRING:
53 case google::spanner::v1::TypeCode::BYTES:
54 case google::spanner::v1::TypeCode::DATE:
55 case google::spanner::v1::TypeCode::TIMESTAMP:
56 return pv1.string_value() == pv2.string_value();
57 case google::spanner::v1::TypeCode::ARRAY: {
58 auto const& etype1 = pt1.array_element_type();
59 auto const& etype2 = pt2.array_element_type();
60 if (etype1.code() != etype2.code())
return false;
61 auto const& v1 = pv1.list_value().values();
62 auto const& v2 = pv2.list_value().values();
63 if (v1.size() != v2.size())
return false;
64 for (
int i = 0; i < v1.size(); ++i) {
65 if (!Equal(etype1, v1.Get(i), etype1, v2.Get(i))) {
71 case google::spanner::v1::TypeCode::STRUCT: {
72 auto const& fields1 = pt1.struct_type().fields();
73 auto const& fields2 = pt2.struct_type().fields();
74 if (fields1.size() != fields2.size())
return false;
75 auto const& v1 = pv1.list_value().values();
76 auto const& v2 = pv2.list_value().values();
77 if (fields1.size() != v1.size() || v1.size() != v2.size())
return false;
78 for (
int i = 0; i < fields1.size(); ++i) {
79 auto const& f1 = fields1.Get(i);
80 auto const& f2 = fields2.Get(i);
81 if (f1.name() != f2.name())
return false;
82 if (!Equal(f1.type(), v1.Get(i), f2.type(), v2.Get(i))) {
96 std::ostream& EscapeQuotes(std::ostream& os, std::string
const& s) {
97 for (
auto const& c : s) {
98 if (c ==
'"') os <<
"\\";
109 std::ostream& StreamHelper(std::ostream& os, google::protobuf::Value
const& v,
110 google::spanner::v1::Type
const& t,
112 if (v.kind_case() == google::protobuf::Value::kNullValue) {
117 case google::spanner::v1::TypeCode::BOOL:
118 return os << v.bool_value();
120 case google::spanner::v1::TypeCode::INT64:
121 return os << internal::FromProto(t, v).get<std::int64_t>().value();
123 case google::spanner::v1::TypeCode::FLOAT64:
124 return os << internal::FromProto(t, v).get<
double>().value();
126 case google::spanner::v1::TypeCode::STRING:
128 case StreamMode::kScalar:
129 return os << v.string_value();
130 case StreamMode::kAggregate:
132 EscapeQuotes(os, v.string_value());
137 case google::spanner::v1::TypeCode::BYTES:
138 return os << internal::BytesFromBase64(v.string_value()).value();
140 case google::spanner::v1::TypeCode::TIMESTAMP:
141 case google::spanner::v1::TypeCode::DATE:
142 return os << v.string_value();
144 case google::spanner::v1::TypeCode::ARRAY: {
145 const char* delimiter =
"";
147 for (
auto const& e : v.list_value().values()) {
149 StreamHelper(os, e, t.array_element_type(), StreamMode::kAggregate);
155 case google::spanner::v1::TypeCode::STRUCT: {
156 const char* delimiter =
"";
158 for (
int i = 0; i < v.list_value().values_size(); ++i) {
160 if (!t.struct_type().fields(i).name().empty()) {
162 EscapeQuotes(os, t.struct_type().fields(i).name());
165 StreamHelper(os, v.list_value().values(i),
166 t.struct_type().fields(i).type(), StreamMode::kAggregate);
173 return os <<
"Error: unknown value type code " << t.code();
182 Value FromProto(google::spanner::v1::Type t, google::protobuf::Value v) {
183 return Value(std::move(t), std::move(v));
186 std::pair<google::spanner::v1::Type, google::protobuf::Value> ToProto(Value v) {
187 return std::make_pair(std::move(v.type_), std::move(v.value_));
193 return Equal(a.type_, a.value_, b.type_, b.value_);
197 return StreamHelper(os, v.value_, v.type_, StreamMode::kScalar);
204 bool Value::TypeProtoIs(
bool, google::spanner::v1::Type
const& type) {
205 return type.code() == google::spanner::v1::TypeCode::BOOL;
208 bool Value::TypeProtoIs(std::int64_t, google::spanner::v1::Type
const& type) {
209 return type.code() == google::spanner::v1::TypeCode::INT64;
212 bool Value::TypeProtoIs(
double, google::spanner::v1::Type
const& type) {
213 return type.code() == google::spanner::v1::TypeCode::FLOAT64;
216 bool Value::TypeProtoIs(Timestamp, google::spanner::v1::Type
const& type) {
217 return type.code() == google::spanner::v1::TypeCode::TIMESTAMP;
220 bool Value::TypeProtoIs(CommitTimestamp,
221 google::spanner::v1::Type
const& type) {
222 return type.code() == google::spanner::v1::TypeCode::TIMESTAMP;
225 bool Value::TypeProtoIs(Date, google::spanner::v1::Type
const& type) {
226 return type.code() == google::spanner::v1::TypeCode::DATE;
229 bool Value::TypeProtoIs(std::string
const&,
230 google::spanner::v1::Type
const& type) {
231 return type.code() == google::spanner::v1::TypeCode::STRING;
234 bool Value::TypeProtoIs(Bytes
const&, google::spanner::v1::Type
const& type) {
235 return type.code() == google::spanner::v1::TypeCode::BYTES;
242 google::spanner::v1::Type Value::MakeTypeProto(
bool) {
243 google::spanner::v1::Type t;
244 t.set_code(google::spanner::v1::TypeCode::BOOL);
248 google::spanner::v1::Type Value::MakeTypeProto(std::int64_t) {
249 google::spanner::v1::Type t;
250 t.set_code(google::spanner::v1::TypeCode::INT64);
254 google::spanner::v1::Type Value::MakeTypeProto(
double) {
255 google::spanner::v1::Type t;
256 t.set_code(google::spanner::v1::TypeCode::FLOAT64);
260 google::spanner::v1::Type Value::MakeTypeProto(std::string
const&) {
261 google::spanner::v1::Type t;
262 t.set_code(google::spanner::v1::TypeCode::STRING);
266 google::spanner::v1::Type Value::MakeTypeProto(Bytes
const&) {
267 google::spanner::v1::Type t;
268 t.set_code(google::spanner::v1::TypeCode::BYTES);
272 google::spanner::v1::Type Value::MakeTypeProto(Timestamp) {
273 google::spanner::v1::Type t;
274 t.set_code(google::spanner::v1::TypeCode::TIMESTAMP);
278 google::spanner::v1::Type Value::MakeTypeProto(CommitTimestamp) {
279 google::spanner::v1::Type t;
280 t.set_code(google::spanner::v1::TypeCode::TIMESTAMP);
284 google::spanner::v1::Type Value::MakeTypeProto(Date) {
285 google::spanner::v1::Type t;
286 t.set_code(google::spanner::v1::TypeCode::DATE);
290 google::spanner::v1::Type Value::MakeTypeProto(
int) {
291 return MakeTypeProto(std::int64_t{});
294 google::spanner::v1::Type Value::MakeTypeProto(
char const*) {
295 return MakeTypeProto(std::string{});
302 google::protobuf::Value Value::MakeValueProto(
bool b) {
303 google::protobuf::Value v;
308 google::protobuf::Value Value::MakeValueProto(std::int64_t i) {
309 google::protobuf::Value v;
310 v.set_string_value(std::to_string(i));
314 google::protobuf::Value Value::MakeValueProto(
double d) {
315 google::protobuf::Value v;
317 v.set_string_value(
"NaN");
318 }
else if (std::isinf(d)) {
319 v.set_string_value(d < 0 ?
"-Infinity" :
"Infinity");
321 v.set_number_value(d);
326 google::protobuf::Value Value::MakeValueProto(std::string s) {
327 google::protobuf::Value v;
328 v.set_string_value(std::move(s));
332 google::protobuf::Value Value::MakeValueProto(Bytes bytes) {
333 google::protobuf::Value v;
334 v.set_string_value(internal::BytesToBase64(std::move(bytes)));
338 google::protobuf::Value Value::MakeValueProto(Timestamp ts) {
339 google::protobuf::Value v;
340 v.set_string_value(internal::TimestampToRFC3339(ts));
344 google::protobuf::Value Value::MakeValueProto(CommitTimestamp) {
345 google::protobuf::Value v;
346 v.set_string_value(
"spanner.commit_timestamp()");
350 google::protobuf::Value Value::MakeValueProto(Date d) {
351 google::protobuf::Value v;
352 v.set_string_value(internal::DateToString(d));
356 google::protobuf::Value Value::MakeValueProto(
int i) {
357 return MakeValueProto(std::int64_t{i});
360 google::protobuf::Value Value::MakeValueProto(
char const* s) {
361 return MakeValueProto(std::string(s));
368 StatusOr<bool> Value::GetValue(
bool, google::protobuf::Value
const& pv,
369 google::spanner::v1::Type
const&) {
370 if (pv.kind_case() != google::protobuf::Value::kBoolValue) {
371 return Status(StatusCode::kUnknown,
"missing BOOL");
373 return pv.bool_value();
376 StatusOr<std::int64_t> Value::GetValue(std::int64_t,
377 google::protobuf::Value
const& pv,
378 google::spanner::v1::Type
const&) {
379 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
380 return Status(StatusCode::kUnknown,
"missing INT64");
382 auto const& s = pv.string_value();
385 std::int64_t x = {std::strtoll(s.c_str(), &end, 10)};
387 auto const err = std::string(std::strerror(errno));
388 return Status(StatusCode::kUnknown, err +
": \"" + s +
"\"");
390 if (end == s.c_str()) {
391 return Status(StatusCode::kUnknown,
"No numeric conversion: \"" + s +
"\"");
394 return Status(StatusCode::kUnknown,
"Trailing data: \"" + s +
"\"");
399 StatusOr<double> Value::GetValue(
double, google::protobuf::Value
const& pv,
400 google::spanner::v1::Type
const&) {
401 if (pv.kind_case() == google::protobuf::Value::kNumberValue) {
402 return pv.number_value();
404 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
405 return Status(StatusCode::kUnknown,
"missing FLOAT64");
407 std::string
const& s = pv.string_value();
408 auto const inf = std::numeric_limits<double>::infinity();
409 if (s ==
"-Infinity")
return -inf;
410 if (s ==
"Infinity")
return inf;
411 if (s ==
"NaN")
return std::nan(
"");
412 return Status(StatusCode::kUnknown,
"bad FLOAT64 data: \"" + s +
"\"");
415 StatusOr<std::string> Value::GetValue(std::string
const&,
416 google::protobuf::Value
const& pv,
417 google::spanner::v1::Type
const&) {
418 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
419 return Status(StatusCode::kUnknown,
"missing STRING");
421 return pv.string_value();
424 StatusOr<std::string> Value::GetValue(std::string
const&,
425 google::protobuf::Value&& pv,
426 google::spanner::v1::Type
const&) {
427 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
428 return Status(StatusCode::kUnknown,
"missing STRING");
430 return std::move(*pv.mutable_string_value());
433 StatusOr<Bytes> Value::GetValue(Bytes
const&, google::protobuf::Value
const& pv,
434 google::spanner::v1::Type
const&) {
435 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
436 return Status(StatusCode::kUnknown,
"missing BYTES");
438 auto decoded = internal::BytesFromBase64(pv.string_value());
439 if (!decoded)
return decoded.status();
443 StatusOr<Timestamp> Value::GetValue(Timestamp,
444 google::protobuf::Value
const& pv,
445 google::spanner::v1::Type
const&) {
446 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
447 return Status(StatusCode::kUnknown,
"missing TIMESTAMP");
449 return internal::TimestampFromRFC3339(pv.string_value());
452 StatusOr<CommitTimestamp> Value::GetValue(CommitTimestamp,
453 google::protobuf::Value
const& pv,
454 google::spanner::v1::Type
const&) {
455 if (pv.kind_case() != google::protobuf::Value::kStringValue ||
456 pv.string_value() !=
"spanner.commit_timestamp()") {
457 return Status(StatusCode::kUnknown,
"invalid commit_timestamp");
459 return CommitTimestamp{};
462 StatusOr<Date> Value::GetValue(Date, google::protobuf::Value
const& pv,
463 google::spanner::v1::Type
const&) {
464 if (pv.kind_case() != google::protobuf::Value::kStringValue) {
465 return Status(StatusCode::kUnknown,
"missing DATE");
467 return internal::DateFromString(pv.string_value());
The Value class represents a type-safe, nullable Spanner value.
std::ostream & operator<<(std::ostream &os, Value const &v)
bool operator==(Value const &a, Value const &b)
Contains all the Cloud Spanner C++ client types and functions.
#define SPANNER_CLIENT_NS