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