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 #include "mongo/platform/basic.h"
32 
33 #include "mongo/bson/mutable/element.h"
34 
35 #include "mongo/bson/mutable/algorithm.h"
36 #include "mongo/bson/mutable/document.h"
37 
38 namespace mongo {
39 namespace mutablebson {
40 
41 // Many of the methods of Element are actually implemented in document.cpp, since they need
42 // access to the firewalled implementation of Document.
43 
pushFront(Element e)44 Status Element::pushFront(Element e) {
45     return addChild(e, true);
46 }
47 
pushBack(Element e)48 Status Element::pushBack(Element e) {
49     return addChild(e, false);
50 }
51 
popFront()52 Status Element::popFront() {
53     Element left = leftChild();
54     if (!left.ok())
55         return Status(ErrorCodes::EmptyArrayOperation, "popFront on empty");
56     return left.remove();
57 }
58 
popBack()59 Status Element::popBack() {
60     Element right = rightChild();
61     if (!right.ok())
62         return Status(ErrorCodes::EmptyArrayOperation, "popBack on empty");
63     return right.remove();
64 }
65 
appendDouble(StringData fieldName,double value)66 Status Element::appendDouble(StringData fieldName, double value) {
67     return pushBack(getDocument().makeElementDouble(fieldName, value));
68 }
69 
appendString(StringData fieldName,StringData value)70 Status Element::appendString(StringData fieldName, StringData value) {
71     return pushBack(getDocument().makeElementString(fieldName, value));
72 }
73 
appendObject(StringData fieldName,const BSONObj & value)74 Status Element::appendObject(StringData fieldName, const BSONObj& value) {
75     return pushBack(getDocument().makeElementObject(fieldName, value));
76 }
77 
appendArray(StringData fieldName,const BSONObj & value)78 Status Element::appendArray(StringData fieldName, const BSONObj& value) {
79     return pushBack(getDocument().makeElementArray(fieldName, value));
80 }
81 
appendBinary(StringData fieldName,uint32_t len,mongo::BinDataType binType,const void * data)82 Status Element::appendBinary(StringData fieldName,
83                              uint32_t len,
84                              mongo::BinDataType binType,
85                              const void* data) {
86     return pushBack(getDocument().makeElementBinary(fieldName, len, binType, data));
87 }
88 
appendUndefined(StringData fieldName)89 Status Element::appendUndefined(StringData fieldName) {
90     return pushBack(getDocument().makeElementUndefined(fieldName));
91 }
92 
appendOID(StringData fieldName,const OID value)93 Status Element::appendOID(StringData fieldName, const OID value) {
94     return pushBack(getDocument().makeElementOID(fieldName, value));
95 }
96 
appendBool(StringData fieldName,bool value)97 Status Element::appendBool(StringData fieldName, bool value) {
98     return pushBack(getDocument().makeElementBool(fieldName, value));
99 }
100 
appendDate(StringData fieldName,Date_t value)101 Status Element::appendDate(StringData fieldName, Date_t value) {
102     return pushBack(getDocument().makeElementDate(fieldName, value));
103 }
104 
appendNull(StringData fieldName)105 Status Element::appendNull(StringData fieldName) {
106     return pushBack(getDocument().makeElementNull(fieldName));
107 }
108 
appendRegex(StringData fieldName,StringData re,StringData flags)109 Status Element::appendRegex(StringData fieldName, StringData re, StringData flags) {
110     return pushBack(getDocument().makeElementRegex(fieldName, re, flags));
111 }
112 
appendDBRef(StringData fieldName,StringData ns,const OID oid)113 Status Element::appendDBRef(StringData fieldName, StringData ns, const OID oid) {
114     return pushBack(getDocument().makeElementDBRef(fieldName, ns, oid));
115 }
116 
appendCode(StringData fieldName,StringData value)117 Status Element::appendCode(StringData fieldName, StringData value) {
118     return pushBack(getDocument().makeElementCode(fieldName, value));
119 }
120 
appendSymbol(StringData fieldName,StringData value)121 Status Element::appendSymbol(StringData fieldName, StringData value) {
122     return pushBack(getDocument().makeElementSymbol(fieldName, value));
123 }
124 
appendCodeWithScope(StringData fieldName,StringData code,const BSONObj & scope)125 Status Element::appendCodeWithScope(StringData fieldName, StringData code, const BSONObj& scope) {
126     return pushBack(getDocument().makeElementCodeWithScope(fieldName, code, scope));
127 }
128 
appendInt(StringData fieldName,int32_t value)129 Status Element::appendInt(StringData fieldName, int32_t value) {
130     return pushBack(getDocument().makeElementInt(fieldName, value));
131 }
132 
appendTimestamp(StringData fieldName,Timestamp value)133 Status Element::appendTimestamp(StringData fieldName, Timestamp value) {
134     return pushBack(getDocument().makeElementTimestamp(fieldName, value));
135 }
136 
appendDecimal(StringData fieldName,Decimal128 value)137 Status Element::appendDecimal(StringData fieldName, Decimal128 value) {
138     return pushBack(getDocument().makeElementDecimal(fieldName, value));
139 }
140 
appendLong(StringData fieldName,int64_t value)141 Status Element::appendLong(StringData fieldName, int64_t value) {
142     return pushBack(getDocument().makeElementLong(fieldName, value));
143 }
144 
appendMinKey(StringData fieldName)145 Status Element::appendMinKey(StringData fieldName) {
146     return pushBack(getDocument().makeElementMinKey(fieldName));
147 }
148 
appendMaxKey(StringData fieldName)149 Status Element::appendMaxKey(StringData fieldName) {
150     return pushBack(getDocument().makeElementMaxKey(fieldName));
151 }
152 
appendElement(const BSONElement & value)153 Status Element::appendElement(const BSONElement& value) {
154     return pushBack(getDocument().makeElement(value));
155 }
156 
appendSafeNum(StringData fieldName,SafeNum value)157 Status Element::appendSafeNum(StringData fieldName, SafeNum value) {
158     return pushBack(getDocument().makeElementSafeNum(fieldName, value));
159 }
160 
toString() const161 std::string Element::toString() const {
162     if (!ok())
163         return "INVALID-MUTABLE-ELEMENT";
164 
165     if (hasValue())
166         return getValue().toString();
167 
168     const BSONType type = getType();
169 
170     // The only types that sometimes don't have a value are Object and Array nodes.
171     dassert((type == mongo::Object) || (type == mongo::Array));
172 
173     if (type == mongo::Object) {
174         BSONObjBuilder builder;
175         writeTo(&builder);
176         BSONObj obj = builder.obj();
177         return obj.firstElement().toString();
178     } else {
179         // It must be an array.
180         BSONObjBuilder builder;
181         BSONArrayBuilder arrayBuilder(builder.subarrayStart(getFieldName()));
182         writeArrayTo(&arrayBuilder);
183         arrayBuilder.done();
184         BSONObj obj = builder.obj();
185         return obj.firstElement().toString();
186     }
187 }
188 
189 }  // namespace mutablebson
190 }  // namespace mongo
191