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/status.h" 36 #include "mongo/base/string_data.h" 37 #include "mongo/db/jsobj.h" 38 #include "mongo/util/safe_num.h" 39 40 namespace mongo { 41 namespace mutablebson { 42 43 /** For an overview of mutable BSON, please see the file document.h in this directory. */ 44 45 class ConstElement; 46 class Document; 47 48 /** Element represents a BSON value or object in a mutable BSON Document. The lifetime of 49 * an Element is a subset of the Document to which it belongs. Much like a BSONElement, an 50 * Element has a type, a field name, and (usually) a value. An Element may be used to read 51 * or modify the value (including changing its type), to navigate to related Elements in 52 * the Document tree, or for a number of topological changes to the Document 53 * structure. Element also offers the ability to compare its value to that of other 54 * Elements, and to serialize its value to a BSONObjBuilder or BSONArrayBuilder. 55 * 56 * Elements have reference or iterator like semantics, and are very lightweight. You 57 * should not worry about the cost of passing an Element by value, copying an Element, or 58 * similar operations. Such operations do not mean that the logical element in the 59 * underlying Document is duplicated. Only the reference is duplicated. 60 * 61 * The API for Element is broken into several sections: 62 * 63 * - Topology mutation: These methods are to either add other Elements to the Document 64 * tree as siblings or children (when applicable) of the current Element, to remove the 65 * Element from the tree, or to remove children of the Element (when applicable). 66 * 67 * - Navigation: These methods are used to navigate the Document tree by returning other 68 * Elements in specified relationships to the current Element. In this regard, Elements 69 * act much like STL iterators that walk over the Document tree. One important 70 * difference is that Elements are never invalidated, even when 'remove' is called. If 71 * you have two Elements that alias the same element in the Document tree, modifications 72 * through one Element will be visible via the other. 73 * 74 * - Value access: These methods provide access to the value in the Document tree that the 75 * current Element represents. All leaf (a.k.a. 'primitive', or non-Object and 76 * non-Array) like Elements will always be able to provide a value. However, there are 77 * cases where non-leaf Elements (representing Objects or Arrays) cannot provide a 78 * value. Therefore, you must always call 'hasValue' to determine if the value is 79 * available before calling 'getValue'. Similarly, you must determine the type of the 80 * Element by calling getType() and only call the matching typed getValue. 81 * 82 * - Comparison: It is possible to compare one Element with another to determine ordering 83 * or equality as defined by woCompare. Similarly, it is possible to directly compare an 84 * Element with a BSONElement. It is legal to compare two Elements which belong to 85 * different Documents. 86 * 87 * - Serialization: Elements may be serialized to BSONObjBuilder or to BSONArrayBuilder 88 * objects when appropriate. One detail to consider is that writeTo for the root Element 89 * behaves differently than the others: it does not start a new subobj scope in the 90 * builder, so all of its children will be added at the current level to the 91 * builder. The provided builder does not have its 'done' method called automatically. 92 * 93 * - Value mutation: You may freely modify the value of an Element, including 94 * modifications that change the type of the Element and setting the value of the 95 * Element to the value of another BSONObj. You may also set the value from a SafeNum or 96 * from a BSONElement. 97 * 98 * - Accessors: These provide access to various properties of the Element, like the 99 * Document to which the Element belongs, the BSON type and field name of the Element, 100 * etc. One critical accessor is 'ok'. When using the topology API to navigate a 101 * document, it is possible to request an Element which does not exist, like the parent 102 * of the root element, or the left child of an integer, or the right sibling of the 103 * last element in an array. In these cases, the topology API will return an Element for 104 * which the 'ok' accessor will return 'false', which is roughly analagous to an 'end' 105 * valued STL iterator. It is illegal to call any method (other than 'ok') on a non-OK 106 * Element. 107 * 108 * - Streaming API: As a convenience for when you are building Documents from scratch, an 109 * API is provided that combines the effects of calling makeElement on the Document with 110 * calling pushBack on the current Element. The effect is to create the element and make 111 * it the new rightmost child of this Element. Use of this API is discouraged and it may 112 * be removed. 113 */ 114 115 class Element { 116 public: 117 typedef uint32_t RepIdx; 118 119 // Some special RepIdx values. These are really implementation details, but they are 120 // here so that we can inline Element::OK, which gets called very frequently, and they 121 // need to be public so some free functions in document.cpp can use them. You must not 122 // use these values explicitly. 123 124 // Used to signal an invalid Element. 125 static const RepIdx kInvalidRepIdx = RepIdx(-1); 126 127 // A rep that points to an unexamined entity 128 static const RepIdx kOpaqueRepIdx = RepIdx(-2); 129 130 // This is the highest valid rep that does not overlap flag values. 131 static const RepIdx kMaxRepIdx = RepIdx(-3); 132 133 // 134 // Topology mutation API. Element arguments must belong to the same Document. 135 // 136 137 /** Add the provided Element to the left of this Element. The added Element must be 138 * 'ok', and this Element must have a parent. 139 */ 140 Status addSiblingLeft(Element e); 141 142 /** Add the provided Element to the right of this Element. The added Element must be 143 * 'ok', and this Element must have a parent. 144 */ 145 Status addSiblingRight(Element e); 146 147 /** 'Remove' this Element by detaching it from its parent and siblings. The Element 148 * continues to exist and may be manipulated, but cannot be re-obtained by navigating 149 * from the root. 150 */ 151 Status remove(); 152 153 /** If this Element is empty, add 'e' as the first child. Otherwise, add 'e' as the new 154 * left child. 155 */ 156 Status pushFront(Element e); 157 158 /** If this Element is empty, add 'e' as the first child. Otherwise, add 'e' as the new 159 * right child. 160 */ 161 Status pushBack(Element e); 162 163 /** Remove the leftmost child Element if it exists, otherwise return an error. */ 164 Status popFront(); 165 166 /** Remove the rightmost child Element if it exists, otherwise return an error. */ 167 Status popBack(); 168 169 /** Rename this Element to the provided name. */ 170 Status rename(StringData newName); 171 172 173 // 174 // Navigation API. 175 // 176 177 /** Returns either this Element's left child, or a non-ok Element if no left child 178 * exists. 179 */ 180 Element leftChild() const; 181 182 /** Returns either this Element's right child, or a non-ok Element if no right child 183 * exists. Note that obtaining the right child may require realizing all immediate 184 * child nodes of a document that is being consumed lazily. 185 */ 186 Element rightChild() const; 187 188 /** Returns true if this element has children. Always returns false if this Element is 189 * not an Object or Array. 190 */ 191 bool hasChildren() const; 192 193 /** Returns either this Element's sibling 'distance' elements to the left, or a non-ok 194 * Element if no such left sibling exists. 195 */ 196 Element leftSibling(size_t distance = 1) const; 197 198 /** Returns either this Element's sibling 'distance' Elements to the right, or a non-ok 199 * Element if no such right sibling exists. 200 */ 201 Element rightSibling(size_t distance = 1) const; 202 203 /** Returns this Element's parent, or a non-ok Element if this Element has no parent 204 * (is a root). 205 */ 206 Element parent() const; 207 208 /** Returns the nth child, if any, of this Element. If no such element exists, a non-ok 209 * Element is returned. This is not a constant time operation. This method is also 210 * available as operator[] taking a size_t for convenience. 211 */ 212 Element findNthChild(size_t n) const; 213 inline Element operator[](size_t n) const; 214 215 /** Returns the first child, if any, of this Element named 'name'. If no such Element 216 * exists, a non-ok Element is returned. This is not a constant time operation. It is illegal 217 * to call this on an Array. This method is also available as operator[] taking a StringData 218 * for convenience. 219 */ 220 Element findFirstChildNamed(StringData name) const; 221 inline Element operator[](StringData name) const; 222 223 /** Returns the first element found named 'name', starting the search at the current 224 * Element, and walking right. If no such Element exists, a non-ok Element is 225 * returned. This is not a constant time operation. This implementation is used in the 226 * specialized implementation of findElement<ElementType, FieldNameEquals>. 227 */ 228 Element findElementNamed(StringData name) const; 229 230 // 231 // Counting API. 232 // 233 234 /** Returns the number of valid siblings to the left of this Element. */ 235 size_t countSiblingsLeft() const; 236 237 /** Returns the number of valid siblings to the right of this Element. */ 238 size_t countSiblingsRight() const; 239 240 /** Return the number of children of this Element. */ 241 size_t countChildren() const; 242 243 // 244 // Value access API. 245 // 246 // We only provide accessors for BSONElement and for simple types. For more complex 247 // types like regex you should obtain the BSONElement and use that API to extract the 248 // components. 249 // 250 // Note that the getValueX methods are *unchecked* in release builds: You are 251 // responsible for calling hasValue() to ensure that this element has a value 252 // representation, and for calling getType to ensure that the Element is of the proper 253 // type. 254 // 255 // As usual, methods here are in bsonspec type order, please keep them that way. 256 // 257 258 /** Returns true if 'getValue' can return a valid BSONElement from which a value may be 259 * extracted. See the notes for 'getValue' to understand the conditions under which an 260 * Element can provide a BSONElement. 261 */ 262 bool hasValue() const; 263 264 /** Returns true if this element is a numeric type (e.g. NumberLong). Currently, the 265 * only numeric BSON types are NumberLong, NumberInt, NumberDouble, and NumberDecimal. 266 */ 267 bool isNumeric() const; 268 269 /** Returns true if this element is one of the integral numeric types (e.g. NumberLong 270 * or NumberInt). 271 */ 272 bool isIntegral() const; 273 274 /** Get the value of this element if available. Note that not all elements have a 275 * representation as a BSONElement. For elements that do have a representation, this 276 * will return it. For elements that do not this method returns an eoo 277 * BSONElement. All 'value-ish' Elements will have a BSONElement 278 * representation. 'Tree-ish' Elements may or may not have a BSONElement 279 * representation. Mutations may cause elements to change whether or not they have a 280 * value and may invalidate previously returned values. 281 * 282 * Please note that a const BSONElement allows retrieval of a non-const 283 * BSONObj. However, the contents of the BSONElement returned here must be treated as 284 * const. 285 */ 286 const BSONElement getValue() const; 287 288 /** Get the value from a double valued Element. */ 289 inline double getValueDouble() const; 290 291 /** Get the value from a std::string valued Element. */ 292 inline StringData getValueString() const; 293 294 /** Get the value from an object valued Element. Note that this may not always be 295 * possible! 296 */ 297 inline BSONObj getValueObject() const; 298 299 /** Get the value from an object valued Element. Note that this may not always be 300 * possible! 301 */ 302 inline BSONArray getValueArray() const; 303 304 /** Returns true if this Element is the undefined type. */ 305 inline bool isValueUndefined() const; 306 307 /** Get the value from an OID valued Element. */ 308 inline OID getValueOID() const; 309 310 /** Get the value from a bool valued Element. */ 311 inline bool getValueBool() const; 312 313 /** Get the value from a date valued Element. */ 314 inline Date_t getValueDate() const; 315 316 /** Returns true if this Element is the null type. */ 317 inline bool isValueNull() const; 318 319 /** Get the value from a symbol valued Element. */ 320 inline StringData getValueSymbol() const; 321 322 /** Get the value from an int valued Element. */ 323 inline int32_t getValueInt() const; 324 325 /** Get the value from a timestamp valued Element. */ 326 inline Timestamp getValueTimestamp() const; 327 328 /** Get the value from a long valued Element. */ 329 inline int64_t getValueLong() const; 330 331 /** Get the value from a decimal valued Element. */ 332 inline Decimal128 getValueDecimal() const; 333 334 /** Returns true if this Element is the min key type. */ 335 inline bool isValueMinKey() const; 336 337 /** Returns true if this Element is the max key type. */ 338 inline bool isValueMaxKey() const; 339 340 /** Returns the numeric value as a SafeNum */ 341 SafeNum getValueSafeNum() const; 342 343 344 // 345 // Comparision API. 346 // 347 348 /** Compare this Element with Element 'other'. The two Elements may belong to different 349 * Documents. You should not call this on the root Element of the Document because the 350 * root Element does not have a field name. Use compareWithBSONObj to handle that 351 * case. 352 * 353 * Returns -1 if this < other according to BSONElement::woCompare 354 * Returns 0 if this == other either tautologically, or according to woCompare. 355 * Returns 1 if this > other according to BSONElement::woCompare 356 */ 357 int compareWithElement(const ConstElement& other, 358 const StringData::ComparatorInterface* comparator, 359 bool considerFieldName = true) const; 360 361 /** Compare this Element with BSONElement 'other'. You should not call this on the root 362 * Element of the Document because the root Element does not have a field name. Use 363 * compareWithBSONObj to handle that case. 364 * 365 * Returns -1 if this < other according to BSONElement::woCompare 366 * Returns 0 if this == other either tautologically, or according to woCompare. 367 * Returns 1 if this > other according to BSONElement::woCompare 368 */ 369 int compareWithBSONElement(const BSONElement& other, 370 const StringData::ComparatorInterface* comparator, 371 bool considerFieldName = true) const; 372 373 /** Compare this Element, which must be an Object or an Array, with 'other'. 374 * 375 * Returns -1 if this object < other according to BSONElement::woCompare 376 * Returns 0 if this object == other either tautologically, or according to woCompare. 377 * Returns 1 if this object > other according to BSONElement::woCompare 378 */ 379 int compareWithBSONObj(const BSONObj& other, 380 const StringData::ComparatorInterface* comparator, 381 bool considerFieldName = true) const; 382 383 384 // 385 // Serialization API. 386 // 387 388 /** Write this Element to the provided object builder. */ 389 void writeTo(BSONObjBuilder* builder) const; 390 391 /** Write this Element to the provided array builder. This Element must be of type 392 * mongo::Array. 393 */ 394 void writeArrayTo(BSONArrayBuilder* builder) const; 395 396 397 // 398 // Value mutation API. Please note that the types are ordered according to bsonspec.org 399 // ordering. Please keep them that way. 400 // 401 402 /** Set the value of this Element to the given double. */ 403 Status setValueDouble(double value); 404 405 /** Set the value of this Element to the given string. */ 406 Status setValueString(StringData value); 407 408 /** Set the value of this Element to the given object. The data in 'value' is 409 * copied. 410 */ 411 Status setValueObject(const BSONObj& value); 412 413 /** Set the value of this Element to the given object. The data in 'value' is 414 * copied. 415 */ 416 Status setValueArray(const BSONObj& value); 417 418 /** Set the value of this Element to the given binary data. */ 419 Status setValueBinary(uint32_t len, mongo::BinDataType binType, const void* data); 420 421 /** Set the value of this Element to Undefined. */ 422 Status setValueUndefined(); 423 424 /** Set the value of this Element to the given OID. */ 425 Status setValueOID(OID value); 426 427 /** Set the value of this Element to the given boolean. */ 428 Status setValueBool(bool value); 429 430 /** Set the value of this Element to the given date. */ 431 Status setValueDate(Date_t value); 432 433 /** Set the value of this Element to Null. */ 434 Status setValueNull(); 435 436 /** Set the value of this Element to the given regex parameters. */ 437 Status setValueRegex(StringData re, StringData flags); 438 439 /** Set the value of this Element to the given db ref parameters. */ 440 Status setValueDBRef(StringData ns, OID oid); 441 442 /** Set the value of this Element to the given code data. */ 443 Status setValueCode(StringData value); 444 445 /** Set the value of this Element to the given symbol. */ 446 Status setValueSymbol(StringData value); 447 448 /** Set the value of this Element to the given code and scope data. */ 449 Status setValueCodeWithScope(StringData code, const BSONObj& scope); 450 451 /** Set the value of this Element to the given integer. */ 452 Status setValueInt(int32_t value); 453 454 /** Set the value of this Element to the given timestamp. */ 455 Status setValueTimestamp(Timestamp value); 456 457 /** Set the value of this Element to the given long integer */ 458 Status setValueLong(int64_t value); 459 460 /** Set the value of this Element to the given decimal. */ 461 Status setValueDecimal(Decimal128 value); 462 463 /** Set the value of this Element to MinKey. */ 464 Status setValueMinKey(); 465 466 /** Set the value of this Element to MaxKey. */ 467 Status setValueMaxKey(); 468 469 470 // 471 // Value mutation API from variant types. 472 // 473 474 /** Set the value of this element to equal the value of the provided BSONElement 475 * 'value'. The name of this Element is not modified. 476 * 477 * The contents of value are copied. 478 */ 479 Status setValueBSONElement(const BSONElement& value); 480 481 /** Set the value of this Element to a numeric type appropriate to hold the given 482 * SafeNum value. 483 */ 484 Status setValueSafeNum(const SafeNum value); 485 486 /** Set the value of this Element to the value from another Element. 487 * 488 * The name of this Element is not modified. 489 */ 490 Status setValueElement(ConstElement setFrom); 491 492 493 // 494 // Accessors 495 // 496 497 /** Returns true if this Element represents a valid part of the Document. */ 498 inline bool ok() const; 499 500 /** Returns the Document to which this Element belongs. */ 501 inline Document& getDocument(); 502 503 /** Returns the Document to which this Element belongs. */ 504 inline const Document& getDocument() const; 505 506 /** Returns the BSONType of this Element. */ 507 BSONType getType() const; 508 509 /** Returns true if this Element is of the specified type */ 510 inline bool isType(BSONType type) const; 511 512 /** Returns the field name of this Element. Note that the value returned here is not 513 * stable across mutations, since the storage for fieldNames may be reallocated. If 514 * you need a stable version of the fieldName, you must call toString on the returned 515 * StringData. 516 */ 517 StringData getFieldName() const; 518 519 /** Returns the opaque ID for this element. This is unlikely to be useful to a caller 520 * and is mostly for testing. 521 */ 522 inline RepIdx getIdx() const; 523 524 525 // 526 // Stream API - BSONObjBuilder like API, but methods return a Status. These are 527 // strictly a convenience API. You don't need to use them if you would rather be more 528 // explicit. 529 // 530 531 /** Append the provided double value as a new field with the provided name. */ 532 Status appendDouble(StringData fieldName, double value); 533 534 /** Append the provided std::string value as a new field with the provided name. */ 535 Status appendString(StringData fieldName, StringData value); 536 537 /** Append the provided object as a new field with the provided name. The data in 538 * 'value' is copied. 539 */ 540 Status appendObject(StringData fieldName, const BSONObj& value); 541 542 /** Append the provided array object as a new field with the provided name. The data in 543 * value is copied. 544 */ 545 Status appendArray(StringData fieldName, const BSONObj& value); 546 547 /** Append the provided binary data as a new field with the provided name. */ 548 Status appendBinary(StringData fieldName, 549 uint32_t len, 550 mongo::BinDataType binType, 551 const void* data); 552 553 /** Append an undefined value as a new field with the provided name. */ 554 Status appendUndefined(StringData fieldName); 555 556 /** Append the provided OID as a new field with the provided name. */ 557 Status appendOID(StringData fieldName, mongo::OID value); 558 559 /** Append the provided bool as a new field with the provided name. */ 560 Status appendBool(StringData fieldName, bool value); 561 562 /** Append the provided date as a new field with the provided name. */ 563 Status appendDate(StringData fieldName, Date_t value); 564 565 /** Append a null as a new field with the provided name. */ 566 Status appendNull(StringData fieldName); 567 568 /** Append the provided regex data as a new field with the provided name. */ 569 Status appendRegex(StringData fieldName, StringData re, StringData flags); 570 571 /** Append the provided DBRef data as a new field with the provided name. */ 572 Status appendDBRef(StringData fieldName, StringData ns, mongo::OID oid); 573 574 /** Append the provided code data as a new field with the iven name. */ 575 Status appendCode(StringData fieldName, StringData value); 576 577 /** Append the provided symbol data as a new field with the provided name. */ 578 Status appendSymbol(StringData fieldName, StringData value); 579 580 /** Append the provided code and scope data as a new field with the provided name. */ 581 Status appendCodeWithScope(StringData fieldName, StringData code, const BSONObj& scope); 582 583 /** Append the provided integer as a new field with the provided name. */ 584 Status appendInt(StringData fieldName, int32_t value); 585 586 /** Append the provided timestamp as a new field with the provided name. */ 587 Status appendTimestamp(StringData fieldName, Timestamp value); 588 589 /** Append the provided long integer as a new field with the provided name. */ 590 Status appendLong(StringData fieldName, int64_t value); 591 592 /** Append the provided decimal as a new field with the provided name. */ 593 Status appendDecimal(StringData fieldName, Decimal128 value); 594 595 /** Append a max key as a new field with the provided name. */ 596 Status appendMinKey(StringData fieldName); 597 598 /** Append a min key as a new field with the provided name. */ 599 Status appendMaxKey(StringData fieldName); 600 601 /** Append the given BSONElement. The data in 'value' is copied. */ 602 Status appendElement(const BSONElement& value); 603 604 /** Append the provided number as field of the appropriate numeric type with the 605 * provided name. 606 */ 607 Status appendSafeNum(StringData fieldName, SafeNum value); 608 609 /** Convert this element to its JSON representation if ok(), 610 * otherwise return !ok() message */ 611 std::string toString() const; 612 613 private: 614 friend class Document; 615 friend class ConstElement; 616 617 friend bool operator==(const Element&, const Element&); 618 619 inline Element(Document* doc, RepIdx repIdx); 620 621 Status addChild(Element e, bool front); 622 623 StringData getValueStringOrSymbol() const; 624 625 Status setValue(Element::RepIdx newValueIdx); 626 627 Document* _doc; 628 RepIdx _repIdx; 629 }; 630 631 /** Element comparison support. Comparison is like STL iterator comparision: equal Elements 632 * refer to the same underlying data. The equality does *not* mean that the underlying 633 * values are equivalent. Use the Element::compareWith methods to compare the represented 634 * data. 635 */ 636 637 /** Returns true if l and r refer to the same data, false otherwise. */ 638 inline bool operator==(const Element& l, const Element& r); 639 640 /** Returns false if l and r refer to the same data, true otherwise. */ 641 inline bool operator!=(const Element& l, const Element& r); 642 643 } // namespace mutablebson 644 } // namespace mongo 645 646 #include "mongo/bson/mutable/element-inl.h" 647