Merge pull request #1 from lganzzzo/AddFloatArrays

mapping::Serializer: 1D - Array Deserialization - General case.
This commit is contained in:
Don Smyth 2021-01-04 10:29:55 -08:00 committed by GitHub
commit 54bf0a958c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 292 additions and 10 deletions

View File

@ -70,9 +70,9 @@ Deserializer::Deserializer() {
setDeserializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, nullptr);
setDeserializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Deserializer::deserializeEnum);
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Deserializer::deserializeArray);
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, nullptr);
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, nullptr);
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Deserializer::deserializeArray2<oatpp::AbstractVector>);
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Deserializer::deserializeArray2<oatpp::AbstractList>);
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Deserializer::deserializeArray2<oatpp::AbstractUnorderedSet>);
setDeserializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, nullptr);
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, nullptr);
@ -280,10 +280,26 @@ const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
case TIMESTAMPOID: return oatpp::UInt64::Class::getType();
case FLOAT8ARRAYOID: return oatpp::Vector<Float64>::Class::getType();
case UUIDOID: return oatpp::postgresql::Uuid::Class::getType();
// Arrays
case TEXTARRAYOID:
case VARCHARARRAYOID: return oatpp::Vector<oatpp::String>::Class::getType();
case INT2ARRAYOID: return oatpp::Vector<oatpp::Int16>::Class::getType();
case INT4ARRAYOID: return oatpp::Vector<oatpp::Int32>::Class::getType();
case INT8ARRAYOID: return oatpp::Vector<oatpp::Int64>::Class::getType();
case FLOAT4ARRAYOID: return oatpp::Vector<oatpp::Float32>::Class::getType();
case FLOAT8ARRAYOID: return oatpp::Vector<oatpp::Float64>::Class::getType();
case BOOLARRAYOID: return oatpp::Vector<oatpp::Boolean>::Class::getType();
case TIMESTAMPARRAYOID: return oatpp::Vector<oatpp::UInt64>::Class::getType();
case UUIDARRAYOID: return oatpp::Vector<oatpp::postgresql::Uuid>::Class::getType();
}
return nullptr;

View File

@ -25,6 +25,8 @@
#ifndef oatpp_postgresql_mapping_Deserializer_hpp
#define oatpp_postgresql_mapping_Deserializer_hpp
#include "PgArray.hpp"
#include "oatpp/core/data/mapping/TypeResolver.hpp"
#include "oatpp/core/Types.hpp"
@ -40,6 +42,8 @@ public:
struct InData {
InData() = default;
InData(PGresult* dbres, int row, int col, const std::shared_ptr<const data::mapping::TypeResolver>& pTypeResolver);
std::shared_ptr<const data::mapping::TypeResolver> typeResolver;
@ -98,6 +102,47 @@ private:
static oatpp::Void deserializeArray(const Deserializer* _this, const InData& data, const Type* type);
template<class Collection>
static oatpp::Void deserializeArray2(const Deserializer* _this, const InData& data, const Type* type) {
if(data.isNull) {
return oatpp::Void(nullptr, type);
}
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
auto itemType = *type->params.begin(); // Get "wanted" type of the list item
auto listWrapper = polymorphicDispatcher->createObject(); // Instantiate list of the "wanted" type
PgArrayHeader* arr = (PgArrayHeader*) data.data;
arr->size = (v_int32) htonl(arr->size);
arr->oid = (v_int32) htonl(arr->oid);
p_char8 payload = (p_char8) &data.data[sizeof(PgArrayHeader)];
for(v_int32 i = 0; i < arr->size; i ++) {
InData itemData;
itemData.typeResolver = data.typeResolver;
itemData.size = (v_int32)ntohl(*((p_int32) payload));
itemData.data = (const char*) (payload + sizeof(v_int32));
itemData.oid = arr->oid;
itemData.isNull = itemData.size < 0;
if(itemData.size > 0) {
payload += sizeof(v_int32) + itemData.size;
} else {
payload += sizeof(v_int32);
}
const auto& item = _this->deserialize(itemData, itemType);
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
}
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
}
};
}}}

View File

