15 #include "google/cloud/spanner/value.h"
16 #include "google/cloud/internal/strerror.h"
17 #include "absl/time/civil_time.h"
35 bool Equal(
google::spanner::v1::Type
const& pt1,
36 google::protobuf::Value
const& pv1,
37 google::spanner::v1::Type
const& pt2,
38 google::protobuf::Value
const& pv2) {
39 if (pt1.code() != pt2.code())
return false;
40 if (pv1.kind_case() != pv2.kind_case())
return false;
42 case google::spanner::v1::TypeCode::BOOL:
43 return pv1.bool_value() == pv2.bool_value();
44 case google::spanner::v1::TypeCode::INT64:
45 return pv1.string_value() == pv2.string_value();
46 case google::spanner::v1::TypeCode::FLOAT64:
48 if (pv1.string_value() ==
"NaN" || pv2.string_value() ==
"NaN") {
51 return pv1.string_value() == pv2.string_value() &&
52 pv1.number_value() == pv2.number_value();
53 case google::spanner::v1::TypeCode::STRING:
54 case google::spanner::v1::TypeCode::BYTES:
55 case google::spanner::v1::TypeCode::JSON:
56 case google::spanner::v1::TypeCode::DATE:
57 case google::spanner::v1::TypeCode::TIMESTAMP:
58 case google::spanner::v1::TypeCode::NUMERIC:
59 return pv1.string_value() == pv2.string_value();
60 case google::spanner::v1::TypeCode::ARRAY: {
61 auto const& etype1 = pt1.array_element_type();
62 auto const& etype2 = pt2.array_element_type();
63 if (etype1.code() != etype2.code())
return false;
64 auto const& v1 = pv1.list_value().values();
65 auto const& v2 = pv2.list_value().values();
66 if (v1.size() != v2.size())
return false;
67 for (
int i = 0; i < v1.size(); ++i) {
68 if (!Equal(etype1, v1.Get(i), etype1, v2.Get(i))) {
74 case google::spanner::v1::TypeCode::STRUCT: {
75 auto const& fields1 = pt1.struct_type().fields();
76 auto const& fields2 = pt2.struct_type().fields();
77 if (fields1.size() != fields2.size())
return false;
78 auto const& v1 = pv1.list_value().values();
79 auto const& v2 = pv2.list_value().values();
80 if (fields1.size() != v1.size() || v1.size() != v2.size())
return false;
81 for (
int i = 0; i < fields1.size(); ++i) {
82 auto const& f1 = fields1.Get(i);
83 auto const& f2 = fields2.Get(i);
84 if (f1.name() != f2.name())
return false;
85 if (!Equal(f1.type(), v1.Get(i), f2.type(), v2.Get(i))) {
99 std::ostream& EscapeQuotes(std::ostream& os, std::string
const& s) {
100 for (
auto const& c : s) {
101 if (c ==
'"') os <<
"\\";
110 enum class StreamMode { kScalar, kAggregate };
112 std::ostream& StreamHelper(std::ostream& os,
113 google::protobuf::Value
const& v,
114 google::spanner::v1::Type
const& t,
116 if (v.kind_case() ==
google::protobuf::Value::kNullValue) {
121 case google::spanner::v1::TypeCode::BOOL:
122 return os << v.bool_value();
124 case google::spanner::v1::TypeCode::INT64:
128 case google::spanner::v1::TypeCode::FLOAT64:
131 case google::spanner::v1::TypeCode::STRING:
133 case StreamMode::kScalar:
134 return os << v.string_value();
135 case StreamMode::kAggregate:
137 EscapeQuotes(os, v.string_value());
142 case google::spanner::v1::TypeCode::BYTES:
143 return os << spanner_internal::BytesFromBase64(v.string_value())
.value();
145 case google::spanner::v1::TypeCode::JSON:
146 case google::spanner::v1::TypeCode::TIMESTAMP:
147 case google::spanner::v1::TypeCode::NUMERIC:
148 return os << v.string_value();
150 case google::spanner::v1::TypeCode::DATE:
154 case google::spanner::v1::TypeCode::ARRAY: {
155 char const* delimiter =
"";
157 for (
auto const& e : v.list_value().values()) {
159 StreamHelper(os, e, t.array_element_type(), StreamMode::kAggregate);
165 case google::spanner::v1::TypeCode::STRUCT: {
166 char const* delimiter =
"";
168 for (
int i = 0; i < v.list_value().values_size(); ++i) {
170 if (!t.struct_type().fields(i).name().empty()) {
172 EscapeQuotes(os, t.struct_type().fields(i).name());
175 StreamHelper(os, v.list_value().values(i),
176 t.struct_type().fields(i).type(), StreamMode::kAggregate);
183 return os <<
"Error: unknown value type code " << t.code();
191 return Equal(a.type_, a.value_, b.type_, b.value_);
194 std::ostream& operator<<(std::ostream& os,
Value const& v) {
195 return StreamHelper(os, v.value_, v.type_, StreamMode::kScalar);
202 bool Value::TypeProtoIs(
bool,
google::spanner::v1::Type
const& type) {
203 return type.code() ==
google::spanner::v1::TypeCode::BOOL;
206 bool Value::TypeProtoIs(std::int64_t,
google::spanner::v1::Type
const& type) {
207 return type.code() ==
google::spanner::v1::TypeCode::INT64;
210 bool Value::TypeProtoIs(
double,
google::spanner::v1::Type
const& type) {
211 return type.code() ==
google::spanner::v1::TypeCode::FLOAT64;
215 return type.code() ==
google::spanner::v1::TypeCode::TIMESTAMP;
219 google::spanner::v1::Type
const& type) {
220 return type.code() ==
google::spanner::v1::TypeCode::TIMESTAMP;
223 bool Value::TypeProtoIs(absl::CivilDay,
google::spanner::v1::Type
const& type) {
224 return type.code() ==
google::spanner::v1::TypeCode::DATE;
227 bool Value::TypeProtoIs(std::string
const&,
228 google::spanner::v1::Type
const& type) {
229 return type.code() ==
google::spanner::v1::TypeCode::STRING;
232 bool Value::TypeProtoIs(
Bytes const&,
google::spanner::v1::Type
const& type) {
233 return type.code() ==
google::spanner::v1::TypeCode::BYTES;
236 bool Value::TypeProtoIs(
Json const&,
google::spanner::v1::Type
const& type) {
237 return type.code() ==
google::spanner::v1::TypeCode::JSON;
241 return type.code() ==
google::spanner::v1::TypeCode::NUMERIC;
248 google::spanner::v1::Type
Value::MakeTypeProto(
bool) {
249 google::spanner::v1::Type t;
250 t.set_code(
google::spanner::v1::TypeCode::BOOL);
254 google::spanner::v1::Type
Value::MakeTypeProto(std::int64_t) {
255 google::spanner::v1::Type t;
256 t.set_code(
google::spanner::v1::TypeCode::INT64);
260 google::spanner::v1::Type
Value::MakeTypeProto(
double) {
261 google::spanner::v1::Type t;
262 t.set_code(
google::spanner::v1::TypeCode::FLOAT64);
266 google::spanner::v1::Type
Value::MakeTypeProto(std::string
const&) {
267 google::spanner::v1::Type t;
268 t.set_code(
google::spanner::v1::TypeCode::STRING);
273 google::spanner::v1::Type t;
274 t.set_code(
google::spanner::v1::TypeCode::BYTES);
279 google::spanner::v1::Type t;
280 t.set_code(
google::spanner::v1::TypeCode::JSON);
285 google::spanner::v1::Type t;
286 t.set_code(
google::spanner::v1::TypeCode::NUMERIC);
291 google::spanner::v1::Type t;
292 t.set_code(
google::spanner::v1::TypeCode::TIMESTAMP);
297 google::spanner::v1::Type t;
298 t.set_code(
google::spanner::v1::TypeCode::TIMESTAMP);
302 google::spanner::v1::Type
Value::MakeTypeProto(absl::CivilDay) {
303 google::spanner::v1::Type t;
304 t.set_code(
google::spanner::v1::TypeCode::DATE);
308 google::spanner::v1::Type
Value::MakeTypeProto(
int) {
309 return MakeTypeProto(std::int64_t{});
312 google::spanner::v1::Type
Value::MakeTypeProto(
char const*) {
313 return MakeTypeProto(std::string{});
320 google::protobuf::Value
Value::MakeValueProto(
bool b) {
321 google::protobuf::Value v;
326 google::protobuf::Value
Value::MakeValueProto(std::int64_t i) {
327 google::protobuf::Value v;
328 v.set_string_value(std::to_string(i));
332 google::protobuf::Value
Value::MakeValueProto(
double d) {
333 google::protobuf::Value v;
335 v.set_string_value(
"NaN");
336 }
else if (std::isinf(d)) {
337 v.set_string_value(d < 0 ?
"-Infinity" :
"Infinity");
339 v.set_number_value(d);
344 google::protobuf::Value
Value::MakeValueProto(std::string s) {
345 google::protobuf::Value v;
346 v.set_string_value(std::move(s));
351 google::protobuf::Value v;
352 v.set_string_value(spanner_internal::BytesToBase64(std::move(bytes)));
357 google::protobuf::Value v;
358 v.set_string_value(std::string(std::move(j)));
363 google::protobuf::Value v;
369 google::protobuf::Value v;
370 v.set_string_value(spanner_internal::TimestampToRFC3339(ts));
375 google::protobuf::Value v;
376 v.set_string_value(
"spanner.commit_timestamp()");
380 google::protobuf::Value
Value::MakeValueProto(absl::CivilDay d) {
381 google::protobuf::Value v;
384 std::ostringstream ss;
385 ss << std::internal << std::setfill(
'0') << std::setw(4) << d.year() <<
'-';
386 ss << std::setfill(
'0') << std::setw(2) << d.month() <<
'-';
387 ss << std::setfill(
'0') << std::setw(2) << d.day();
388 v.set_string_value(std::move(ss).str());
392 google::protobuf::Value
Value::MakeValueProto(
int i) {
393 return MakeValueProto(std::int64_t{i});
396 google::protobuf::Value
Value::MakeValueProto(
char const* s) {
397 return MakeValueProto(std::string(s));
404 StatusOr<
bool>
Value::GetValue(
bool,
google::protobuf::Value
const& pv,
405 google::spanner::v1::Type
const&) {
406 if (pv.kind_case() !=
google::protobuf::Value::kBoolValue) {
409 return pv.bool_value();
412 StatusOr<std::int64_t>
Value::GetValue(std::int64_t,
413 google::protobuf::Value
const& pv,
414 google::spanner::v1::Type
const&) {
415 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
418 auto const& s = pv.string_value();
421 std::int64_t x = {std::strtoll(s.c_str(), &end, 10)};
424 google::
cloud::internal::strerror(errno) +
": \"" + s +
"\"");
426 if (end == s.c_str()) {
435 StatusOr<
double>
Value::GetValue(
double,
google::protobuf::Value
const& pv,
436 google::spanner::v1::Type
const&) {
437 if (pv.kind_case() ==
google::protobuf::Value::kNumberValue) {
438 return pv.number_value();
440 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
443 std::string
const& s = pv.string_value();
444 auto const inf = std::numeric_limits<
double>::infinity();
445 if (s ==
"-Infinity")
return -inf;
446 if (s ==
"Infinity")
return inf;
447 if (s ==
"NaN")
return std::nan(
"");
451 StatusOr<std::string>
Value::GetValue(std::string
const&,
452 google::protobuf::Value
const& pv,
453 google::spanner::v1::Type
const&) {
454 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
457 return pv.string_value();
460 StatusOr<std::string>
Value::GetValue(std::string
const&,
461 google::protobuf::Value&& pv,
462 google::spanner::v1::Type
const&) {
463 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
466 return std::move(*pv.mutable_string_value());
470 google::spanner::v1::Type
const&) {
471 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
474 auto decoded = spanner_internal::BytesFromBase64(pv.string_value());
480 google::spanner::v1::Type
const&) {
481 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
484 return Json(pv.string_value()
);
488 google::protobuf::Value
const& pv,
489 google::spanner::v1::Type
const&) {
490 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
499 google::protobuf::Value
const& pv,
500 google::spanner::v1::Type
const&) {
501 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
504 return spanner_internal::TimestampFromRFC3339(pv.string_value());
508 google::protobuf::Value
const& pv,
509 google::spanner::v1::Type
const&) {
510 if (pv.kind_case() !=
google::protobuf::Value::kStringValue ||
511 pv.string_value() !=
"spanner.commit_timestamp()") {
517 StatusOr<absl::CivilDay>
Value::GetValue(absl::CivilDay,
518 google::protobuf::Value
const& pv,
519 google::spanner::v1::Type
const&) {
520 if (pv.kind_case() !=
google::protobuf::Value::kStringValue) {
523 auto const& s = pv.string_value();
525 if (absl::ParseCivilTime(s, &day))
return day;
527 s +
": Failed to match RFC3339 full-date");