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