@ -5,6 +5,10 @@
#ifndef oatpp_postgresql_mapping_PgArray_hpp
#define oatpp_postgresql_mapping_PgArray_hpp
#include "oatpp/core/Types.hpp"
#include <libpq-fe.h>
// TODO: Assumes 64 bits for each element -- only valid for float64 and int64!
struct PgElem {
v_int32 size;

View File

@ -14,6 +14,8 @@ add_definitions (
add_executable(module-tests
oatpp-postgresql/ql_template/ParserTest.cpp
oatpp-postgresql/ql_template/ParserTest.hpp
oatpp-postgresql/types/ArrayTest.cpp
oatpp-postgresql/types/ArrayTest.hpp
oatpp-postgresql/types/FloatTest.cpp
oatpp-postgresql/types/FloatTest.hpp
oatpp-postgresql/types/InterpretationTest.cpp

View File

@ -0,0 +1,51 @@
DROP TABLE IF EXISTS test_arrays1;
DROP TABLE IF EXISTS test_arrays2;
CREATE TABLE test_arrays1 (
f_real real[],
f_double double precision[],
f_int16 smallint[],
f_int32 integer[],
f_int64 bigint[],
f_bool boolean[],
f_text text[]
);
CREATE TABLE test_arrays2 (
f_real real[][],
f_double double precision[][],
f_int16 smallint[][],
f_int32 integer[][],
f_int64 bigint[][],
f_bool boolean[][],
f_text text[][]
);
INSERT INTO test_arrays1
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
VALUES
(null, null, null, null, null, null, null);
INSERT INTO test_arrays1
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
VALUES
('{}', '{}', '{}', '{}', '{}', '{}', '{}');
INSERT INTO test_arrays1
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
VALUES
('{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}');
INSERT INTO test_arrays1
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
VALUES
('{0}', '{0}', '{0}', '{0}', '{0}', '{false}', '{"", ""}');
INSERT INTO test_arrays1
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
VALUES
('{1}', '{1}', '{1}', '{1}', '{1}', '{true}', '{"hello"}');

View File

@ -1,6 +1,7 @@
#include "ql_template/ParserTest.hpp"
#include "types/ArrayTest.hpp"
#include "types/IntTest.hpp"
#include "types/FloatTest.hpp"
#include "types/InterpretationTest.hpp"
@ -11,11 +12,12 @@ namespace {
void runTests() {
OATPP_RUN_TEST(oatpp::test::postgresql::ql_template::ParserTest);
OATPP_RUN_TEST(oatpp::test::postgresql::types::IntTest);
OATPP_RUN_TEST(oatpp::test::postgresql::types::FloatTest);
OATPP_RUN_TEST(oatpp::test::postgresql::types::InterpretationTest);
// OATPP_RUN_TEST(oatpp::test::postgresql::ql_template::ParserTest);
//
// OATPP_RUN_TEST(oatpp::test::postgresql::types::IntTest);
// OATPP_RUN_TEST(oatpp::test::postgresql::types::FloatTest);
OATPP_RUN_TEST(oatpp::test::postgresql::types::ArrayTest);
// OATPP_RUN_TEST(oatpp::test::postgresql::types::InterpretationTest);
}

View File

@ -0,0 +1,122 @@
/***************************************************************************
*
* 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 "ArrayTest.hpp"
#include "oatpp-postgresql/orm.hpp"
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
#include <limits>
#include <cstdio>
#include <iostream>
namespace oatpp { namespace test { namespace postgresql { namespace types {
namespace {
#include OATPP_CODEGEN_BEGIN(DTO)
class Row : public oatpp::DTO {
DTO_INIT(Row, DTO);
DTO_FIELD(Float32, f_real);
DTO_FIELD(Float64, f_double);
};
#include OATPP_CODEGEN_END(DTO)
#include OATPP_CODEGEN_BEGIN(DbClient)
class MyClient : public oatpp::orm::DbClient {
public:
MyClient(const std::shared_ptr<oatpp::orm::Executor>& executor)
: oatpp::orm::DbClient(executor)
{
executeQuery("DROP TABLE IF EXISTS oatpp_schema_version_ArrayTest;", {});
oatpp::orm::SchemaMigration migration(executor, "ArrayTest");
migration.addFile(1, TEST_DB_MIGRATION "ArrayTest.sql");
migration.migrate();
auto version = executor->getSchemaVersion("ArrayTest");
OATPP_LOGD("DbClient", "Migration - OK. Version=%d.", version);
}
QUERY(insertValues,
"INSERT INTO test_floats "
"(f_real, f_double) "
"VALUES "
"(:row.f_real, :row.f_double);",
PARAM(oatpp::Object<Row>, row), PREPARE(true))
QUERY(deleteValues,
"DELETE FROM test_floats;")
QUERY(selectValues, "SELECT * FROM test_arrays1;")
};
#include OATPP_CODEGEN_END(DbClient)
}
void ArrayTest::onRun() {
OATPP_LOGI(TAG, "DB-URL='%s'", TEST_DB_URL);
auto connectionProvider = std::make_shared<oatpp::postgresql::ConnectionProvider>(TEST_DB_URL);
auto executor = std::make_shared<oatpp::postgresql::Executor>(connectionProvider);
auto client = MyClient(executor);
{
auto res = client.selectValues();
if(res->isSuccess()) {
OATPP_LOGD(TAG, "OK, knownCount=%d, hasMore=%d", res->getKnownCount(), res->hasMoreToFetch());
} else {
auto message = res->getErrorMessage();
OATPP_LOGD(TAG, "Error, message=%s", message->c_str());
}
auto dataset = res->fetch<oatpp::Vector<oatpp::Fields<oatpp::Any>>>();
oatpp::parser::json::mapping::ObjectMapper om;
om.getSerializer()->getConfig()->useBeautifier = true;
om.getSerializer()->getConfig()->enabledInterpretations = {"postgresql"};
auto str = om.writeToString(dataset);
std::cout << "\n" << str->std_str() << std::endl;
}
}
}}}}

View File

@ -0,0 +1,40 @@
/***************************************************************************
*
* 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_test_postgresql_types_ArrayTest_hpp
#define oatpp_test_postgresql_types_ArrayTest_hpp
#include "oatpp-test/UnitTest.hpp"
namespace oatpp { namespace test { namespace postgresql { namespace types {
class ArrayTest : public UnitTest {
public:
ArrayTest() : UnitTest("TEST[postgresql::types::ArrayTest]") {}
void onRun() override;
};
}}}}
#endif // oatpp_test_postgresql_types_ArrayTest_hpp