mapping. Introduce ResultMapper.

This commit is contained in:
lganzzzo 2020-08-12 00:36:08 +03:00
parent bd86ab6480
commit 6ed7282d73
7 changed files with 269 additions and 133 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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,

View File

@ -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);
}
}}

View File

@ -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();

View 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");
}
}}}

View 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