diff --git a/CMakeLists.txt b/CMakeLists.txt index 7b2ee96..d5922ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,7 +2,7 @@ # SPDX-License-Identifier: MIT cmake_minimum_required(VERSION 3.16) -project(libasql VERSION 0.95.0 LANGUAGES CXX) +project(libasql VERSION 0.96.0 LANGUAGES CXX) include(GNUInstallDirs) include(GenerateExportHeader) diff --git a/demos/async1/coroutines.cpp b/demos/async1/coroutines.cpp index 2287c70..b599041 100644 --- a/demos/async1/coroutines.cpp +++ b/demos/async1/coroutines.cpp @@ -326,7 +326,7 @@ int main(int argc, char *argv[]) callPool(); } - if (true) { + if (false) { auto callPoolBegin = []() -> ACoroTerminator { auto _ = qScopeGuard([] { qDebug() << "coro pool exited"; }); qDebug() << "coro exec pool started"; @@ -352,23 +352,66 @@ int main(int argc, char *argv[]) }); co_yield obj; // so that this promise is destroyed if this object is destroyed - auto fooresult = /*co_await*/ APool::exec(u8"SELECT now(), pg_sleep(1)" /*, obj*/); - // if (result.has_value()) { - // qDebug() << "coro exec result has value" << result->toJsonObject(); - // } else { - // qDebug() << "coro exec result error" << result.error(); - // } - - // result = co_await t->coCommit(); - // if (result.has_value()) { - // qDebug() << "coro exec result has value" << result->toJsonObject(); - // } else { - // qDebug() << "coro exec result error" << result.error(); - // } + std::ignore = APool::exec(u8"SELECT now(), pg_sleep(1)" /*, obj*/); }; callPoolBegin(); } + if (true) { + auto callJsonBegin = []() -> ACoroTerminator { + auto _ = qScopeGuard([] { qDebug() << "coro pool exited"; }); + qDebug() << "coro exec pool started"; + + auto result = co_await APool::exec(u8"SELECT jsonb_build_object()", nullptr); + if (result.has_value()) { + auto row = result->begin(); + qDebug() << "coro exec result has value" << result->toJsonObject(); + qDebug() << "coro exec result has value" << row.value(0); + } else { + qDebug() << "coro exec result error" << result.error(); + } + + result = co_await APool::exec(u8"SELECT jsonb_build_array()", nullptr); + if (result.has_value()) { + auto row = result->begin(); + qDebug() << "coro exec result has value" << result->toJsonObject(); + qDebug() << "coro exec result has value" << row.value(0); + } else { + qDebug() << "coro exec result error" << result.error(); + } + + result = co_await APool::exec(u8"SELECT json_build_object()", nullptr); + if (result.has_value()) { + auto row = result->begin(); + qDebug() << "coro exec result has value" << result->toJsonObject(); + qDebug() << "coro exec result has value" << row.value(0); + } else { + qDebug() << "coro exec result error" << result.error(); + } + + result = co_await APool::exec(u8"SELECT json_build_array()", nullptr); + if (result.has_value()) { + auto row = result->begin(); + qDebug() << "coro exec result has value" << result->toJsonObject(); + qDebug() << "coro exec result has value" << row.value(0); + } else { + qDebug() << "coro exec result error" << result.error(); + } + + result = co_await APool::exec(u8"SELECT 'b12e975f-9717-4edb-b37e-d1e3827e6b3b'::uuid", + nullptr); + if (result.has_value()) { + auto row = result->begin(); + qDebug() << "coro exec result has value" << result->toJsonObject(); + qDebug() << "coro exec result has value" << row.value(0); + } else { + qDebug() << "coro exec result error" << result.error(); + } + }; + + callJsonBegin(); + } + app.exec(); } diff --git a/src/adriverpg.cpp b/src/adriverpg.cpp index 9368de4..bd913f9 100644 --- a/src/adriverpg.cpp +++ b/src/adriverpg.cpp @@ -22,6 +22,10 @@ Q_LOGGING_CATEGORY(ASQL_PG, "asql.pg", QtInfoMsg) +using namespace ASql; +using namespace Qt::StringLiterals; + +namespace { // workaround for postgres defining their OIDs in a private header file #define QBOOLOID 16 #define QINT8OID 20 @@ -44,6 +48,7 @@ Q_LOGGING_CATEGORY(ASQL_PG, "asql.pg", QtInfoMsg) #define QREGPROCOID 24 #define QXIDOID 28 #define QCIDOID 29 +#define QJSONOID 114 #define QJSONBOID 3802 #define QUUIDOID 2950 #define QBITOID 1560 @@ -51,19 +56,59 @@ Q_LOGGING_CATEGORY(ASQL_PG, "asql.pg", QtInfoMsg) #define VARHDRSZ 4 -using namespace ASql; -using namespace Qt::StringLiterals; - -ADriverPg::ADriverPg(const QString &connInfo) - : ADriver(connInfo) -{ -} - -ADriverPg::~ADriverPg() = default; - -bool ADriverPg::isValid() const +inline QMetaType qDecodePSQLType(int t) { - return true; + int type = QMetaType::UnknownType; + switch (t) { + case QBOOLOID: + type = QMetaType::Bool; + break; + case QINT8OID: + type = QMetaType::LongLong; + break; + case QINT2OID: + case QINT4OID: + case QOIDOID: + case QREGPROCOID: + case QXIDOID: + case QCIDOID: + type = QMetaType::Int; + break; + case QNUMERICOID: + case QFLOAT4OID: + case QFLOAT8OID: + type = QMetaType::Double; + break; + case QABSTIMEOID: + case QRELTIMEOID: + case QDATEOID: + type = QMetaType::QDate; + break; + case QTIMEOID: + case QTIMETZOID: + type = QMetaType::QTime; + break; + case QTIMESTAMPOID: + case QTIMESTAMPTZOID: + type = QMetaType::QDateTime; + break; + case QBYTEAOID: + type = QMetaType::QByteArray; + break; + case QJSONBOID: + [[fallthrough]]; + case QJSONOID: + type = QMetaType::QJsonValue; + break; + case QUUIDOID: + type = QMetaType::QUuid; + break; + default: + type = QMetaType::QString; + break; + } + // qDebug(ASQL_PG) << "decode pg type" << t << type; + return QMetaType(type); } QString connectionStatus(ConnStatusType type) @@ -84,6 +129,19 @@ QString connectionStatus(ConnStatusType type) return u"STATUS: "_s.arg(type); } } +} // namespace + +ADriverPg::ADriverPg(const QString &connInfo) + : ADriver(connInfo) +{ +} + +ADriverPg::~ADriverPg() = default; + +bool ADriverPg::isValid() const +{ + return true; +} void ADriverPg::open(QObject *receiver, std::function cb) { @@ -900,53 +958,6 @@ QString AResultPg::fieldName(int column) const return QString::fromUtf8(PQfname(m_result, column)); } -static QMetaType qDecodePSQLType(int t) -{ - int type = QMetaType::UnknownType; - switch (t) { - case QBOOLOID: - type = QMetaType::Bool; - break; - case QINT8OID: - type = QMetaType::LongLong; - break; - case QINT2OID: - case QINT4OID: - case QOIDOID: - case QREGPROCOID: - case QXIDOID: - case QCIDOID: - type = QMetaType::Int; - break; - case QNUMERICOID: - case QFLOAT4OID: - case QFLOAT8OID: - type = QMetaType::Double; - break; - case QABSTIMEOID: - case QRELTIMEOID: - case QDATEOID: - type = QMetaType::QDate; - break; - case QTIMEOID: - case QTIMETZOID: - type = QMetaType::QTime; - break; - case QTIMESTAMPOID: - case QTIMESTAMPTZOID: - type = QMetaType::QDateTime; - break; - case QBYTEAOID: - type = QMetaType::QByteArray; - break; - default: - type = QMetaType::QString; - break; - } - // qDebug(ASQL_PG) << "decode pg type" << t << type; - return QMetaType(type); -} - QVariant AResultPg::value(int row, int column) const { if (column >= PQnfields(m_result)) { @@ -1045,6 +1056,18 @@ QVariant AResultPg::value(int row, int column) const PQfreemem(data); return QVariant(ba); } + case QMetaType::QJsonValue: + { + const auto doc = QJsonDocument::fromJson(val); + if (doc.isObject()) { + return doc.object(); + } else if (doc.isArray()) { + return doc.array(); + } + break; + } + case QMetaType::QUuid: + return QUuid::fromString(val); default: case QMetaType::UnknownType: qWarning(ASQL_PG, "unknown data type");