mirror of
https://github.com/oatpp/oatpp-postgresql.git
synced 2024-11-27 02:39:56 +08:00
Merge pull request #1 from lganzzzo/AddFloatArrays
mapping::Serializer: 1D - Array Deserialization - General case.
This commit is contained in:
commit
54bf0a958c
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}}}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
51
test/oatpp-postgresql/migration/ArrayTest.sql
Normal file
51
test/oatpp-postgresql/migration/ArrayTest.sql
Normal 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"}');
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
122
test/oatpp-postgresql/types/ArrayTest.cpp
Normal file
122
test/oatpp-postgresql/types/ArrayTest.cpp
Normal 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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}}}}
|
40
test/oatpp-postgresql/types/ArrayTest.hpp
Normal file
40
test/oatpp-postgresql/types/ArrayTest.hpp
Normal 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
|
Loading…
Reference in New Issue
Block a user