1 | // |
2 | // Document.cpp |
3 | // |
4 | // Library: MongoDB |
5 | // Package: MongoDB |
6 | // Module: Document |
7 | // |
8 | // Copyright (c) 2012, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/MongoDB/Document.h" |
16 | #include "Poco/MongoDB/Binary.h" |
17 | #include "Poco/MongoDB/ObjectId.h" |
18 | #include "Poco/MongoDB/Array.h" |
19 | #include "Poco/MongoDB/RegularExpression.h" |
20 | #include "Poco/MongoDB/JavaScriptCode.h" |
21 | #include <sstream> |
22 | |
23 | |
24 | namespace Poco { |
25 | namespace MongoDB { |
26 | |
27 | |
28 | Document::Document() |
29 | { |
30 | } |
31 | |
32 | |
33 | Document::~Document() |
34 | { |
35 | } |
36 | |
37 | |
38 | Element::Ptr Document::get(const std::string& name) const |
39 | { |
40 | Element::Ptr element; |
41 | |
42 | ElementSet::const_iterator it = std::find_if(_elements.begin(), _elements.end(), ElementFindByName(name)); |
43 | if (it != _elements.end()) |
44 | { |
45 | return *it; |
46 | } |
47 | |
48 | return element; |
49 | } |
50 | |
51 | |
52 | Int64 Document::getInteger(const std::string& name) const |
53 | { |
54 | Element::Ptr element = get(name); |
55 | if (element.isNull()) throw Poco::NotFoundException(name); |
56 | |
57 | if (ElementTraits<double>::TypeId == element->type()) |
58 | { |
59 | ConcreteElement<double>* concrete = dynamic_cast<ConcreteElement<double>*>(element.get()); |
60 | if (concrete) return static_cast<Int64>(concrete->value()); |
61 | } |
62 | else if (ElementTraits<Int32>::TypeId == element->type()) |
63 | { |
64 | ConcreteElement<Int32>* concrete = dynamic_cast<ConcreteElement<Int32>*>(element.get()); |
65 | if (concrete) return concrete->value(); |
66 | } |
67 | else if (ElementTraits<Int64>::TypeId == element->type()) |
68 | { |
69 | ConcreteElement<Int64>* concrete = dynamic_cast<ConcreteElement<Int64>*>(element.get()); |
70 | if (concrete) return concrete->value(); |
71 | } |
72 | throw Poco::BadCastException("Invalid type mismatch!" ); |
73 | } |
74 | |
75 | |
76 | void Document::read(BinaryReader& reader) |
77 | { |
78 | int size; |
79 | reader >> size; |
80 | |
81 | unsigned char type; |
82 | reader >> type; |
83 | |
84 | while (type != '\0') |
85 | { |
86 | Element::Ptr element; |
87 | |
88 | std::string name = BSONReader(reader).readCString(); |
89 | |
90 | switch (type) |
91 | { |
92 | case ElementTraits<double>::TypeId: |
93 | element = new ConcreteElement<double>(name, 0); |
94 | break; |
95 | case ElementTraits<Int32>::TypeId: |
96 | element = new ConcreteElement<Int32>(name, 0); |
97 | break; |
98 | case ElementTraits<std::string>::TypeId: |
99 | element = new ConcreteElement<std::string>(name, "" ); |
100 | break; |
101 | case ElementTraits<Document::Ptr>::TypeId: |
102 | element = new ConcreteElement<Document::Ptr>(name, new Document); |
103 | break; |
104 | case ElementTraits<Array::Ptr>::TypeId: |
105 | element = new ConcreteElement<Array::Ptr>(name, new Array); |
106 | break; |
107 | case ElementTraits<Binary::Ptr>::TypeId: |
108 | element = new ConcreteElement<Binary::Ptr>(name, new Binary); |
109 | break; |
110 | case ElementTraits<ObjectId::Ptr>::TypeId: |
111 | element = new ConcreteElement<ObjectId::Ptr>(name, new ObjectId); |
112 | break; |
113 | case ElementTraits<bool>::TypeId: |
114 | element = new ConcreteElement<bool>(name, false); |
115 | break; |
116 | case ElementTraits<Poco::Timestamp>::TypeId: |
117 | element = new ConcreteElement<Poco::Timestamp>(name, Poco::Timestamp()); |
118 | break; |
119 | case ElementTraits<BSONTimestamp>::TypeId: |
120 | element = new ConcreteElement<BSONTimestamp>(name, BSONTimestamp()); |
121 | break; |
122 | case ElementTraits<NullValue>::TypeId: |
123 | element = new ConcreteElement<NullValue>(name, NullValue(0)); |
124 | break; |
125 | case ElementTraits<RegularExpression::Ptr>::TypeId: |
126 | element = new ConcreteElement<RegularExpression::Ptr>(name, new RegularExpression()); |
127 | break; |
128 | case ElementTraits<JavaScriptCode::Ptr>::TypeId: |
129 | element = new ConcreteElement<JavaScriptCode::Ptr>(name, new JavaScriptCode()); |
130 | break; |
131 | case ElementTraits<Int64>::TypeId: |
132 | element = new ConcreteElement<Int64>(name, 0); |
133 | break; |
134 | default: |
135 | { |
136 | std::stringstream ss; |
137 | ss << "Element " << name << " contains an unsupported type 0x" << std::hex << (int) type; |
138 | throw Poco::NotImplementedException(ss.str()); |
139 | } |
140 | //TODO: x0F -> JavaScript code with scope |
141 | // xFF -> Min Key |
142 | // x7F -> Max Key |
143 | } |
144 | |
145 | element->read(reader); |
146 | _elements.push_back(element); |
147 | |
148 | reader >> type; |
149 | } |
150 | } |
151 | |
152 | |
153 | std::string Document::toString(int indent) const |
154 | { |
155 | std::ostringstream oss; |
156 | |
157 | oss << '{'; |
158 | |
159 | if (indent > 0) oss << std::endl; |
160 | |
161 | |
162 | for (ElementSet::const_iterator it = _elements.begin(); it != _elements.end(); ++it) |
163 | { |
164 | if (it != _elements.begin()) |
165 | { |
166 | oss << ','; |
167 | if (indent > 0) oss << std::endl; |
168 | } |
169 | |
170 | for (int i = 0; i < indent; ++i) oss << ' '; |
171 | |
172 | oss << '"' << (*it)->name() << '"'; |
173 | oss << (indent > 0 ? " : " : ":" ); |
174 | |
175 | oss << (*it)->toString(indent > 0 ? indent + 2 : 0); |
176 | } |
177 | |
178 | if (indent > 0) |
179 | { |
180 | oss << std::endl; |
181 | if (indent >= 2) indent -= 2; |
182 | |
183 | for (int i = 0; i < indent; ++i) oss << ' '; |
184 | } |
185 | |
186 | oss << '}'; |
187 | |
188 | return oss.str(); |
189 | } |
190 | |
191 | |
192 | void Document::write(BinaryWriter& writer) |
193 | { |
194 | if (_elements.empty()) |
195 | { |
196 | writer << 5; |
197 | } |
198 | else |
199 | { |
200 | std::stringstream sstream; |
201 | Poco::BinaryWriter tempWriter(sstream); |
202 | for (ElementSet::iterator it = _elements.begin(); it != _elements.end(); ++it) |
203 | { |
204 | tempWriter << static_cast<unsigned char>((*it)->type()); |
205 | BSONWriter(tempWriter).writeCString((*it)->name()); |
206 | Element::Ptr element = *it; |
207 | element->write(tempWriter); |
208 | } |
209 | tempWriter.flush(); |
210 | |
211 | Poco::Int32 len = static_cast<Poco::Int32>(5 + sstream.tellp()); /* 5 = sizeof(len) + 0-byte */ |
212 | writer << len; |
213 | writer.writeRaw(sstream.str()); |
214 | } |
215 | writer << '\0'; |
216 | } |
217 | |
218 | |
219 | } } // namespace Poco::MongoDB |
220 | |