Skip to content

Commit c8d1eef

Browse files
authored
Add AColumn::as<T>() and ARow::args<Ts...>() for structured bindings (#65)
1 parent 33e5d11 commit c8d1eef

1 file changed

Lines changed: 84 additions & 0 deletions

File tree

src/aresult.h

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,25 @@
66

77
#include <asql_export.h>
88
#include <memory>
9+
#include <optional>
10+
#include <tuple>
11+
#include <type_traits>
12+
#include <utility>
913

1014
#include <QVariant>
1115

1216
namespace ASql {
1317

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+
1428
class ASQL_EXPORT AResultPrivate
1529
{
1630
public:
@@ -220,6 +234,56 @@ class ASQL_EXPORT AResult
220234
[[nodiscard]] QJsonValue toJsonValue() const;
221235
[[nodiscard]] QCborValue toCborValue() const;
222236
[[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+
}
223287
};
224288

225289
class ASQL_EXPORT ARow
@@ -294,6 +358,26 @@ class ASQL_EXPORT AResult
294358
{
295359
return AColumn(d, row, d->indexOfField(name));
296360
}
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+
}
297381
};
298382

299383
class ASQL_EXPORT const_iterator

0 commit comments

Comments
 (0)