1
0
Fork 0
arangodb/lib/Basics/BsonHelper.h

363 lines
11 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/// @brief abstraction for libbson
///
/// @file lib/Basics/BsonHelper.h
///
/// DISCLAIMER
///
/// Copyright 2014-2014 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
/// http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Max Neunhoeffer
/// @author Copyright 2014, triagens GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////
#ifndef TRIAGENS_BASICS_BSON_HELPER_H
#define TRIAGENS_BASICS_BSON_HELPER_H 1
#include "Common.h"
extern "C" {
#include "libbson-1.0/bson.h"
}
// -----------------------------------------------------------------------------
// --SECTION-- types
// -----------------------------------------------------------------------------
namespace triagens {
namespace basics {
class BsonIter;
class Bson {
friend class BsonIter;
// -----------------------------------------------------------------------------
// --SECTION-- private data
// -----------------------------------------------------------------------------
bson_t _bson; // this class is only a very thin wrapping layer
uint32_t count; // for array appending
void init () {
bson_init(&_bson);
count = 0;
}
void destruct () {
bson_destroy(&_bson);
}
// -----------------------------------------------------------------------------
// --SECTION-- constructors and destructors
// -----------------------------------------------------------------------------
public:
////////////////////////////////////////////////////////////////////////////////
/// @brief Create an empty Bson structure
////////////////////////////////////////////////////////////////////////////////
Bson () {
// This will be empty but can mutable.
init();
}
Bson (uint8_t const* data, uint32_t length) {
// This will be readonly!
bson_init_static(&_bson, data, length);
count = 0;
}
~Bson () {
destruct();
}
Bson (Bson const& another) {
bson_copy_to(&another._bson, &_bson);
count = 0;
}
void operator= (Bson const& that) {
destruct();
bson_copy_to(&that._bson, &_bson);
count = 0;
}
uint8_t const* getBuffer () {
// Only usable to copy out.
return bson_get_data(&_bson);
}
uint8_t* steal (uint32_t* length) {
// Ownership goes over to the caller.
uint8_t* buf = bson_destroy_with_steal(&_bson, true, length);
bson_init(&_bson);
return buf;
}
void clear () {
bson_reinit(&_bson);
count = 0;
}
bool appendNull (string const key) {
// Returns false if append did not work.
return bson_append_null(&_bson, key.c_str(), key.size());
}
bool appendBool (string const key, bool value) {
// Returns false if append did not work.
return bson_append_bool(&_bson, key.c_str(), key.size(), value);
}
bool appendDouble (string const key, double value) {
// Returns false if append did not work.
return bson_append_double(&_bson, key.c_str(), key.size(), value);
}
bool appendUtf8 (string const key, string value) {
// Returns false if append did not work.
return bson_append_utf8(&_bson, key.c_str(), key.size(),
value.c_str(), value.size());
}
bool appendDocumentBegin (string const key, Bson& child) {
// Returns false if append did not work, child will be
// destroyed and reinitialised, even if the append operation
// did not work.
bool result;
child.destruct();
result = bson_append_document_begin(&_bson, key.c_str(), key.size(),
&child._bson);
if (result) {
child.count = 0;
return true;
}
else {
child.init();
return false;
}
}
bool appendDocumentEnd (string const key, Bson& child) {
// Returns false if append did not work, child will be
// empty afterwards, even if the append operation did not work.
bool result;
result = bson_append_document_end(&_bson, &child._bson);
child.init();
return result;
}
bool toJson (string& result) {
size_t length;
char* p = bson_as_json(&_bson, &length);
if (NULL == p) {
return false;
}
result.clear();
result.append(p, length);
bson_free(p);
return true;
}
bool operator== (Bson const& that) {
return bson_equal(&_bson, &that._bson);
}
bool operator< (Bson const& that) {
return bson_compare(&_bson, &that._bson) == -1;
}
bool operator<= (Bson const& that) {
return bson_compare(&_bson, &that._bson) <= 0;
}
bool operator>= (Bson const& that) {
return bson_compare(&_bson, &that._bson) >= 0;
}
int compare (Bson const& that) {
return bson_compare(&_bson, &that._bson);
}
bool appendIterItem (string key, BsonIter& that);
// This needs to be a real method because it needs access to
// the details of the BsonIter class.
bool appendBson (Bson const& that) {
return bson_concat(&_bson, &that._bson);
}
size_t size () {
return static_cast<size_t>(bson_count_keys(&_bson));
}
bool hasField (string key) {
return bson_has_field(&_bson, key.c_str());
}
}; // class Bson
class BsonIter {
friend class Bson;
bson_iter_t _bsonIter;
bool _hasData;
public:
BsonIter (Bson const& b) : _hasData(false) {
bson_iter_init (&_bsonIter, &(b._bson));
}
~BsonIter () {} // no destruction is needed for bson_iter_t objects
bool hasData () {
return _hasData;
}
bool next () {
// Must be called before accessing the first element, returns
// true iff there is another one after this call.
return (_hasData = bson_iter_next(&_bsonIter));
}
bool find (string const key) {
// Returns true if key is found. Note: case-insensitive.
return (_hasData = bson_iter_find(&_bsonIter, key.c_str()));
}
bool findCaseSensitive (string const key) {
// Returns true if key is found.
return (_hasData = bson_iter_find(&_bsonIter, key.c_str()));
}
bool getKey (string& key) {
// Copies key to the argument and returns true, if the
// iterator is pointing to something, otherwise it returns
// false and the argument is unchanged.
if (! _hasData) {
return false;
}
char const* p = bson_iter_key(&_bsonIter);
key.clear();
key.append(p);
return true;
}
bson_type_t getType () {
// Returns one of the allowed bson types:
// BSON_TYPE_EOD = 0x00,
// BSON_TYPE_DOUBLE = 0x01,
// BSON_TYPE_UTF8 = 0x02,
// BSON_TYPE_DOCUMENT = 0x03,
// BSON_TYPE_ARRAY = 0x04,
// BSON_TYPE_BINARY = 0x05,
// BSON_TYPE_UNDEFINED = 0x06,
// BSON_TYPE_OID = 0x07,
// BSON_TYPE_BOOL = 0x08,
// BSON_TYPE_DATE_TIME = 0x09,
// BSON_TYPE_NULL = 0x0A,
// BSON_TYPE_REGEX = 0x0B,
// BSON_TYPE_DBPOINTER = 0x0C,
// BSON_TYPE_CODE = 0x0D,
// BSON_TYPE_SYMBOL = 0x0E,
// BSON_TYPE_CODEWSCOPE = 0x0F,
// BSON_TYPE_INT32 = 0x10,
// BSON_TYPE_TIMESTAMP = 0x11,
// BSON_TYPE_INT64 = 0x12,
// BSON_TYPE_MAXKEY = 0x7F,
// BSON_TYPE_MINKEY = 0xFF,
// of type bson_type_t.
return (! _hasData) ? BSON_TYPE_EOD
: bson_iter_type(&_bsonIter);
}
bool getBool () {
return (! _hasData || ! BSON_ITER_HOLDS_BOOL(&_bsonIter))
? false : bson_iter_bool(&_bsonIter);
}
double getDouble () {
return (! _hasData || ! BSON_ITER_HOLDS_DOUBLE(&_bsonIter))
? 0.0 : bson_iter_bool(&_bsonIter);
}
string getUtf8 () {
string res;
if (! _hasData || ! BSON_ITER_HOLDS_UTF8(&_bsonIter)) {
return res;
}
uint32_t length;
char const* p = bson_iter_utf8(&_bsonIter, &length);
res.append(p,length);
return res;
}
bool recurse (BsonIter& child) {
bson_type_t type = getType();
if (type == BSON_TYPE_ARRAY || type == BSON_TYPE_DOCUMENT) {
child._hasData = false;
return bson_iter_recurse(&_bsonIter, &child._bsonIter);
}
return false;
}
};
string EscapeUtf8ForJson (string s) {
char* p = bson_utf8_escape_for_json (s.c_str(), s.size());
string res(p);
bson_free(p);
return res;
}
inline bool Bson::appendIterItem (string key, BsonIter& that) {
if (! that.hasData()) {
return false;
}
return bson_append_iter(&_bson, key.c_str(), key.size(),
&that._bsonIter);
}
// Left out so far:
// append for anything non-JSON
// bson_writer
// bson_reader
// bson_context because it is only needed for oids
// copy_to_excluding
// extract raw sub-bsons from iter (bson_iter_array, bson_iter_document)
// extract for anything non-JSON
// overwrite for fixed-length data via iterator
// visitor for bson
// oid support
// reserve: not exported by official libbson
// bson-strings : unnecessary
// utf8-validation
} // namespace triagens.basics
} // namespace triagens
#endif
// Local Variables:
// mode: outline-minor
// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)"
// End: