1717#include " google/cloud/internal/throw_delegate.h"
1818#include " absl/container/flat_hash_set.h"
1919#include " absl/strings/cord.h"
20+ #include " absl/strings/substitute.h"
2021#include < google/bigtable/v2/types.pb.h>
2122#include < google/protobuf/descriptor.h>
2223#include < google/protobuf/message.h>
@@ -339,58 +340,71 @@ std::ostream& operator<<(std::ostream& os, Value const& v) {
339340}
340341
341342// NOLINTNEXTLINE(misc-no-recursion)
342- bool Value::TypeAndArrayValuesMatch (google::bigtable::v2::Type const & type,
343+ Status Value::TypeAndArrayValuesMatch (google::bigtable::v2::Type const & type,
343344 google::bigtable::v2::Value const & value) {
344345 if (!value.has_array_value ()) {
345- return false ;
346+ return internal::InternalError ( " Value kind must be ARRAY_VALUE for columns of type: MAP " ) ;
346347 }
347348 auto const & vals = value.array_value ().values ();
348- // NOLINTNEXTLINE(misc-no-recursion)
349- return std::all_of (vals.begin (), vals.end (), [&](auto const & val) -> bool {
350- return TypeAndValuesMatch (type.array_type ().element_type (), val);
351- });
349+ for (auto const & val : vals) {
350+ auto const element_match_result = TypeAndValuesMatch (type.array_type ().element_type (), val);
351+ if (!element_match_result.ok ()) {
352+ return element_match_result;
353+ }
354+ }
355+ return Status{};
352356}
353357
354358// NOLINTNEXTLINE(misc-no-recursion)
355- bool Value::TypeAndMapValuesMatch (google::bigtable::v2::Type const & type,
359+ Status Value::TypeAndMapValuesMatch (google::bigtable::v2::Type const & type,
356360 google::bigtable::v2::Value const & value) {
357361 if (!value.has_array_value ()) {
358- return false ;
362+ return internal::InternalError ( " Value kind must be ARRAY_VALUE for columns of type: MAP " ) ;
359363 }
360364 auto key_type = type.map_type ().key_type ();
361365 auto value_type = type.map_type ().value_type ();
362366 auto const & vals = value.array_value ().values ();
363- // NOLINTNEXTLINE(misc-no-recursion)
364- return std::all_of (vals.begin (), vals.end (), [&](auto const & val) -> bool {
367+ for (auto const & val : vals) {
365368 if (!val.has_array_value () || val.array_value ().values_size () != 2 ) {
366- return false ;
369+ return internal::InternalError ( " ARRAY_VALUE must contain entries of 2 values " ) ;
367370 }
368371 auto map_key = val.array_value ().values (0 );
369372 auto map_value = val.array_value ().values (1 );
370- return TypeAndValuesMatch (key_type, map_key) &&
371- TypeAndValuesMatch (value_type, map_value);
372- });
373+ // NOLINTNEXTLINE(misc-no-recursion)
374+ auto key_match_result = TypeAndValuesMatch (key_type, map_key);
375+ if (!key_match_result.ok ()) {
376+ return key_match_result;
377+ }
378+ // NOLINTNEXTLINE(misc-no-recursion)
379+ auto value_match_result = TypeAndValuesMatch (value_type, map_value);
380+ if (!value_match_result.ok ()) {
381+ return value_match_result;
382+ }
383+ }
384+ return Status{};
373385}
374386
375387// NOLINTNEXTLINE(misc-no-recursion)
376- bool Value::TypeAndStructValuesMatch (google::bigtable::v2::Type const & type,
388+ Status Value::TypeAndStructValuesMatch (google::bigtable::v2::Type const & type,
377389 google::bigtable::v2::Value const & value) {
378390 if (!value.has_array_value ()) {
379- return false ;
391+ return internal::InternalError ( " Value kind must be ARRAY_VALUE for columns of type: STRUCT " ) ;
380392 }
381393 auto fields = type.struct_type ().fields ();
382394 auto values = value.array_value ().values ();
383395 if (fields.size () != values.size ()) {
384- return false ;
396+ auto const message = absl::Substitute (" received Struct with $0 values, but metadata has $1 fields" , values.size (), fields.size ());
397+ return internal::InternalError (message);
385398 }
386399 for (int i = 0 ; i < fields.size (); ++i) {
387400 auto const & f1 = fields.Get (i);
388401 auto const & v = values[i];
389- if (!TypeAndValuesMatch (f1.type (), v)) {
390- return false ;
402+ auto match_result = TypeAndValuesMatch (f1.type (), v);
403+ if (!match_result.ok ()) {
404+ return match_result;
391405 }
392406 }
393- return true ;
407+ return Status{} ;
394408}
395409
396410/* *
@@ -399,51 +413,74 @@ bool Value::TypeAndStructValuesMatch(google::bigtable::v2::Type const& type,
399413 * the value contents themselves
400414 */
401415// NOLINTNEXTLINE(misc-no-recursion)
402- bool Value::TypeAndValuesMatch (google::bigtable::v2::Type const & type,
416+ Status Value::TypeAndValuesMatch (google::bigtable::v2::Type const & type,
403417 google::bigtable::v2::Value const & value) {
404418 using google::bigtable::v2::Type;
405- bool has_matching_value;
419+ auto make_mismatch_metadata_status = [&](std::string const & value_kind, std::string const & type_name) {
420+ auto const message = absl::Substitute (" Value kind must be $0 for columns of type: $1" , value_kind, type_name);
421+ return internal::InternalError (message);
422+ };
423+ // Null values are allowed by default
424+ if (IsNullValue (value)) {
425+ return Status{};
426+ }
427+ Status result;
406428 switch (type.kind_case ()) {
407429 case Type::kArrayType :
408- has_matching_value = TypeAndArrayValuesMatch (type, value);
430+ result = TypeAndArrayValuesMatch (type, value);
409431 break ;
410432 case Type::kMapType :
411- has_matching_value = TypeAndMapValuesMatch (type, value);
433+ result = TypeAndMapValuesMatch (type, value);
412434 break ;
413435 case Type::kStructType :
414- has_matching_value = TypeAndStructValuesMatch (type, value);
436+ result = TypeAndStructValuesMatch (type, value);
415437 break ;
416438 case Type::kBoolType :
417- has_matching_value = value.has_bool_value ();
439+ if (!value.has_bool_value ()) {
440+ result = make_mismatch_metadata_status (" BOOL_VALUE" , " BOOL" );
441+ }
418442 break ;
419443 case Type::kBytesType :
420- has_matching_value = value.has_bytes_value ();
444+ if (!value.has_bytes_value ()) {
445+ result = make_mismatch_metadata_status (" BYTES_VALUE" , " BYTES" );
446+ }
421447 break ;
422448 case Type::kDateType :
423- has_matching_value = value.has_date_value ();
424- break ;
425- case Type::kEnumType :
426- has_matching_value = value.has_int_value ();
449+ if (!value.has_date_value ()) {
450+ result = make_mismatch_metadata_status (" DATE_VALUE" , " DATE" );
451+ }
427452 break ;
428453 case Type::kFloat32Type :
454+ if (!value.has_float_value ()) {
455+ result = make_mismatch_metadata_status (" FLOAT_VALUE" , " FLOAT32" );
456+ }
457+ break ;
429458 case Type::kFloat64Type :
430- has_matching_value = value.has_float_value ();
459+ if (!value.has_float_value ()) {
460+ result = make_mismatch_metadata_status (" FLOAT_VALUE" , " FLOAT64" );
461+ }
431462 break ;
432463 case Type::kInt64Type :
433- has_matching_value = value.has_int_value ();
464+ if (!value.has_int_value ()) {
465+ result = make_mismatch_metadata_status (" INT_VALUE" , " INT64" );
466+ }
434467 break ;
435468 case Type::kStringType :
436- has_matching_value = value.has_string_value ();
469+ if (!value.has_string_value ()) {
470+ result = make_mismatch_metadata_status (" STRING_VALUE" , " STRING" );
471+ }
437472 break ;
438473 case Type::kTimestampType :
439- has_matching_value = value.has_timestamp_value ();
474+ if (!value.has_timestamp_value ()) {
475+ result = make_mismatch_metadata_status (" TIMESTAMP_VALUE" , " TIMESTAMP" );
476+ }
440477 break ;
441478 default :
442- has_matching_value = false ;
479+ result = internal::InternalError ( " Unsupported type " ) ;
443480 break ;
444481 }
445482 // Nulls are allowed;
446- return has_matching_value || IsNullValue (value) ;
483+ return result ;
447484}
448485
449486//
0 commit comments