1 2 /** 3 * Copyright (C) 2018-present MongoDB, Inc. 4 * 5 * This program is free software: you can redistribute it and/or modify 6 * it under the terms of the Server Side Public License, version 1, 7 * as published by MongoDB, Inc. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * Server Side Public License for more details. 13 * 14 * You should have received a copy of the Server Side Public License 15 * along with this program. If not, see 16 * <http://www.mongodb.com/licensing/server-side-public-license>. 17 * 18 * As a special exception, the copyright holders give permission to link the 19 * code of portions of this program with the OpenSSL library under certain 20 * conditions as described in each individual source file and distribute 21 * linked combinations including the program with the OpenSSL library. You 22 * must comply with the Server Side Public License in all respects for 23 * all of the code used other than as permitted herein. If you modify file(s) 24 * with this exception, you may extend this exception to your version of the 25 * file(s), but you are not obligated to do so. If you do not wish to do so, 26 * delete this exception statement from your version. If you delete this 27 * exception statement from all source files in the program, then also delete 28 * it in the license file. 29 */ 30 31 #pragma once 32 33 #include <cstdint> 34 35 #include "mongo/base/disallow_copying.h" 36 #include "mongo/base/string_data.h" 37 #include "mongo/bson/mutable/const_element.h" 38 #include "mongo/bson/mutable/damage_vector.h" 39 #include "mongo/bson/mutable/element.h" 40 #include "mongo/db/jsobj.h" 41 #include "mongo/util/safe_num.h" 42 43 namespace mongo { 44 namespace mutablebson { 45 46 /** Mutable BSON Overview 47 * 48 * Mutable BSON provides classes to facilitate the manipulation of existing BSON objects 49 * or the construction of new BSON objects from scratch in an incremental fashion. The 50 * operations (including additions, deletions, renamings, type changes and value 51 * modification) that are to be performed do not need to be known ahead of time, and do 52 * not need to occur in any particular order. This is in contrast to BSONObjBuilder and 53 * BSONArrayBuilder which offer only serialization and cannot revise already serialized 54 * data. If you need to build a BSONObj but you know upfront what you need to build then 55 * you should use BSONObjBuilder and BSONArrayBuilder directly as they will be faster and 56 * less resource intensive. 57 * 58 * The classes in this library (Document, Element, and ConstElement) present a tree-like 59 * (or DOM like) interface. Elements are logically equivalent to BSONElements: they carry 60 * a type, a field name, and a value. Every Element belongs to a Document, which roots the 61 * tree, and Elements of proper type (mongo::Object or mongo::Array) may have child 62 * Elements of their own. Given an Element, you may navigate to the Element's parent, to 63 * its siblings to the left or right of the Element in the tree, and to the leftmost or 64 * rightmost children of the Element. Note that some Elements may not offer all of these 65 * relationships: An Element that represents a terminal BSON value (like an integer) will 66 * not have children (though it may well have siblings). Similarly, an Element that is an 67 * 'only child' will not have any left or right siblings. Given a Document, you may begin 68 * navigating by obtaining the root Element of the tree by calling Document::root. See the 69 * documentation for the Element class for the specific navigation methods that will be 70 * available from the root Element. 71 * 72 * Elements within the Document may be modified in various ways: the value of the Element 73 * may be changed, the Element may be removed, it may be renamed, and if it is eligible 74 * for children (i.e. it represents a mongo::Array or mongo::Object) it may have child 75 * Elements added to it. Once you have completed building or modifying the Document, you 76 * may write it back out to a BSONObjBuilder by calling Document::writeTo. You may also 77 * serialize individual Elements within the Document to BSONObjBuilder or BSONArrayBuilder 78 * objects by calling Element::writeTo or Element::writeArrayTo. 79 * 80 * In addition to the above capabilities, there are algorithms provided in 'algorithm.h' 81 * to help with tasks like searching for Elements that match a predicate or for sorting 82 * the children of an Object Element. 83 * 84 * Example 1: Building up a document from scratch, reworking it, and then serializing it: 85 86 namespace mmb = mongo::mutablebson; 87 // Create a new document 88 mmb::Document doc; 89 // doc contents: '{}' 90 91 // Get the root of the document. 92 mmb::Element root = doc.root(); 93 94 // Create a new mongo::NumberInt typed Element to represent life, the universe, and 95 // everything, then push that Element into the root object, making it a child of root. 96 mmb::Element e0 = doc.makeElementInt("ltuae", 42); 97 root.pushBack(e0); 98 // doc contents: '{ ltuae : 42 }' 99 100 // Create a new empty mongo::Object-typed Element named 'magic', and push it back as a 101 // child of the root, making it a sibling of e0. 102 mmb::Element e1 = doc.makeElementObject("magic"); 103 root.pushBack(e1); 104 // doc contents: '{ ltuae : 42, magic : {} }' 105 106 // Create a new mongo::NumberDouble typed Element to represent Pi, and insert it as child 107 // of the new object we just created. 108 mmb::Element e3 = doc.makeElementDouble("pi", 3.14); 109 e1.pushBack(e3); 110 // doc contents: '{ ltuae : 42, magic : { pi : 3.14 } }' 111 112 // Create a new mongo::NumberDouble to represent Plancks constant in electrovolt 113 // micrometers, and add it as a child of the 'magic' object. 114 mmb::Element e4 = doc.makeElementDouble("hbar", 1.239); 115 e1.pushBack(e4); 116 // doc contents: '{ ltuae : 42, magic : { pi : 3.14, hbar : 1.239 } }' 117 118 // Rename the parent element of 'hbar' to be 'constants'. 119 e4.parent().rename("constants"); 120 // doc contents: '{ ltuae : 42, constants : { pi : 3.14, hbar : 1.239 } }' 121 122 // Rename 'ltuae' to 'answer' by accessing it as the root objects left child. 123 doc.root().leftChild().rename("answer"); 124 // doc contents: '{ answer : 42, constants : { pi : 3.14, hbar : 1.239 } }' 125 126 // Sort the constants by name. 127 mmb::sortChildren(doc.root().rightChild(), mmb::FieldNameLessThan()); 128 // doc contents: '{ answer : 42, constants : { hbar : 1.239, pi : 3.14 } }' 129 130 mongo::BSONObjBuilder builder; 131 doc.writeTo(&builder); 132 mongo::BSONObj result = builder.obj(); 133 // result contents: '{ answer : 42, constants : { hbar : 1.239, pi : 3.14 } }' 134 135 * While you can use this library to build Documents from scratch, its real purpose is to 136 * manipulate existing BSONObjs. A BSONObj may be passed to the Document constructor or to 137 * Document::make[Object|Array]Element, in which case the Document or Element will reflect 138 * the values contained within the provided BSONObj. Modifications will not alter the 139 * underlying BSONObj: they are held off to the side within the Document. However, when 140 * the Document is subsequently written back out to a BSONObjBuilder, the modifications 141 * applied to the Document will be reflected in the serialized version. 142 * 143 * Example 2: Modifying an existing BSONObj (some error handling removed for length) 144 145 namespace mmb = mongo::mutablebson; 146 147 static const char inJson[] = 148 "{" 149 " 'whale': { 'alive': true, 'dv': -9.8, 'height': 50, attrs : [ 'big' ] }," 150 " 'petunias': { 'alive': true, 'dv': -9.8, 'height': 50 } " 151 "}"; 152 mongo::BSONObj obj = mongo::fromjson(inJson); 153 154 // Create a new document representing the BSONObj with the above contents. 155 mmb::Document doc(obj); 156 157 // The whale hits the planet and dies. 158 mmb::Element whale = mmb::findFirstChildNamed(doc.root(), "whale"); 159 // Find the 'dv' field in the whale. 160 mmb::Element whale_deltav = mmb::findFirstChildNamed(whale, "dv"); 161 // Set the dv field to zero. 162 whale_deltav.setValueDouble(0.0); 163 // Find the 'height' field in the whale. 164 mmb::Element whale_height = mmb::findFirstChildNamed(whale, "height"); 165 // Set the height field to zero. 166 whale_deltav.setValueDouble(0); 167 // Find the 'alive' field, and set it to false. 168 mmb::Element whale_alive = mmb::findFirstChildNamed(whale, "alive"); 169 whale_alive.setValueBool(false); 170 171 // The petunias survive, update its fields much like we did above. 172 mmb::Element petunias = mmb::findFirstChildNamed(doc.root(), "petunias"); 173 mmb::Element petunias_deltav = mmb::findFirstChildNamed(petunias, "dv"); 174 petunias_deltav.setValueDouble(0.0); 175 mmb::Element petunias_height = mmb::findFirstChildNamed(petunias, "height"); 176 petunias_deltav.setValueDouble(0); 177 178 // Replace the whale by its wreckage, saving only its attributes: 179 // Construct a new mongo::Object element for the ex-whale. 180 mmb::Element ex_whale = doc.makeElementObject("ex-whale"); 181 doc.root().pushBack(ex_whale); 182 // Find the attributes of the old 'whale' element. 183 mmb::Element whale_attrs = mmb::findFirstChildNamed(whale, "attrs"); 184 // Remove the attributes from the whale (they remain valid, but detached). 185 whale_attrs.remove(); 186 // Add the attributes into the ex-whale. 187 ex_whale.pushBack(whale_attrs); 188 // Remove the whale object. 189 whale.remove(); 190 191 // Current state of document: 192 "{" 193 " 'petunias': { 'alive': true, 'dv': 0.0, 'height': 50 }," 194 " 'ex-whale': { 'attrs': [ 'big' ] } })" 195 "}"; 196 197 * Both of the above examples are derived from tests in mutable_bson_test.cpp, see the 198 * tests Example1 and Example2 if you would like to play with the code. 199 * 200 * Additional details on Element and Document are available in their class and member 201 * comments. 202 */ 203 204 /** Document is the entry point into the mutable BSON system. It has a fairly simple 205 * API. It acts as an owner for the Element resources of the document, provides a 206 * pre-constructed designated root Object Element, and acts as a factory for new Elements, 207 * which may then be attached to the root or to other Elements by calling the appropriate 208 * topology mutation methods in Element. 209 * 210 * The default constructor builds an empty Document which you may then extend by creating 211 * new Elements and manipulating the tree topology. It is also possible to build a 212 * Document that derives its initial values from a BSONObj. The given BSONObj will not be 213 * modified, but it also must not be modified elsewhere while Document is using it. Unlike 214 * all other calls in this library where a BSONObj is passed in, the one argument Document 215 * constructor *does not copy* the BSONObj's contents, so they must remain valid for the 216 * duration of Documents lifetime. Document does hold a copy of the BSONObj itself, so it 217 * will up the refcount if the BSONObj internals are counted. 218 * 219 * Newly constructed Elements formed by calls to 'makeElement[Type]' methods are not 220 * attached to the root of the document. You must explicitly attach them somewhere. If you 221 * lose the Element value that is returned to you from a 'makeElement' call before you 222 * attach it to the tree then the value will be unreachable. Elements in a document do not 223 * outlive the Document. 224 * 225 * Document provides a convenience method to serialize all of the Elements in the tree 226 * that are reachable from the root element to a BSONObjBuilder. In general you should use 227 * this in preference to root().writeTo() if you mean to write the entire 228 * Document. Similarly, Document provides wrappers for comparisons that simply delegate to 229 * comparison operations on the root Element. 230 * 231 * A 'const Document' is very limited: you may only write its contents out or obtain a 232 * ConstElement for the root. ConstElement is much like Element, but does not permit 233 * mutations. See the class comment for ConstElement for more information. 234 */ 235 class Document { 236 // TODO: In principle there is nothing that prevents implementing a deep copy for 237 // Document, but for now it is not permitted. 238 MONGO_DISALLOW_COPYING(Document); 239 240 public: 241 // 242 // Lifecycle 243 // 244 245 /** Construct a new empty document. */ 246 Document(); 247 248 enum InPlaceMode { 249 kInPlaceDisabled = 0, 250 kInPlaceEnabled = 1, 251 }; 252 253 /** Construct new document for the given BSONObj. The data in 'value' is NOT copied. By 254 * default, queueing of in-place modifications against the underlying document is 255 * permitted. To disable this behavior, explicitly pass kInPlaceDisabled. 256 */ 257 explicit Document(const BSONObj& value, InPlaceMode inPlaceMode = kInPlaceEnabled); 258 259 /** Abandon all internal state associated with this Document, and return to a state 260 * semantically equivalent to that yielded by a call to the default constructor. All 261 * objects associated with the current document state are invalidated (e.g. Elements, 262 * BSONElements, BSONObj's values, field names, etc.). This method is useful because 263 * it may (though it is not required to) preserve the memory allocation of the 264 * internal data structures of Document. If you need to logically create and destroy 265 * many Documents in serial, it may be faster to reset. 266 */ 267 void reset(); 268 269 /** As the no argument 'reset', but returns to a state semantically equivalent to that 270 * yielded by a call to the two argument constructor with the arguments provided 271 * here. As with the other 'reset' call, all associated objects are invalidated. */ 272 void reset(const BSONObj& value, InPlaceMode inPlaceMode = kInPlaceEnabled); 273 274 /** Destroy this document permanently */ 275 ~Document(); 276 277 278 // 279 // Comparison API 280 // 281 282 /** Compare this Document to 'other' with the semantics of BSONObj::woCompare. */ 283 inline int compareWith(const Document& other, 284 const StringData::ComparatorInterface* comparator, 285 bool considerFieldName = true) const; 286 287 /** Compare this Document to 'other' with the semantics of BSONObj::woCompare. */ 288 inline int compareWithBSONObj(const BSONObj& other, 289 const StringData::ComparatorInterface* comparator, 290 bool considerFieldName = true) const; 291 292 293 // 294 // Serialization API 295 // 296 297 /** Serialize the Elements reachable from the root Element of this Document to the 298 * provided builder. 299 */ 300 inline void writeTo(BSONObjBuilder* builder) const; 301 302 /** Serialize the Elements reachable from the root Element of this Document and return 303 * the result as a BSONObj. 304 */ 305 inline BSONObj getObject() const; 306 307 308 // 309 // Element creation API. 310 // 311 // Newly created elements are not attached to the tree (effectively, they are 312 // 'roots'). You must call one of the topology management methods in 'Element' to 313 // connect the newly created Element to another Element in the Document, possibly the 314 // Element referenced by Document::root. Elements do not outlive the Document. 315 // 316 317 /** Create a new double Element with the given value and field name. */ 318 Element makeElementDouble(StringData fieldName, double value); 319 320 /** Create a new std::string Element with the given value and field name. */ 321 Element makeElementString(StringData fieldName, StringData value); 322 323 /** Create a new empty object Element with the given field name. */ 324 Element makeElementObject(StringData fieldName); 325 326 /** Create a new object Element with the given field name. The data in 'value' is 327 * copied. 328 */ 329 Element makeElementObject(StringData fieldName, const BSONObj& value); 330 331 /** Create a new empty array Element with the given field name. */ 332 Element makeElementArray(StringData fieldName); 333 334 /** Create a new array Element with the given field name. The data in 'value' is 335 * copied. 336 */ 337 Element makeElementArray(StringData fieldName, const BSONObj& value); 338 339 /** Create a new binary Element with the given data and field name. */ 340 Element makeElementBinary(StringData fieldName, 341 uint32_t len, 342 BinDataType binType, 343 const void* data); 344 345 /** Create a new undefined Element with the given field name. */ 346 Element makeElementUndefined(StringData fieldName); 347 348 /** Create a new OID + Element with the given field name. */ 349 Element makeElementNewOID(StringData fieldName); 350 351 /** Create a new OID Element with the given value and field name. */ 352 Element makeElementOID(StringData fieldName, mongo::OID value); 353 354 /** Create a new bool Element with the given value and field name. */ 355 Element makeElementBool(StringData fieldName, bool value); 356 357 /** Create a new date Element with the given value and field name. */ 358 Element makeElementDate(StringData fieldName, Date_t value); 359 360 /** Create a new null Element with the given field name. */ 361 Element makeElementNull(StringData fieldName); 362 363 /** Create a new regex Element with the given data and field name. */ 364 Element makeElementRegex(StringData fieldName, StringData regex, StringData flags); 365 366 /** Create a new DBRef Element with the given data and field name. */ 367 Element makeElementDBRef(StringData fieldName, StringData ns, mongo::OID oid); 368 369 /** Create a new code Element with the given value and field name. */ 370 Element makeElementCode(StringData fieldName, StringData value); 371 372 /** Create a new symbol Element with the given value and field name. */ 373 Element makeElementSymbol(StringData fieldName, StringData value); 374 375 /** Create a new scoped code Element with the given data and field name. */ 376 Element makeElementCodeWithScope(StringData fieldName, StringData code, const BSONObj& scope); 377 378 /** Create a new integer Element with the given value and field name. */ 379 Element makeElementInt(StringData fieldName, int32_t value); 380 381 /** Create a new timestamp Element with the given value and field name. */ 382 Element makeElementTimestamp(StringData fieldName, Timestamp value); 383 384 /** Create a new long integer Element with the given value and field name. */ 385 Element makeElementLong(StringData fieldName, int64_t value); 386 387 /** Create a new dec128 Element with the given value and field name. */ 388 Element makeElementDecimal(StringData fieldName, Decimal128 value); 389 390 /** Create a new min key Element with the given field name. */ 391 Element makeElementMinKey(StringData fieldName); 392 393 /** Create a new max key Element with the given field name. */ 394 Element makeElementMaxKey(StringData fieldName); 395 396 397 // 398 // Element creation methods from variant types 399 // 400 401 /** Construct a new Element with the same name, type, and value as the provided 402 * BSONElement. The value is copied. 403 */ 404 Element makeElement(const BSONElement& elt); 405 406 /** Construct a new Element with the same type and value as the provided BSONElement, 407 * but with a new name. The value is copied. 408 */ 409 Element makeElementWithNewFieldName(StringData fieldName, const BSONElement& elt); 410 411 /** Create a new element of the appopriate type to hold the given value, with the given 412 * field name. 413 */ 414 Element makeElementSafeNum(StringData fieldName, SafeNum value); 415 416 /** Construct a new element with the same name, type, and value as the provided mutable 417 * Element. The data is copied from the given Element. Unlike most methods in this 418 * class the provided Element may be from a different Document. 419 */ 420 Element makeElement(ConstElement elt); 421 422 /** Construct a new Element with the same type and value as the provided mutable 423 * Element, but with a new field name. The data is copied from the given 424 * Element. Unlike most methods in this class the provided Element may be from a 425 * different Document. 426 */ 427 Element makeElementWithNewFieldName(StringData fieldName, ConstElement elt); 428 429 // 430 // Accessors 431 // 432 433 /** Returns the root element for this document. */ 434 inline Element root(); 435 436 /** Returns the root element for this document. */ 437 inline ConstElement root() const; 438 439 /** Returns an element that will compare equal to a non-ok element. */ 440 inline Element end(); 441 442 /** Returns an element that will compare equal to a non-ok element. */ 443 inline ConstElement end() const; 444 445 inline std::string toString() const; 446 447 // 448 // In-place API. 449 // 450 451 /** Ensure that at least 'expectedEvents' damage events can be recorded for in-place 452 * mutations without reallocation. This call is ignored if damage events are disabled. 453 */ 454 void reserveDamageEvents(size_t expectedEvents); 455 456 /** Request a vector of damage events describing in-place updates to this Document. If 457 * the modifications to this Document were not all able to be achieved in-place, then 458 * a non-OK Status is returned, and the provided damage vector will be made empty and 459 * *source set equal to NULL. Otherwise, the provided damage vector is populated, and 460 * the 'source' argument is set to point to a region from which bytes can be read. The 461 * 'source' offsets in the damage vector are to be interpreted as offsets within this 462 * region. If the 'size' parameter is non-null and 'source' is set to a non-NULL 463 * value, then size will be filled in with the size of the 'source' region to 464 * facilitate making an owned copy of the source data, in the event that that is 465 * needed. 466 * 467 * The lifetime of the source region should be considered to extend only from the 468 * return from this call to before the next API call on this Document or any of its 469 * member Elements. That is almost certainly overly conservative: some read only calls 470 * are undoubtedly fine. But it is very easy to invalidate 'source' by calling any 471 * mutating operation, so proceed with due caution. 472 * 473 * It is expected, though, that in normal modes of operation obtainin the damage 474 * vector is one of the last operations performed on a Document before its 475 * destruction, so this is not so great a restriction. 476 * 477 * The destination offsets in the damage events are implicitly offsets into the 478 * BSONObj used to construct this Document. 479 */ 480 bool getInPlaceUpdates(DamageVector* damages, const char** source, size_t* size = NULL); 481 482 /** Drop the queue of in-place update damage events, and do not queue new operations 483 * that would otherwise have been in-place. Use this if you know that in-place updates 484 * will not continue to be possible and do not want to pay the overhead of 485 * speculatively queueing them. After calling this method, getInPlaceUpdates will 486 * return a non-OK Status. It is not possible to re-enable in-place updates once 487 * disabled. 488 */ 489 void disableInPlaceUpdates(); 490 491 /** Returns the current in-place mode for the document. Note that for some documents, 492 * like those created without any backing BSONObj, this will always return kForbidden, 493 * since in-place updates make no sense for such an object. In other cases, an object 494 * which started in kInPlacePermitted mode may transition to kInPlaceForbidden if a 495 * topology mutating operation is applied. 496 */ 497 InPlaceMode getCurrentInPlaceMode() const; 498 499 /** A convenience routine, this returns true if the current in-place mode is 500 * kInPlaceEnabled, and false otherwise. 501 */ 502 inline bool isInPlaceModeEnabled() const; 503 504 private: 505 friend class Element; 506 507 // For now, the implementation of Document is firewalled. 508 class Impl; 509 inline Impl& getImpl(); 510 inline const Impl& getImpl() const; 511 512 Element makeRootElement(); 513 Element makeRootElement(const BSONObj& value); 514 Element makeElement(ConstElement element, const StringData* fieldName); 515 516 const std::unique_ptr<Impl> _impl; 517 518 // The root element of this document. 519 const Element _root; 520 }; 521 522 } // namespace mutablebson 523 } // namespace mongo 524 525 #include "mongo/bson/mutable/document-inl.h" 526