mirror of https://gitee.com/bigwinds/arangodb
363 lines
11 KiB
C++
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:
|
|
|
|
|