Skip to content

Commit

Permalink
Decode JSONB/JSON/UUID Postgres types to specialized types
Browse files Browse the repository at this point in the history
  • Loading branch information
dantti committed Nov 14, 2024
1 parent e8c4bde commit b030113
Show file tree
Hide file tree
Showing 3 changed files with 140 additions and 74 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
71 changes: 57 additions & 14 deletions demos/async1/coroutines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -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();
}
141 changes: 82 additions & 59 deletions src/adriverpg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -44,26 +48,67 @@ 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
#define QVARBITOID 1562

#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)
Expand All @@ -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<void(bool, const QString &)> cb)
{
Expand Down Expand Up @@ -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)) {
Expand Down Expand Up @@ -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");
Expand Down

0 comments on commit b030113

Please sign in to comment.