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