Skip to content

Commit 54bf0a9

Browse files
authored
Merge pull request #1 from lganzzzo/AddFloatArrays
mapping::Serializer: 1D - Array Deserialization - General case.
2 parents 6b9b6a2 + 0b8ca99 commit 54bf0a9

File tree

8 files changed

+292
-10
lines changed

8 files changed

+292
-10
lines changed

src/oatpp-postgresql/mapping/Deserializer.cpp

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ Deserializer::Deserializer() {
7070
setDeserializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, nullptr);
7171
setDeserializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Deserializer::deserializeEnum);
7272

73-
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Deserializer::deserializeArray);
74-
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, nullptr);
75-
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, nullptr);
73+
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Deserializer::deserializeArray2<oatpp::AbstractVector>);
74+
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Deserializer::deserializeArray2<oatpp::AbstractList>);
75+
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Deserializer::deserializeArray2<oatpp::AbstractUnorderedSet>);
7676

7777
setDeserializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, nullptr);
7878
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, nullptr);
@@ -280,10 +280,26 @@ const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
280280

281281
case TIMESTAMPOID: return oatpp::UInt64::Class::getType();
282282

283-
case FLOAT8ARRAYOID: return oatpp::Vector<Float64>::Class::getType();
284-
285283
case UUIDOID: return oatpp::postgresql::Uuid::Class::getType();
286284

285+
// Arrays
286+
287+
case TEXTARRAYOID:
288+
case VARCHARARRAYOID: return oatpp::Vector<oatpp::String>::Class::getType();
289+
290+
case INT2ARRAYOID: return oatpp::Vector<oatpp::Int16>::Class::getType();
291+
case INT4ARRAYOID: return oatpp::Vector<oatpp::Int32>::Class::getType();
292+
case INT8ARRAYOID: return oatpp::Vector<oatpp::Int64>::Class::getType();
293+
294+
case FLOAT4ARRAYOID: return oatpp::Vector<oatpp::Float32>::Class::getType();
295+
case FLOAT8ARRAYOID: return oatpp::Vector<oatpp::Float64>::Class::getType();
296+
297+
case BOOLARRAYOID: return oatpp::Vector<oatpp::Boolean>::Class::getType();
298+
299+
case TIMESTAMPARRAYOID: return oatpp::Vector<oatpp::UInt64>::Class::getType();
300+
301+
case UUIDARRAYOID: return oatpp::Vector<oatpp::postgresql::Uuid>::Class::getType();
302+
287303
}
288304

289305
return nullptr;

src/oatpp-postgresql/mapping/Deserializer.hpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#ifndef oatpp_postgresql_mapping_Deserializer_hpp
2626
#define oatpp_postgresql_mapping_Deserializer_hpp
2727

28+
#include "PgArray.hpp"
29+
2830
#include "oatpp/core/data/mapping/TypeResolver.hpp"
2931
#include "oatpp/core/Types.hpp"
3032

@@ -40,6 +42,8 @@ class Deserializer {
4042

4143
struct InData {
4244

45+
InData() = default;
46+
4347
InData(PGresult* dbres, int row, int col, const std::shared_ptr<const data::mapping::TypeResolver>& pTypeResolver);
4448

4549
std::shared_ptr<const data::mapping::TypeResolver> typeResolver;
@@ -98,6 +102,47 @@ class Deserializer {
98102

99103
static oatpp::Void deserializeArray(const Deserializer* _this, const InData& data, const Type* type);
100104

105+
template<class Collection>
106+
static oatpp::Void deserializeArray2(const Deserializer* _this, const InData& data, const Type* type) {
107+
108+
if(data.isNull) {
109+
return oatpp::Void(nullptr, type);
110+
}
111+
112+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
113+
auto itemType = *type->params.begin(); // Get "wanted" type of the list item
114+
auto listWrapper = polymorphicDispatcher->createObject(); // Instantiate list of the "wanted" type
115+
116+
PgArrayHeader* arr = (PgArrayHeader*) data.data;
117+
arr->size = (v_int32) htonl(arr->size);
118+
arr->oid = (v_int32) htonl(arr->oid);
119+
p_char8 payload = (p_char8) &data.data[sizeof(PgArrayHeader)];
120+
121+
for(v_int32 i = 0; i < arr->size; i ++) {
122+
123+
InData itemData;
124+
itemData.typeResolver = data.typeResolver;
125+
itemData.size = (v_int32)ntohl(*((p_int32) payload));
126+
itemData.data = (const char*) (payload + sizeof(v_int32));
127+
itemData.oid = arr->oid;
128+
itemData.isNull = itemData.size < 0;
129+
130+
if(itemData.size > 0) {
131+
payload += sizeof(v_int32) + itemData.size;
132+
} else {
133+
payload += sizeof(v_int32);
134+
}
135+
136+
const auto& item = _this->deserialize(itemData, itemType);
137+
138+
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
139+
140+
}
141+
142+
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
143+
144+
}
145+
101146
};
102147

103148
}}}

