mirror of
https://github.com/oatpp/oatpp-postgresql.git
synced 2024-11-27 02:39:56 +08:00
mapping. Introduce ResultMapper.
This commit is contained in:
parent
bd86ab6480
commit
6ed7282d73
@ -13,7 +13,7 @@ add_library(${OATPP_THIS_MODULE_NAME}
|
||||
oatpp-postgresql/mapping/Serializer.cpp
|
||||
oatpp-postgresql/mapping/Serializer.hpp
|
||||
oatpp-postgresql/mapping/TypeMapper.cpp
|
||||
oatpp-postgresql/mapping/TypeMapper.hpp oatpp-postgresql/mapping/Oid.hpp oatpp-postgresql/QueryResult.cpp oatpp-postgresql/QueryResult.hpp)
|
||||
oatpp-postgresql/mapping/TypeMapper.hpp oatpp-postgresql/mapping/Oid.hpp oatpp-postgresql/QueryResult.cpp oatpp-postgresql/QueryResult.hpp oatpp-postgresql/mapping/ResultMapper.cpp oatpp-postgresql/mapping/ResultMapper.hpp)
|
||||
|
||||
set_target_properties(${OATPP_THIS_MODULE_NAME} PROPERTIES
|
||||
CXX_STANDARD 11
|
||||
|
@ -65,7 +65,7 @@ std::shared_ptr<QueryResult> Executor::prepareQuery(const StringTemplate& queryT
|
||||
queryTemplate.getTemplateVariables().size(),
|
||||
extra->paramTypes.get());
|
||||
|
||||
auto res = std::make_shared<QueryResult>(qres, connection);
|
||||
auto res = std::make_shared<QueryResult>(qres, connection, m_resultMapper);
|
||||
|
||||
auto status = PQresultStatus(qres);
|
||||
if (status != PGRES_COMMAND_OK) {
|
||||
@ -116,7 +116,7 @@ std::shared_ptr<QueryResult> Executor::executeQuery(const StringTemplate& queryT
|
||||
paramFormats.get(),
|
||||
1);
|
||||
|
||||
auto res = std::make_shared<QueryResult>(qres, connection);
|
||||
auto res = std::make_shared<QueryResult>(qres, connection, m_resultMapper);
|
||||
|
||||
auto status = PQresultStatus(qres);
|
||||
if (status != PGRES_TUPLES_OK) {
|
||||
|
@ -30,6 +30,7 @@
|
||||
|
||||
#include "mapping/Serializer.hpp"
|
||||
#include "mapping/TypeMapper.hpp"
|
||||
#include "mapping/ResultMapper.hpp"
|
||||
|
||||
#include "oatpp/orm/Executor.hpp"
|
||||
#include "oatpp/core/parser/Caret.hpp"
|
||||
@ -49,6 +50,7 @@ private:
|
||||
private:
|
||||
mapping::TypeMapper m_typeMapper;
|
||||
mapping::Serializer m_serializer;
|
||||
std::shared_ptr<mapping::ResultMapper> m_resultMapper = std::make_shared<mapping::ResultMapper>();
|
||||
public:
|
||||
|
||||
StringTemplate parseQueryTemplate(const oatpp::String& name,
|
||||
|
@ -26,10 +26,13 @@
|
||||
|
||||
namespace oatpp { namespace postgresql {
|
||||
|
||||
QueryResult::QueryResult(PGresult* dbResult, const std::shared_ptr<Connection>& connection)
|
||||
QueryResult::QueryResult(PGresult* dbResult,
|
||||
const std::shared_ptr<Connection>& connection,
|
||||
const std::shared_ptr<mapping::ResultMapper>& resultMapper)
|
||||
: m_dbResult(dbResult)
|
||||
, m_connection(connection)
|
||||
, m_cursor(0)
|
||||
, m_resultMapper(resultMapper)
|
||||
, m_resultData(dbResult)
|
||||
{
|
||||
auto status = PQresultStatus(m_dbResult);
|
||||
switch(status) {
|
||||
@ -69,68 +72,11 @@ v_int64 QueryResult::count() {
|
||||
}
|
||||
|
||||
std::vector<std::vector<oatpp::Void>> QueryResult::fetchRows(v_int64 count) {
|
||||
|
||||
std::vector<std::vector<oatpp::Void>> result;
|
||||
|
||||
auto leftCount = this->count() - m_cursor;
|
||||
auto wantToRead = count;
|
||||
if(wantToRead > leftCount) {
|
||||
wantToRead = leftCount;
|
||||
}
|
||||
|
||||
auto fieldsCount = PQnfields(m_dbResult);
|
||||
|
||||
for(v_int64 i = 0; i < wantToRead; i++) {
|
||||
|
||||
std::vector<oatpp::Void> row(fieldsCount);
|
||||
|
||||
for(v_int32 fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex ++) {
|
||||
auto oid = PQftype(m_dbResult, fieldIndex);
|
||||
auto size = PQfsize(m_dbResult, fieldIndex);
|
||||
char* data = PQgetvalue(m_dbResult, m_cursor, fieldIndex);
|
||||
// TODO map
|
||||
}
|
||||
|
||||
result.push_back(std::move(row));
|
||||
|
||||
++ m_cursor;
|
||||
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
void QueryResult::fetch(oatpp::Void& polymorph, v_int64 count) {
|
||||
|
||||
auto type = polymorph.valueType;
|
||||
|
||||
if(type->classId.id == oatpp::data::mapping::type::__class::AbstractVector::CLASS_ID.id) {
|
||||
fetchAsList<oatpp::AbstractVector>(polymorph, count);
|
||||
} else if(type->classId.id == oatpp::data::mapping::type::__class::AbstractList::CLASS_ID.id) {
|
||||
fetchAsList<oatpp::AbstractList>(polymorph, count);
|
||||
} else if(type->classId.id == oatpp::data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id) {
|
||||
fetchAsList<oatpp::AbstractUnorderedSet>(polymorph, count);
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::postgresql::QueryResult::fetch()]: "
|
||||
"Error. Invalid result container type. "
|
||||
"Allowed types are oatpp::Vector, oatpp::List, oatpp::UnorderedSet");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void QueryResult::readRow(Type* type, v_int64 rowIndex) {
|
||||
if(type->classId.id == oatpp::data::mapping::type::__class::AbstractVector::CLASS_ID.id) {
|
||||
return readRowAsList<oatpp::AbstractVector>(this, type, rowIndex);
|
||||
} else if(type->classId.id == oatpp::data::mapping::type::__class::AbstractList::CLASS_ID.id) {
|
||||
return readRowAsList<oatpp::AbstractList>(this, type, rowIndex);
|
||||
} else if(type->classId.id == oatpp::data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id) {
|
||||
return readRowAsList<oatpp::AbstractUnorderedSet>(this, type, rowIndex);
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::postgresql::QueryResult::readRow()]: "
|
||||
"Error. Invalid result container type. "
|
||||
"Allowed types are oatpp::Vector, oatpp::List, oatpp::UnorderedSet");
|
||||
}
|
||||
polymorph = m_resultMapper->readRows(&m_resultData, polymorph.valueType, count);
|
||||
}
|
||||
|
||||
}}
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "Connection.hpp"
|
||||
#include "mapping/Deserializer.hpp"
|
||||
#include "mapping/ResultMapper.hpp"
|
||||
#include "oatpp/orm/QueryResult.hpp"
|
||||
|
||||
namespace oatpp { namespace postgresql {
|
||||
@ -36,84 +37,20 @@ private:
|
||||
static constexpr v_int32 TYPE_ERROR = 0;
|
||||
static constexpr v_int32 TYPE_COMMAND = 1;
|
||||
static constexpr v_int32 TYPE_TUPLES = 2;
|
||||
private:
|
||||
typedef oatpp::data::mapping::type::Type Type;
|
||||
private:
|
||||
|
||||
template<class Collection>
|
||||
static oatpp::Void readRowAsList(QueryResult* _this, Type* type, v_int64 rowIndex) {
|
||||
|
||||
auto listWrapper = type->creator();
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const typename Collection::Class::AbstractPolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
const auto& list = listWrapper.template staticCast<Collection>();
|
||||
|
||||
Type* itemType = *type->params.begin();
|
||||
|
||||
auto fieldsCount = PQnfields(_this->m_dbResult);
|
||||
|
||||
for(v_int32 fieldIndex = 0; fieldIndex < fieldsCount; fieldIndex ++) {
|
||||
|
||||
mapping::Deserializer::InData inData;
|
||||
|
||||
inData.oid = PQftype(_this->m_dbResult, fieldIndex);
|
||||
inData.size = PQfsize(_this->m_dbResult, fieldIndex);
|
||||
inData.data = PQgetvalue(_this->m_dbResult, rowIndex, fieldIndex);
|
||||
|
||||
polymorphicDispatcher->addPolymorphicItem(listWrapper, _this->m_deserializer.deserialize(inData, itemType));
|
||||
|
||||
}
|
||||
|
||||
return listWrapper;
|
||||
|
||||
}
|
||||
|
||||
template<class Collection>
|
||||
static oatpp::Void readRowAsKeyValue(QueryResult* _this, Type* type, v_int64 rowIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
oatpp::Void readRow(Type* type, v_int64 rowIndex);
|
||||
|
||||
private:
|
||||
|
||||
template<class Collection>
|
||||
void fetchAsList(oatpp::Void& polymorph, v_int64 count) {
|
||||
|
||||
auto type = polymorph.valueType;
|
||||
|
||||
auto listWrapper = type->creator();
|
||||
polymorph = listWrapper;
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const typename Collection::Class::AbstractPolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
const auto& list = listWrapper.template staticCast<Collection>();
|
||||
|
||||
Type* itemType = *type->params.begin();
|
||||
|
||||
auto leftCount = this->count() - m_cursor;
|
||||
auto wantToRead = count;
|
||||
if(wantToRead > leftCount) {
|
||||
wantToRead = leftCount;
|
||||
}
|
||||
|
||||
for(v_int64 i = 0; i < wantToRead; i++) {
|
||||
polymorphicDispatcher->addPolymorphicItem(listWrapper, readRow(itemType, m_cursor));
|
||||
++ m_cursor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
PGresult* m_dbResult;
|
||||
std::shared_ptr<Connection> m_connection;
|
||||
v_int64 m_cursor;
|
||||
std::shared_ptr<mapping::ResultMapper> m_resultMapper;
|
||||
mapping::ResultMapper::ResultData m_resultData;
|
||||
bool m_success;
|
||||
v_int32 m_type;
|
||||
private:
|
||||
mapping::Deserializer m_deserializer;
|
||||
public:
|
||||
|
||||
QueryResult(PGresult* dbResult, const std::shared_ptr<Connection>& connection);
|
||||
QueryResult(PGresult* dbResult,
|
||||
const std::shared_ptr<Connection>& connection,
|
||||
const std::shared_ptr<mapping::ResultMapper>& resultMapper);
|
||||
|
||||
~QueryResult();
|
||||
|
||||
|
121
src/oatpp-postgresql/mapping/ResultMapper.cpp
Normal file
121
src/oatpp-postgresql/mapping/ResultMapper.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#include "ResultMapper.hpp"
|
||||
|
||||
namespace oatpp { namespace postgresql { namespace mapping {
|
||||
|
||||
ResultMapper::ResultData::ResultData(PGresult* pDbResult)
|
||||
: dbResult(pDbResult)
|
||||
{
|
||||
|
||||
rowIndex = 0;
|
||||
rowCount = PQntuples(dbResult);
|
||||
|
||||
{
|
||||
colCount = PQnfields(dbResult);
|
||||
for (v_int32 i = 0; i < colCount; i++) {
|
||||
oatpp::String colName = (const char*) PQfname(dbResult, i);
|
||||
colNames.push_back(colName);
|
||||
colIndices.insert({colName, i});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ResultMapper::ResultMapper() {
|
||||
|
||||
{
|
||||
m_readOneRowMethods.resize(data::mapping::type::ClassId::getClassCount(), nullptr);
|
||||
|
||||
setReadOneRowMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, nullptr);
|
||||
|
||||
setReadOneRowMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &ResultMapper::readRowAsList<oatpp::AbstractVector>);
|
||||
setReadOneRowMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &ResultMapper::readRowAsList<oatpp::AbstractList>);
|
||||
setReadOneRowMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &ResultMapper::readRowAsList<oatpp::AbstractUnorderedSet>);
|
||||
|
||||
setReadOneRowMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, nullptr);
|
||||
setReadOneRowMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
m_readRowsMethods.resize(data::mapping::type::ClassId::getClassCount(), nullptr);
|
||||
|
||||
setReadRowsMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &ResultMapper::readRowsAsList<oatpp::AbstractVector>);
|
||||
setReadRowsMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &ResultMapper::readRowsAsList<oatpp::AbstractList>);
|
||||
setReadRowsMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &ResultMapper::readRowsAsList<oatpp::AbstractUnorderedSet>);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ResultMapper::setReadOneRowMethod(const data::mapping::type::ClassId& classId, ReadOneRowMethod method) {
|
||||
const v_uint32 id = classId.id;
|
||||
if(id < m_readOneRowMethods.size()) {
|
||||
m_readOneRowMethods[id] = method;
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::postgresql::mapping::ResultMapper::setReadOneRowMethod()]: Error. Unknown classId");
|
||||
}
|
||||
}
|
||||
|
||||
void ResultMapper::setReadRowsMethod(const data::mapping::type::ClassId& classId, ReadRowsMethod method) {
|
||||
const v_uint32 id = classId.id;
|
||||
if(id < m_readRowsMethods.size()) {
|
||||
m_readRowsMethods[id] = method;
|
||||
} else {
|
||||
throw std::runtime_error("[oatpp::postgresql::mapping::ResultMapper::setReadRowsMethod()]: Error. Unknown classId");
|
||||
}
|
||||
}
|
||||
|
||||
oatpp::Void ResultMapper::readOneRow(ResultData* dbData, const Type* type, v_int64 rowIndex) {
|
||||
|
||||
auto id = type->classId.id;
|
||||
auto& method = m_readOneRowMethods[id];
|
||||
|
||||
if(method) {
|
||||
return (*method)(this, dbData, type, rowIndex);
|
||||
}
|
||||
|
||||
throw std::runtime_error("[oatpp::postgresql::mapping::ResultMapper::readOneRow()]: "
|
||||
"Error. Invalid result container type. "
|
||||
"Allowed types are oatpp::Vector, oatpp::List, oatpp::UnorderedSet");
|
||||
|
||||
}
|
||||
|
||||
oatpp::Void ResultMapper::readRows(ResultData* dbData, const Type* type, v_int64 count) {
|
||||
|
||||
auto id = type->classId.id;
|
||||
auto& method = m_readRowsMethods[id];
|
||||
|
||||
if(method) {
|
||||
return (*method)(this, dbData, type, count);
|
||||
}
|
||||
|
||||
throw std::runtime_error("[oatpp::postgresql::mapping::ResultMapper::readRows()]: "
|
||||
"Error. Invalid result container type. "
|
||||
"Allowed types are oatpp::Vector, oatpp::List, oatpp::UnorderedSet");
|
||||
|
||||
}
|
||||
|
||||
}}}
|
130
src/oatpp-postgresql/mapping/ResultMapper.hpp
Normal file
130
src/oatpp-postgresql/mapping/ResultMapper.hpp
Normal file
@ -0,0 +1,130 @@
|
||||
/***************************************************************************
|
||||
*
|
||||
* Project _____ __ ____ _ _
|
||||
* ( _ ) /__\ (_ _)_| |_ _| |_
|
||||
* )(_)( /(__)\ )( (_ _)(_ _)
|
||||
* (_____)(__)(__)(__) |_| |_|
|
||||
*
|
||||
*
|
||||
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef oatpp_postgresql_mapping_ResultMapper_hpp
|
||||
#define oatpp_postgresql_mapping_ResultMapper_hpp
|
||||
|
||||
#include "Deserializer.hpp"
|
||||
#include "oatpp/core/Types.hpp"
|
||||
#include <libpq-fe.h>
|
||||
|
||||
namespace oatpp { namespace postgresql { namespace mapping {
|
||||
|
||||
class ResultMapper {
|
||||
public:
|
||||
|
||||
struct ResultData {
|
||||
|
||||
ResultData(PGresult* pDbResult);
|
||||
|
||||
PGresult* dbResult;
|
||||
std::vector<oatpp::String> colNames;
|
||||
std::unordered_map<data::share::StringKeyLabel, v_int32> colIndices;
|
||||
v_int64 colCount;
|
||||
v_int64 rowIndex;
|
||||
v_int64 rowCount;
|
||||
|
||||
};
|
||||
|
||||
private:
|
||||
typedef oatpp::data::mapping::type::Type Type;
|
||||
typedef oatpp::Void (*ReadOneRowMethod)(ResultMapper*, ResultData*, const Type*, v_int64);
|
||||
typedef oatpp::Void (*ReadRowsMethod)(ResultMapper*, ResultData*, const Type*, v_int64);
|
||||
private:
|
||||
|
||||
template<class Collection>
|
||||
static oatpp::Void readRowAsList(ResultMapper* _this, ResultData* dbData, const Type* type, v_int64 rowIndex) {
|
||||
|
||||
auto listWrapper = type->creator();
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const typename Collection::Class::AbstractPolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
const auto& list = listWrapper.template staticCast<Collection>();
|
||||
|
||||
Type* itemType = *type->params.begin();
|
||||
|
||||
for(v_int32 i = 0; i < dbData->colCount; i ++) {
|
||||
|
||||
mapping::Deserializer::InData inData;
|
||||
|
||||
inData.oid = PQftype(dbData->dbResult, i);
|
||||
inData.size = PQfsize(dbData->dbResult, i);
|
||||
inData.data = PQgetvalue(dbData->dbResult, rowIndex, i);
|
||||
|
||||
polymorphicDispatcher->addPolymorphicItem(listWrapper, _this->m_deserializer.deserialize(inData, itemType));
|
||||
|
||||
}
|
||||
|
||||
return listWrapper;
|
||||
|
||||
}
|
||||
|
||||
template<class Collection>
|
||||
static oatpp::Void readRowAsKeyValue(ResultMapper* _this, ResultData* dbData, const Type* type, v_int64 rowIndex) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<class Collection>
|
||||
static oatpp::Void readRowsAsList(ResultMapper* _this, ResultData* dbData, const Type* type, v_int64 count) {
|
||||
|
||||
auto listWrapper = type->creator();
|
||||
|
||||
auto polymorphicDispatcher = static_cast<const typename Collection::Class::AbstractPolymorphicDispatcher*>(type->polymorphicDispatcher);
|
||||
const auto& list = listWrapper.template staticCast<Collection>();
|
||||
|
||||
Type* itemType = *type->params.begin();
|
||||
|
||||
auto leftCount = dbData->rowCount - dbData->rowIndex;
|
||||
auto wantToRead = count;
|
||||
if(wantToRead > leftCount) {
|
||||
wantToRead = leftCount;
|
||||
}
|
||||
|
||||
for(v_int64 i = 0; i < wantToRead; i++) {
|
||||
polymorphicDispatcher->addPolymorphicItem(listWrapper, _this->readOneRow(dbData, itemType, dbData->rowIndex));
|
||||
++ dbData->rowIndex;
|
||||
}
|
||||
|
||||
return listWrapper;
|
||||
|
||||
}
|
||||
|
||||
private:
|
||||
Deserializer m_deserializer;
|
||||
std::vector<ReadOneRowMethod> m_readOneRowMethods;
|
||||
std::vector<ReadRowsMethod> m_readRowsMethods;
|
||||
public:
|
||||
|
||||
ResultMapper();
|
||||
|
||||
void setReadOneRowMethod(const data::mapping::type::ClassId& classId, ReadOneRowMethod method);
|
||||
void setReadRowsMethod(const data::mapping::type::ClassId& classId, ReadRowsMethod method);
|
||||
|
||||
oatpp::Void readOneRow(ResultData* dbData, const Type* type, v_int64 rowIndex);
|
||||
oatpp::Void readRows(ResultData* dbData, const Type* type, v_int64 count);
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
#endif //oatpp_postgresql_mapping_ResultMapper_hpp
|
Loading…
Reference in New Issue
Block a user