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