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 <string> 34 35 #include "mongo/db/jsobj.h" 36 #include "mongo/util/time_support.h" 37 38 namespace mongo { 39 40 class FieldParser { 41 public: 42 /** 43 * Returns true and fills in 'out' with the contents of the field described by 'field' 44 * or with the value in 'def', depending on whether the field is present and has the 45 * correct type in 'doc' or not, respectively. Otherwise, if the field exists but has 46 * the wrong type, returns false. 47 * 48 * NOTE ON BSON OWNERSHIP: 49 * 50 * The caller must assume that this class will point to data inside 'doc' without 51 * copying it. In practice this means that 'doc' MUST EXIST for as long as 'out' 52 * stays in scope. 53 */ 54 55 enum FieldState { 56 // The field is present but has the wrong type 57 FIELD_INVALID = 0, 58 59 // The field is present and has the correct type 60 FIELD_SET, 61 62 // The field is absent in the BSON object but set from default 63 FIELD_DEFAULT, 64 65 // The field is absent and no default was specified 66 FIELD_NONE 67 }; 68 69 static FieldState extract(BSONObj doc, 70 const BSONField<bool>& field, 71 bool* out, 72 std::string* errMsg = NULL); 73 74 static FieldState extract(BSONElement elem, 75 const BSONField<bool>& field, 76 bool* out, 77 std::string* errMsg = NULL); 78 79 static FieldState extract(BSONObj doc, 80 const BSONField<BSONArray>& field, 81 BSONArray* out, 82 std::string* errMsg = NULL); 83 84 static FieldState extract(BSONElement elem, 85 const BSONField<BSONArray>& field, 86 BSONArray* out, 87 std::string* errMsg = NULL); 88 89 static FieldState extract(BSONObj doc, 90 const BSONField<BSONObj>& field, 91 BSONObj* out, 92 std::string* errMsg = NULL); 93 94 static FieldState extract(BSONElement elem, 95 const BSONField<BSONObj>& field, 96 BSONObj* out, 97 std::string* errMsg = NULL); 98 99 static FieldState extract(BSONObj doc, 100 const BSONField<Date_t>& field, 101 Date_t* out, 102 std::string* errMsg = NULL); 103 104 static FieldState extract(BSONElement elem, 105 const BSONField<Date_t>& field, 106 Date_t* out, 107 std::string* errMsg = NULL); 108 109 static FieldState extract(BSONObj doc, 110 const BSONField<Timestamp>& field, 111 Timestamp* out, 112 std::string* errMsg = NULL); 113 114 static FieldState extract(BSONElement elem, 115 const BSONField<Timestamp>& field, 116 Timestamp* out, 117 std::string* errMsg = NULL); 118 119 static FieldState extract(BSONObj doc, 120 const BSONField<std::string>& field, 121 std::string* out, 122 std::string* errMsg = NULL); 123 124 static FieldState extract(BSONElement elem, 125 const BSONField<std::string>& field, 126 std::string* out, 127 std::string* errMsg = NULL); 128 129 static FieldState extract(BSONObj doc, 130 const BSONField<OID>& field, 131 OID* out, 132 std::string* errMsg = NULL); 133 134 static FieldState extract(BSONElement elem, 135 const BSONField<OID>& field, 136 OID* out, 137 std::string* errMsg = NULL); 138 139 static FieldState extract(BSONObj doc, 140 const BSONField<int>& field, 141 int* out, 142 std::string* errMsg = NULL); 143 144 static FieldState extract(BSONElement elem, 145 const BSONField<int>& field, 146 int* out, 147 std::string* errMsg = NULL); 148 149 static FieldState extract(BSONObj doc, 150 const BSONField<long long>& field, 151 long long* out, 152 std::string* errMsg = NULL); 153 154 static FieldState extract(BSONElement elem, 155 const BSONField<long long>& field, 156 long long* out, 157 std::string* errMsg = NULL); 158 159 static FieldState extract(BSONElement elem, 160 const BSONField<double>& field, 161 double* out, 162 std::string* errMsg = NULL); 163 164 static FieldState extract(BSONObj doc, 165 const BSONField<double>& field, 166 double* out, 167 std::string* errMsg = NULL); 168 169 /** 170 * The following extractNumber methods do implicit conversion between any numeric type and 171 * the BSONField type. This can be useful when an exact numeric type is not needed, for 172 * example if the field is sometimes modified from the shell which can change the type. 173 */ 174 static FieldState extractNumber(BSONObj doc, 175 const BSONField<int>& field, 176 int* out, 177 std::string* errMsg = NULL); 178 179 static FieldState extractNumber(BSONElement elem, 180 const BSONField<int>& field, 181 int* out, 182 std::string* errMsg = NULL); 183 184 static FieldState extractNumber(BSONObj doc, 185 const BSONField<long long>& field, 186 long long* out, 187 std::string* errMsg = NULL); 188 189 static FieldState extractNumber(BSONElement elem, 190 const BSONField<long long>& field, 191 long long* out, 192 std::string* errMsg = NULL); 193 194 static FieldState extractNumber(BSONObj doc, 195 const BSONField<double>& field, 196 double* out, 197 std::string* errMsg = NULL); 198 199 static FieldState extractNumber(BSONElement elem, 200 const BSONField<double>& field, 201 double* out, 202 std::string* errMsg = NULL); 203 204 /** 205 * Extracts a document id from a particular field name, which may be of any type but Array. 206 * Wraps the extracted id value in a BSONObj with one element and empty field name. 207 */ 208 static FieldState extractID(BSONObj doc, 209 const BSONField<BSONObj>& field, 210 BSONObj* out, 211 std::string* errMsg = NULL); 212 213 static FieldState extractID(BSONElement elem, 214 const BSONField<BSONObj>& field, 215 BSONObj* out, 216 std::string* errMsg = NULL); 217 218 // TODO: BSONElement extraction of types below 219 220 /** 221 * Extracts a mandatory 'field' from the object 'doc'. Writes the extracted contents to '*out' 222 * if successful or fills '*errMsg', if exising, otherwise. This variant relies on T having a 223 * parseBSON method. 224 */ 225 template <typename T> 226 static FieldState extract(BSONObj doc, 227 const BSONField<T>& field, 228 T* out, 229 std::string* errMsg = NULL); 230 231 /** 232 * Similar to the mandatory 'extract' but on a optional field. The '*out' value would only be 233 * allocated if the field is present. The ownership of '*out' would be transferred to the 234 * caller, in that case. 235 */ 236 template <typename T> 237 static FieldState extract(BSONObj doc, 238 const BSONField<T*>& field, 239 T** out, 240 std::string* errMsg = NULL); 241 242 template <typename T> 243 static FieldState extract(BSONObj doc, 244 const BSONField<T>& field, 245 T** out, // alloc variation 246 std::string* errMsg = NULL); 247 248 /** 249 * Extracts a mandatory repetition of 'field', from the object 'doc'. Writes the extracted 250 * contents to '*out' if successful or fills '*errMsg', if exising, otherwise. This variant 251 * relies on T having a parseBSON method. 252 * 253 * The vector owns the instances of T. 254 */ 255 template <typename T> 256 static FieldState extract(BSONObj doc, 257 const BSONField<std::vector<T*>>& field, 258 std::vector<T*>* out, 259 std::string* errMsg = NULL); 260 261 /** 262 * Extracts a mandatory repetition of 'field', from the field 'elem'. Writes the extracted 263 * contents to '*out' if successful or fills '*errMsg', if exising, otherwise. This variant 264 * relies on T having a parseBSON method. 265 * 266 * The vector owns the instances of T. 267 */ 268 template <typename T> 269 static FieldState extract(BSONElement elem, 270 const BSONField<std::vector<T*>>& field, 271 std::vector<T*>* out, 272 std::string* errMsg = NULL); 273 274 /** 275 * Similar to the mandatory repetition' extract but on an optional field. The '*out' value would 276 * only be allocated if the field is present. The ownership of '*out' would be transferred to 277 * the caller, in that case. 278 * 279 * The vector owns the instances of T. 280 */ 281 template <typename T> 282 static FieldState extract(BSONObj doc, 283 const BSONField<std::vector<T*>>& field, 284 std::vector<T*>** out, 285 std::string* errMsg = NULL); 286 287 // 288 // ==================== Below DEPRECATED; use types instead ==================== 289 // 290 291 /** 292 * The following extract methods are templatized to handle extraction of vectors and 293 * maps of sub-objects. Keys in the map should be StringData compatible. 294 * 295 * It's possible to nest extraction of vectors and maps to any depth, i.e: 296 * 297 * std::vector<map<std::string,vector<std::string> > > val; 298 * FieldParser::extract(doc, field, val, &val); 299 */ 300 template <typename T> 301 static FieldState extract(BSONObj doc, 302 const BSONField<std::vector<T>>& field, 303 std::vector<T>* out, 304 std::string* errMsg = NULL); 305 306 template <typename T> 307 static FieldState extract(BSONElement elem, 308 const BSONField<std::vector<T>>& field, 309 std::vector<T>* out, 310 std::string* errMsg = NULL); 311 312 template <typename K, typename T> 313 static FieldState extract(BSONObj doc, 314 const BSONField<std::map<K, T>>& field, 315 std::map<K, T>* out, 316 std::string* errMsg = NULL); 317 318 template <typename K, typename T> 319 static FieldState extract(BSONElement elem, 320 const BSONField<std::map<K, T>>& field, 321 std::map<K, T>* out, 322 std::string* errMsg = NULL); 323 }; 324 325 } // namespace mongo 326 327 // Inline functions for templating 328 #include "field_parser-inl.h" 329