1 | // |
2 | // Row.cpp |
3 | // |
4 | // Library: Data |
5 | // Package: DataCore |
6 | // Module: Row |
7 | // |
8 | // Copyright (c) 2006, Applied Informatics Software Engineering GmbH. |
9 | // and Contributors. |
10 | // |
11 | // SPDX-License-Identifier: BSL-1.0 |
12 | // |
13 | |
14 | |
15 | #include "Poco/Data/Row.h" |
16 | #include "Poco/Data/SimpleRowFormatter.h" |
17 | #include "Poco/String.h" |
18 | #include "Poco/Exception.h" |
19 | |
20 | |
21 | namespace Poco { |
22 | namespace Data { |
23 | |
24 | |
25 | std::ostream& operator << (std::ostream &os, const Row& row) |
26 | { |
27 | os << row.valuesToString(); |
28 | return os; |
29 | } |
30 | |
31 | |
32 | Row::Row(): |
33 | _pNames(0), |
34 | _pSortMap(new SortMap), |
35 | _pFormatter(new SimpleRowFormatter) |
36 | { |
37 | } |
38 | |
39 | |
40 | Row::Row(NameVecPtr pNames, |
41 | const RowFormatter::Ptr& pFormatter): _pNames(pNames) |
42 | { |
43 | if (!_pNames) throw NullPointerException(); |
44 | init(0, pFormatter); |
45 | } |
46 | |
47 | |
48 | Row::Row(NameVecPtr pNames, |
49 | const SortMapPtr& pSortMap, |
50 | const RowFormatter::Ptr& pFormatter): _pNames(pNames) |
51 | { |
52 | if (!_pNames) throw NullPointerException(); |
53 | init(pSortMap, pFormatter); |
54 | } |
55 | |
56 | |
57 | void Row::init(const SortMapPtr& pSortMap, const RowFormatter::Ptr& pFormatter) |
58 | { |
59 | setFormatter(pFormatter); |
60 | setSortMap(pSortMap); |
61 | |
62 | NameVec::size_type sz = _pNames->size(); |
63 | if (sz) |
64 | { |
65 | _values.resize(sz); |
66 | // Row sortability in the strict weak ordering sense is |
67 | // an invariant, hence we must start with a zero here. |
68 | // If null value is later retrieved from DB, the |
69 | // Var::empty() call should be used to empty |
70 | // the corresponding Row value. |
71 | _values[0] = 0; |
72 | addSortField(0); |
73 | } |
74 | } |
75 | |
76 | |
77 | Row::~Row() |
78 | { |
79 | } |
80 | |
81 | |
82 | Poco::Dynamic::Var& Row::get(std::size_t col) |
83 | { |
84 | try |
85 | { |
86 | return _values.at(col); |
87 | } |
88 | catch (std::out_of_range& re) |
89 | { |
90 | throw RangeException(re.what()); |
91 | } |
92 | } |
93 | |
94 | |
95 | const Poco::Dynamic::Var& Row::get(std::size_t col) const |
96 | { |
97 | try |
98 | { |
99 | return _values.at(col); |
100 | } |
101 | catch (std::out_of_range& re) |
102 | { |
103 | throw RangeException(re.what()); |
104 | } |
105 | } |
106 | |
107 | |
108 | std::size_t Row::getPosition(const std::string& name) const |
109 | { |
110 | if (!_pNames) |
111 | throw NullPointerException(); |
112 | |
113 | NameVec::const_iterator it = _pNames->begin(); |
114 | NameVec::const_iterator end = _pNames->end(); |
115 | std::size_t col = 0; |
116 | for (; it != end; ++it, ++col) |
117 | if (0 == icompare(name, *it)) return col; |
118 | |
119 | throw NotFoundException(name); |
120 | } |
121 | |
122 | |
123 | void Row::addSortField(std::size_t pos) |
124 | { |
125 | poco_assert (pos <= _values.size()); |
126 | |
127 | SortMap::iterator it = _pSortMap->begin(); |
128 | SortMap::iterator end = _pSortMap->end(); |
129 | for (; it != end; ++it) |
130 | { |
131 | if (it->get<0>() == pos) return; |
132 | } |
133 | |
134 | ComparisonType ct; |
135 | if (_values[pos].isEmpty()) |
136 | { |
137 | ct = COMPARE_AS_EMPTY; |
138 | } |
139 | else if ((_values[pos].type() == typeid(Poco::Int8)) || |
140 | (_values[pos].type() == typeid(Poco::UInt8)) || |
141 | (_values[pos].type() == typeid(Poco::Int16)) || |
142 | (_values[pos].type() == typeid(Poco::UInt16)) || |
143 | (_values[pos].type() == typeid(Poco::Int32)) || |
144 | (_values[pos].type() == typeid(Poco::UInt32)) || |
145 | (_values[pos].type() == typeid(Poco::Int64)) || |
146 | (_values[pos].type() == typeid(Poco::UInt64)) || |
147 | (_values[pos].type() == typeid(bool))) |
148 | { |
149 | ct = COMPARE_AS_INTEGER; |
150 | } |
151 | else if ((_values[pos].type() == typeid(float)) || |
152 | (_values[pos].type() == typeid(double))) |
153 | { |
154 | ct = COMPARE_AS_FLOAT; |
155 | } |
156 | else |
157 | { |
158 | ct = COMPARE_AS_STRING; |
159 | } |
160 | |
161 | _pSortMap->push_back(SortTuple(pos, ct)); |
162 | } |
163 | |
164 | |
165 | void Row::addSortField(const std::string& name) |
166 | { |
167 | addSortField(getPosition(name)); |
168 | } |
169 | |
170 | |
171 | void Row::removeSortField(std::size_t pos) |
172 | { |
173 | SortMap::iterator it = _pSortMap->begin(); |
174 | SortMap::iterator end = _pSortMap->end(); |
175 | for (; it != end; ++it) |
176 | { |
177 | if (it->get<0>() == pos) |
178 | { |
179 | _pSortMap->erase(it); |
180 | return; |
181 | } |
182 | } |
183 | } |
184 | |
185 | |
186 | void Row::removeSortField(const std::string& name) |
187 | { |
188 | removeSortField(getPosition(name)); |
189 | } |
190 | |
191 | |
192 | void Row::replaceSortField(std::size_t oldPos, std::size_t newPos) |
193 | { |
194 | poco_assert (oldPos <= _values.size()); |
195 | poco_assert (newPos <= _values.size()); |
196 | |
197 | ComparisonType ct; |
198 | |
199 | if (_values[newPos].isEmpty()) |
200 | { |
201 | ct = COMPARE_AS_EMPTY; |
202 | } |
203 | else if ((_values[newPos].type() == typeid(Poco::Int8)) || |
204 | (_values[newPos].type() == typeid(Poco::UInt8)) || |
205 | (_values[newPos].type() == typeid(Poco::Int16)) || |
206 | (_values[newPos].type() == typeid(Poco::UInt16)) || |
207 | (_values[newPos].type() == typeid(Poco::Int32)) || |
208 | (_values[newPos].type() == typeid(Poco::UInt32)) || |
209 | (_values[newPos].type() == typeid(Poco::Int64)) || |
210 | (_values[newPos].type() == typeid(Poco::UInt64)) || |
211 | (_values[newPos].type() == typeid(bool))) |
212 | { |
213 | ct = COMPARE_AS_INTEGER; |
214 | } |
215 | else if ((_values[newPos].type() == typeid(float)) || |
216 | (_values[newPos].type() == typeid(double))) |
217 | { |
218 | ct = COMPARE_AS_FLOAT; |
219 | } |
220 | else |
221 | { |
222 | ct = COMPARE_AS_STRING; |
223 | } |
224 | |
225 | SortMap::iterator it = _pSortMap->begin(); |
226 | SortMap::iterator end = _pSortMap->end(); |
227 | for (; it != end; ++it) |
228 | { |
229 | if (it->get<0>() == oldPos) |
230 | { |
231 | *it = SortTuple(newPos, ct); |
232 | return; |
233 | } |
234 | } |
235 | |
236 | throw NotFoundException("Field not found" ); |
237 | } |
238 | |
239 | |
240 | void Row::replaceSortField(const std::string& oldName, const std::string& newName) |
241 | { |
242 | replaceSortField(getPosition(oldName), getPosition(newName)); |
243 | } |
244 | |
245 | |
246 | void Row::resetSort() |
247 | { |
248 | _pSortMap->clear(); |
249 | if (_values.size()) addSortField(0); |
250 | } |
251 | |
252 | |
253 | bool Row::isEqualSize(const Row& other) const |
254 | { |
255 | return (other._values.size() == _values.size()); |
256 | } |
257 | |
258 | |
259 | bool Row::isEqualType(const Row& other) const |
260 | { |
261 | std::vector<Poco::Dynamic::Var>::const_iterator it = _values.begin(); |
262 | std::vector<Poco::Dynamic::Var>::const_iterator end = _values.end(); |
263 | for (int i = 0; it != end; ++it, ++i) |
264 | { |
265 | if (it->type() != other._values[i].type()) |
266 | return false; |
267 | } |
268 | |
269 | return true; |
270 | } |
271 | |
272 | |
273 | bool Row::operator == (const Row& other) const |
274 | { |
275 | if (!isEqualSize(other)) return false; |
276 | if (!isEqualType(other)) return false; |
277 | |
278 | std::vector<Poco::Dynamic::Var>::const_iterator it = _values.begin(); |
279 | std::vector<Poco::Dynamic::Var>::const_iterator end = _values.end(); |
280 | for (int i = 0; it != end; ++it, ++i) |
281 | { |
282 | if ((*it).convert<std::string>() != other._values[i].convert<std::string>()) |
283 | return false; |
284 | } |
285 | |
286 | return true; |
287 | } |
288 | |
289 | |
290 | bool Row::operator != (const Row& other) const |
291 | { |
292 | return !(*this == other); |
293 | } |
294 | |
295 | |
296 | bool Row::operator < (const Row& other) const |
297 | { |
298 | if (*_pSortMap != *other._pSortMap) |
299 | throw InvalidAccessException("Rows compared have different sorting criteria." ); |
300 | |
301 | SortMap::const_iterator it = _pSortMap->begin(); |
302 | SortMap::const_iterator end = _pSortMap->end(); |
303 | for (; it != end; ++it) |
304 | { |
305 | switch (it->get<1>()) |
306 | { |
307 | case COMPARE_AS_EMPTY: |
308 | return false; |
309 | |
310 | case COMPARE_AS_INTEGER: |
311 | if (_values[it->get<0>()].convert<Poco::Int64>() < |
312 | other._values[it->get<0>()].convert<Poco::Int64>()) |
313 | return true; |
314 | else if (_values[it->get<0>()].convert<Poco::Int64>() != |
315 | other._values[it->get<0>()].convert<Poco::Int64>()) |
316 | return false; |
317 | break; |
318 | |
319 | case COMPARE_AS_FLOAT: |
320 | if (_values[it->get<0>()].convert<double>() < |
321 | other._values[it->get<0>()].convert<double>()) |
322 | return true; |
323 | else if (_values[it->get<0>()].convert<double>() != |
324 | other._values[it->get<0>()].convert<double>()) |
325 | return false; |
326 | break; |
327 | |
328 | case COMPARE_AS_STRING: |
329 | if (_values[it->get<0>()].convert<std::string>() < |
330 | other._values[it->get<0>()].convert<std::string>()) |
331 | return true; |
332 | else if (_values[it->get<0>()].convert<std::string>() != |
333 | other._values[it->get<0>()].convert<std::string>()) |
334 | return false; |
335 | break; |
336 | |
337 | default: |
338 | throw IllegalStateException("Unknown comparison criteria." ); |
339 | } |
340 | } |
341 | |
342 | return false; |
343 | } |
344 | |
345 | |
346 | void Row::setFormatter(const RowFormatter::Ptr& pFormatter) |
347 | { |
348 | if (pFormatter.get()) |
349 | _pFormatter = pFormatter; |
350 | else |
351 | _pFormatter = new SimpleRowFormatter; |
352 | } |
353 | |
354 | |
355 | void Row::setSortMap(const SortMapPtr& pSortMap) |
356 | { |
357 | if (pSortMap.get()) |
358 | _pSortMap = pSortMap; |
359 | else |
360 | _pSortMap = new SortMap; |
361 | } |
362 | |
363 | |
364 | const std::string& Row::namesToString() const |
365 | { |
366 | if (!_pNames) |
367 | throw NullPointerException(); |
368 | |
369 | return _pFormatter->formatNames(names(), _nameStr); |
370 | } |
371 | |
372 | |
373 | void Row::formatNames() const |
374 | { |
375 | if (!_pNames) |
376 | throw NullPointerException(); |
377 | |
378 | return _pFormatter->formatNames(names()); |
379 | } |
380 | |
381 | |
382 | } } // namespace Poco::Data |
383 | |