src/oatpp-postgresql/mapping/PgArray.hpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
#ifndef oatpp_postgresql_mapping_PgArray_hpp
66
#define oatpp_postgresql_mapping_PgArray_hpp
77

8+
#include "oatpp/core/Types.hpp"
9+
10+
#include <libpq-fe.h>
11+
812
// TODO: Assumes 64 bits for each element -- only valid for float64 and int64!
913
struct PgElem {
1014
v_int32 size;

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ add_definitions (
1414
add_executable(module-tests
1515
oatpp-postgresql/ql_template/ParserTest.cpp
1616
oatpp-postgresql/ql_template/ParserTest.hpp
17+
oatpp-postgresql/types/ArrayTest.cpp
18+
oatpp-postgresql/types/ArrayTest.hpp
1719
oatpp-postgresql/types/FloatTest.cpp
1820
oatpp-postgresql/types/FloatTest.hpp
1921
oatpp-postgresql/types/InterpretationTest.cpp
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
DROP TABLE IF EXISTS test_arrays1;
2+
DROP TABLE IF EXISTS test_arrays2;
3+
4+
CREATE TABLE test_arrays1 (
5+
f_real real[],
6+
f_double double precision[],
7+
8+
f_int16 smallint[],
9+
f_int32 integer[],
10+
f_int64 bigint[],
11+
f_bool boolean[],
12+
13+
f_text text[]
14+
);
15+
16+
CREATE TABLE test_arrays2 (
17+
f_real real[][],
18+
f_double double precision[][],
19+
20+
f_int16 smallint[][],
21+
f_int32 integer[][],
22+
f_int64 bigint[][],
23+
f_bool boolean[][],
24+
25+
f_text text[][]
26+
);
27+
28+
INSERT INTO test_arrays1
29+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
30+
VALUES
31+
(null, null, null, null, null, null, null);
32+
33+
INSERT INTO test_arrays1
34+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
35+
VALUES
36+
('{}', '{}', '{}', '{}', '{}', '{}', '{}');
37+
38+
INSERT INTO test_arrays1
39+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
40+
VALUES
41+
('{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}', '{null, null}');
42+
43+
INSERT INTO test_arrays1
44+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
45+
VALUES
46+
('{0}', '{0}', '{0}', '{0}', '{0}', '{false}', '{"", ""}');
47+
48+
INSERT INTO test_arrays1
49+
(f_real, f_double, f_int16, f_int32, f_int64, f_bool, f_text)
50+
VALUES
51+
('{1}', '{1}', '{1}', '{1}', '{1}', '{true}', '{"hello"}');

test/oatpp-postgresql/tests.cpp

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11

22
#include "ql_template/ParserTest.hpp"
33

4+
#include "types/ArrayTest.hpp"
45
#include "types/IntTest.hpp"
56
#include "types/FloatTest.hpp"
67
#include "types/InterpretationTest.hpp"
@@ -11,11 +12,12 @@ namespace {
1112

1213
void runTests() {
1314

14-
OATPP_RUN_TEST(oatpp::test::postgresql::ql_template::ParserTest);
15-
16-
OATPP_RUN_TEST(oatpp::test::postgresql::types::IntTest);
17-
OATPP_RUN_TEST(oatpp::test::postgresql::types::FloatTest);
18-
OATPP_RUN_TEST(oatpp::test::postgresql::types::InterpretationTest);
15+
// OATPP_RUN_TEST(oatpp::test::postgresql::ql_template::ParserTest);
16+
//
17+
// OATPP_RUN_TEST(oatpp::test::postgresql::types::IntTest);
18+
// OATPP_RUN_TEST(oatpp::test::postgresql::types::FloatTest);
19+
OATPP_RUN_TEST(oatpp::test::postgresql::types::ArrayTest);
20+
// OATPP_RUN_TEST(oatpp::test::postgresql::types::InterpretationTest);
1921

2022
}
2123

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/***************************************************************************
2+
*
3+
* Project _____ __ ____ _ _
4+
* ( _ ) /__\ (_ _)_| |_ _| |_
5+
* )(_)( /(__)\ )( (_ _)(_ _)
6+
* (_____)(__)(__)(__) |_| |_|
7+
*
8+
*
9+
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
10+
*
11+
* Licensed under the Apache License, Version 2.0 (the "License");
12+
* you may not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing, software
18+
* distributed under the License is distributed on an "AS IS" BASIS,
19+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20+
* See the License for the specific language governing permissions and
21+
* limitations under the License.
22+
*
23+
***************************************************************************/
24+
25+
#include "ArrayTest.hpp"
26+
27+
#include "oatpp-postgresql/orm.hpp"
28+
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
29+
30+
#include <limits>
31+
#include <cstdio>
32+
#include <iostream>
33+
34+
namespace oatpp { namespace test { namespace postgresql { namespace types {
35+
36+
namespace {
37+
38+
#include OATPP_CODEGEN_BEGIN(DTO)
39+
40+
class Row : public oatpp::DTO {
41+
42+
DTO_INIT(Row, DTO);
43+
44+
DTO_FIELD(Float32, f_real);
45+
DTO_FIELD(Float64, f_double);
46+
47+
};
48+
49+
#include OATPP_CODEGEN_END(DTO)
50+
51+
#include OATPP_CODEGEN_BEGIN(DbClient)
52+
53+
class MyClient : public oatpp::orm::DbClient {
54+
public:
55+
56+
MyClient(const std::shared_ptr<oatpp::orm::Executor>& executor)
57+
: oatpp::orm::DbClient(executor)
58+
{
59+
60+
executeQuery("DROP TABLE IF EXISTS oatpp_schema_version_ArrayTest;", {});
61+
62+
oatpp::orm::SchemaMigration migration(executor, "ArrayTest");
63+
migration.addFile(1, TEST_DB_MIGRATION "ArrayTest.sql");
64+
migration.migrate();
65+
66+
auto version = executor->getSchemaVersion("ArrayTest");
67+
OATPP_LOGD("DbClient", "Migration - OK. Version=%d.", version);
68+
69+
}
70+
71+
QUERY(insertValues,
72+
"INSERT INTO test_floats "
73+
"(f_real, f_double) "
74+
"VALUES "
75+
"(:row.f_real, :row.f_double);",
76+
PARAM(oatpp::Object<Row>, row), PREPARE(true))
77+
78+
QUERY(deleteValues,
79+
"DELETE FROM test_floats;")
80+
81+
QUERY(selectValues, "SELECT * FROM test_arrays1;")
82+
83+
};
84+
85+
#include OATPP_CODEGEN_END(DbClient)
86+
87+
}
88+
89+
void ArrayTest::onRun() {
90+
91+
OATPP_LOGI(TAG, "DB-URL='%s'", TEST_DB_URL);
92+
93+
auto connectionProvider = std::make_shared<oatpp::postgresql::ConnectionProvider>(TEST_DB_URL);
94+
auto executor = std::make_shared<oatpp::postgresql::Executor>(connectionProvider);
95+
96+
auto client = MyClient(executor);
97+
98+
{
99+
auto res = client.selectValues();
100+
if(res->isSuccess()) {
101+
OATPP_LOGD(TAG, "OK, knownCount=%d, hasMore=%d", res->getKnownCount(), res->hasMoreToFetch());
102+
} else {
103+
auto message = res->getErrorMessage();
104+
OATPP_LOGD(TAG, "Error, message=%s", message->c_str());
105+
}
106+
107+
auto dataset = res->fetch<oatpp::Vector<oatpp::Fields<oatpp::Any>>>();
108+
109+
oatpp::parser::json::mapping::ObjectMapper om;
110+
om.getSerializer()->getConfig()->useBeautifier = true;
111+
om.getSerializer()->getConfig()->enabledInterpretations = {"postgresql"};
112+
113+
auto str = om.writeToString(dataset);
114+
115+
std::cout << "\n" << str->std_str() << std::endl;
116+
117+
}
118+
119+
120+
}
121+
122+
}}}}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/***************************************************************************
2+
*
3+
* Project _____ __ ____ _ _
4+
* ( _ ) /__\ (_ _)_| |_ _| |_
5+
* )(_)( /(__)\ )( (_ _)(_ _)
6+
* (_____)(__)(__)(__) |_| |_|
7+
*
8+
*
9+
* Copyright 2018-present, Leonid Stryzhevskyi <lganzzzo@gmail.com>
10+
*
11+
* Licensed under the Apache License, Version 2.0 (the "License");
12+
* you may not use this file except in compliance with the License.
13+
* You may obtain a copy of the License at
14+
*
15+
* http://www.apache.org/licenses/LICENSE-2.0
16+
*
17+
* Unless required by applicable law or agreed to in writing, software
18+
* distributed under the License is distributed on an "AS IS" BASIS,
19+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20+
* See the License for the specific language governing permissions and
21+
* limitations under the License.
22+
*
23+
***************************************************************************/
24+
25+
#ifndef oatpp_test_postgresql_types_ArrayTest_hpp
26+
#define oatpp_test_postgresql_types_ArrayTest_hpp
27+
28+
#include "oatpp-test/UnitTest.hpp"
29+
30+
namespace oatpp { namespace test { namespace postgresql { namespace types {
31+
32+
class ArrayTest : public UnitTest {
33+
public:
34+
ArrayTest() : UnitTest("TEST[postgresql::types::ArrayTest]") {}
35+
void onRun() override;
36+
};
37+
38+
}}}}
39+
40+
#endif // oatpp_test_postgresql_types_ArrayTest_hpp

0 commit comments

Comments
 (0)