From 7ad6ad2e90f4b17c73c0f74f57460ef50469fa0b Mon Sep 17 00:00:00 2001 From: Andy Schwerin Date: Mon, 23 Dec 2013 14:19:12 -0500 Subject: SERVER-11995 Add basic integer support to bson_extract.h. --- src/mongo/bson/util/bson_extract.cpp | 42 +++++++++++++++++++++++++++++-- src/mongo/bson/util/bson_extract.h | 29 +++++++++++++++++++++ src/mongo/bson/util/bson_extract_test.cpp | 40 +++++++++++++++++++++++++++++ 3 files changed, 109 insertions(+), 2 deletions(-) (limited to 'src/mongo/bson') diff --git a/src/mongo/bson/util/bson_extract.cpp b/src/mongo/bson/util/bson_extract.cpp index a20e2aef4e5..19ca41c47fc 100644 --- a/src/mongo/bson/util/bson_extract.cpp +++ b/src/mongo/bson/util/bson_extract.cpp @@ -67,17 +67,20 @@ namespace mongo { Status status = bsonExtractField(object, fieldName, &value); if (status == ErrorCodes::NoSuchKey) { *out = defaultValue; + return Status::OK(); } else if (!status.isOK()) { return status; } else if (!value.isNumber() && !value.isBoolean()) { - return Status(ErrorCodes::TypeMismatch, "Expected boolean or number type"); + return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << + "Expected boolean or number type for field \"" << fieldName << + "\", found " << typeName(value.type())); } else { *out = value.trueValue(); + return Status::OK(); } - return Status::OK(); } Status bsonExtractStringField(const BSONObj& object, @@ -105,4 +108,39 @@ namespace mongo { return Status::OK(); } + Status bsonExtractIntegerField(const BSONObj& object, + const StringData& fieldName, + long long* out) { + BSONElement value; + Status status = bsonExtractField(object, fieldName, &value); + if (!status.isOK()) + return status; + if (!value.isNumber()) { + return Status(ErrorCodes::TypeMismatch, mongoutils::str::stream() << + "Expected field \"" << fieldName << + "\" to have numeric type, but found " << typeName(value.type())); + } + long long result = value.safeNumberLong(); + if (result != value.numberDouble()) { + return Status(ErrorCodes::BadValue, mongoutils::str::stream() << + "Expected field \"" << fieldName << " to have an value " + "exactly representable as a 64-bit integer, but found " << + value); + } + *out = result; + return Status::OK(); + } + + Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, + const StringData& fieldName, + long long defaultValue, + long long* out) { + Status status = bsonExtractIntegerField(object, fieldName, out); + if (status == ErrorCodes::NoSuchKey) { + *out = defaultValue; + status = Status::OK(); + } + return status; + } + } // namespace mongo diff --git a/src/mongo/bson/util/bson_extract.h b/src/mongo/bson/util/bson_extract.h index 8887a782f83..fd1c6ca057b 100644 --- a/src/mongo/bson/util/bson_extract.h +++ b/src/mongo/bson/util/bson_extract.h @@ -61,6 +61,20 @@ namespace mongo { const StringData& fieldName, bool* out); + /** + * Finds an element named "fieldName" in "object" that represents an integral value. + * + * Returns Status::OK() and sets *out to the element's 64-bit integer value representation on + * success. Returns ErrorCodes::NoSuchKey if there are no matches for "fieldName". Returns + * ErrorCodes::TypeMismatch if the value of the matching element is not of a numeric type. + * Returns ErrorCodes::BadValue if the value does not have an exact 64-bit integer + * representation. For return values other than Status::OK(), the resulting value of "*out" is + * undefined. + */ + Status bsonExtractIntegerField(const BSONObj& object, + const StringData& fieldName, + long long* out); + /** * Finds a string-typed element named "fieldName" in "object" and stores its value in "out". * @@ -88,6 +102,21 @@ namespace mongo { bool defaultValue, bool* out); + /** + * Finds an element named "fieldName" in "object" that represents an integral value. + * + * If a field named "fieldName" is present and is a value of numeric type with an exact 64-bit + * integer representation, returns that representation in *out and returns Status::OK(). If + * there is no field named "fieldName", stores defaultValue into *out and returns Status::OK(). + * If the field is found, but has non-numeric type, returns ErrorCodes::TypeMismatch. If the + * value has numeric type, but cannot be represented as a 64-bit integer, returns + * ErrorCodes::BadValue. + */ + Status bsonExtractIntegerFieldWithDefault(const BSONObj& object, + const StringData& fieldName, + long long defaultValue, + long long* out); + /** * Finds a string element named "fieldName" in "object". * diff --git a/src/mongo/bson/util/bson_extract_test.cpp b/src/mongo/bson/util/bson_extract_test.cpp index 38c9e568bd0..78774104063 100644 --- a/src/mongo/bson/util/bson_extract_test.cpp +++ b/src/mongo/bson/util/bson_extract_test.cpp @@ -96,3 +96,43 @@ TEST(ExtractBSON, ExtractBooleanFieldWithDefault) { ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractBooleanFieldWithDefault(obj1, "b", true, &b)); } + +TEST(ExtractBSON, ExtractIntegerField) { + long long v; + ASSERT_EQUALS(ErrorCodes::NoSuchKey, bsonExtractIntegerField( + BSON("a" << 1), + "b", + &v)); + ASSERT_OK(bsonExtractIntegerFieldWithDefault( + BSON("a" << 1), + "b", + -1LL, + &v)); + ASSERT_EQUALS(-1LL, v); + ASSERT_EQUALS(ErrorCodes::TypeMismatch, bsonExtractIntegerField( + BSON("a" << false), + "a", + &v)); + ASSERT_EQUALS(ErrorCodes::BadValue, bsonExtractIntegerField( + BSON("a" << nan("")), + "a", + &v)); + ASSERT_EQUALS(ErrorCodes::BadValue, bsonExtractIntegerField( + BSON("a" << pow(2.0, 64)), + "a", + &v)); + ASSERT_EQUALS(ErrorCodes::BadValue, bsonExtractIntegerField( + BSON("a" << -1.5), + "a", + &v)); + ASSERT_OK(bsonExtractIntegerField( + BSON("a" << -pow(2.0, 55)), + "a", + &v)); + ASSERT_EQUALS(-(1LL << 55), v); + ASSERT_OK(bsonExtractIntegerField( + BSON("a" << 5178), + "a", + &v)); + ASSERT_EQUALS(5178, v); +} -- cgit v1.2.1