|
6 | 6 |
|
7 | 7 | #include <asql_export.h> |
8 | 8 | #include <memory> |
| 9 | +#include <optional> |
| 10 | +#include <tuple> |
| 11 | +#include <type_traits> |
| 12 | +#include <utility> |
9 | 13 |
|
10 | 14 | #include <QVariant> |
11 | 15 |
|
12 | 16 | namespace ASql { |
13 | 17 |
|
| 18 | +namespace detail { |
| 19 | + |
| 20 | +template <typename T> |
| 21 | +struct is_optional : std::false_type {}; |
| 22 | + |
| 23 | +template <typename T> |
| 24 | +struct is_optional<std::optional<T>> : std::true_type {}; |
| 25 | + |
| 26 | +} // namespace detail |
| 27 | + |
14 | 28 | class ASQL_EXPORT AResultPrivate |
15 | 29 | { |
16 | 30 | public: |
@@ -220,6 +234,56 @@ class ASQL_EXPORT AResult |
220 | 234 | [[nodiscard]] QJsonValue toJsonValue() const; |
221 | 235 | [[nodiscard]] QCborValue toCborValue() const; |
222 | 236 | [[nodiscard]] inline QByteArray toByteArray() const { return d->toByteArray(row, column); } |
| 237 | + |
| 238 | + /*! |
| 239 | + * \brief as converts the column value to the requested type T. |
| 240 | + * |
| 241 | + * Supported types: bool, int, qint64, quint64, double, QString, std::string, |
| 242 | + * QUuid, QDate, QTime, QDateTime, QJsonValue, QCborValue, QByteArray, QVariant, |
| 243 | + * and std::optional<U> for any supported type U (returns std::nullopt when null). |
| 244 | + * Any other type falls back to QVariant::value<T>(). |
| 245 | + */ |
| 246 | + template <typename T> |
| 247 | + [[nodiscard]] inline T as() const |
| 248 | + { |
| 249 | + if constexpr (detail::is_optional<T>::value) { |
| 250 | + if (isNull()) |
| 251 | + return T{}; |
| 252 | + return T{as<typename T::value_type>()}; |
| 253 | + } else if constexpr (std::is_same_v<T, bool>) { |
| 254 | + return toBool(); |
| 255 | + } else if constexpr (std::is_same_v<T, int>) { |
| 256 | + return toInt(); |
| 257 | + } else if constexpr (std::is_same_v<T, qint64>) { |
| 258 | + return toLongLong(); |
| 259 | + } else if constexpr (std::is_same_v<T, quint64>) { |
| 260 | + return toULongLong(); |
| 261 | + } else if constexpr (std::is_same_v<T, double>) { |
| 262 | + return toDouble(); |
| 263 | + } else if constexpr (std::is_same_v<T, QString>) { |
| 264 | + return toString(); |
| 265 | + } else if constexpr (std::is_same_v<T, std::string>) { |
| 266 | + return toStdString(); |
| 267 | + } else if constexpr (std::is_same_v<T, QUuid>) { |
| 268 | + return toUuid(); |
| 269 | + } else if constexpr (std::is_same_v<T, QDate>) { |
| 270 | + return toDate(); |
| 271 | + } else if constexpr (std::is_same_v<T, QTime>) { |
| 272 | + return toTime(); |
| 273 | + } else if constexpr (std::is_same_v<T, QDateTime>) { |
| 274 | + return toDateTime(); |
| 275 | + } else if constexpr (std::is_same_v<T, QJsonValue>) { |
| 276 | + return toJsonValue(); |
| 277 | + } else if constexpr (std::is_same_v<T, QCborValue>) { |
| 278 | + return toCborValue(); |
| 279 | + } else if constexpr (std::is_same_v<T, QByteArray>) { |
| 280 | + return toByteArray(); |
| 281 | + } else if constexpr (std::is_same_v<T, QVariant>) { |
| 282 | + return value(); |
| 283 | + } else { |
| 284 | + return value().template value<T>(); |
| 285 | + } |
| 286 | + } |
223 | 287 | }; |
224 | 288 |
|
225 | 289 | class ASQL_EXPORT ARow |
@@ -294,6 +358,26 @@ class ASQL_EXPORT AResult |
294 | 358 | { |
295 | 359 | return AColumn(d, row, d->indexOfField(name)); |
296 | 360 | } |
| 361 | + |
| 362 | + /*! |
| 363 | + * \brief args returns a tuple of column values converted to the requested types. |
| 364 | + * |
| 365 | + * This enables C++17-style structured bindings over a row: |
| 366 | + * \code |
| 367 | + * auto [id, name] = row.args<int, QString>(); |
| 368 | + * \endcode |
| 369 | + * |
| 370 | + * Each type in the pack is converted via AColumn::as<T>(). |
| 371 | + * Supports the same types as AColumn::as(), including std::optional<U> |
| 372 | + * for nullable columns. |
| 373 | + */ |
| 374 | + template <typename... Ts> |
| 375 | + [[nodiscard]] inline std::tuple<Ts...> args() const |
| 376 | + { |
| 377 | + return [this]<std::size_t... Is>(std::index_sequence<Is...>) { |
| 378 | + return std::make_tuple((*this)[static_cast<int>(Is)].template as<Ts>()...); |
| 379 | + }(std::index_sequence_for<Ts...>{}); |
| 380 | + } |
297 | 381 | }; |
298 | 382 |
|
299 | 383 | class ASQL_EXPORT const_iterator |
|
0 commit comments