Skip to content

Commit de45c16

Browse files
authored
Merge pull request #6 from oatpp/arrays
Arrays
2 parents 723bf2d + b109c46 commit de45c16

File tree

13 files changed

+1256
-29
lines changed

13 files changed

+1256
-29
lines changed

README.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -60,13 +60,16 @@ public:
6060
6161
### Supported Data Types
6262
63-
- INT2
64-
- INT4
65-
- INT8
66-
- TIMESTAMP
67-
- TEXT
68-
- VARCHAR
69-
- FLOAT4
70-
- FLOAT8
71-
- BOOL
72-
- UUID
63+
|Type|Supported|In Array|
64+
|---|:---:|:---:|
65+
|INT2|+|+|
66+
|INT4|+|+|
67+
|INT8|+|+|
68+
|TIMESTAMP|+|+|
69+
|TEXT|+|+|
70+
|VARCHAR|+|+|
71+
|FLOAT4|+|+|
72+
|FLOAT8|+|+|
73+
|BOOL|+|+|
74+
|UUID|+|+|
75+
|**Other Types**|-|-|

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ add_library(${OATPP_THIS_MODULE_NAME}
55
oatpp-postgresql/mapping/Deserializer.cpp
66
oatpp-postgresql/mapping/Deserializer.hpp
77
oatpp-postgresql/mapping/Oid.hpp
8+
oatpp-postgresql/mapping/PgArray.cpp
9+
oatpp-postgresql/mapping/PgArray.hpp
810
oatpp-postgresql/mapping/ResultMapper.cpp
911
oatpp-postgresql/mapping/ResultMapper.hpp
1012
oatpp-postgresql/mapping/Serializer.cpp

src/oatpp-postgresql/mapping/Deserializer.cpp

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,9 @@
2525
#include "Deserializer.hpp"
2626

2727
#include "Oid.hpp"
28+
#include "PgArray.hpp"
2829
#include "oatpp-postgresql/Types.hpp"
2930

30-
#if defined(WIN32) || defined(_WIN32)
31-
#include <WinSock2.h>
32-
#else
33-
#include <arpa/inet.h>
34-
#endif
35-
3631
namespace oatpp { namespace postgresql { namespace mapping {
3732

3833
Deserializer::InData::InData(PGresult* dbres, int row, int col, const std::shared_ptr<const data::mapping::TypeResolver>& pTypeResolver) {
@@ -69,9 +64,9 @@ Deserializer::Deserializer() {
6964
setDeserializerMethod(data::mapping::type::__class::AbstractObject::CLASS_ID, nullptr);
7065
setDeserializerMethod(data::mapping::type::__class::AbstractEnum::CLASS_ID, &Deserializer::deserializeEnum);
7166

72-
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, nullptr);
73-
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, nullptr);
74-
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, nullptr);
67+
setDeserializerMethod(data::mapping::type::__class::AbstractVector::CLASS_ID, &Deserializer::deserializeArray<oatpp::AbstractVector>);
68+
setDeserializerMethod(data::mapping::type::__class::AbstractList::CLASS_ID, &Deserializer::deserializeArray<oatpp::AbstractList>);
69+
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID, &Deserializer::deserializeArray<oatpp::AbstractUnorderedSet>);
7570

7671
setDeserializerMethod(data::mapping::type::__class::AbstractPairList::CLASS_ID, nullptr);
7772
setDeserializerMethod(data::mapping::type::__class::AbstractUnorderedMap::CLASS_ID, nullptr);
@@ -261,9 +256,9 @@ oatpp::Void Deserializer::deserializeEnum(const Deserializer* _this, const InDat
261256

262257
}
263258

264-
const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
259+
const oatpp::Type* Deserializer::guessAnyType(const InData& data) {
265260

266-
switch(oid) {
261+
switch(data.oid) {
267262

268263
case TEXTOID:
269264
case VARCHAROID: return oatpp::String::Class::getType();
@@ -281,6 +276,24 @@ const oatpp::Type* Deserializer::guessAnyType(Oid oid) {
281276

282277
case UUIDOID: return oatpp::postgresql::Uuid::Class::getType();
283278

279+
// Arrays
280+
281+
case TEXTARRAYOID:
282+
case VARCHARARRAYOID: return generateMultidimensionalArrayType<oatpp::String>(data);
283+
284+
case INT2ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int16>(data);
285+
case INT4ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int32>(data);
286+
case INT8ARRAYOID: return generateMultidimensionalArrayType<oatpp::Int64>(data);
287+
288+
case FLOAT4ARRAYOID: return generateMultidimensionalArrayType<oatpp::Float32>(data);
289+
case FLOAT8ARRAYOID: return generateMultidimensionalArrayType<oatpp::Float64>(data);
290+
291+
case BOOLARRAYOID: return generateMultidimensionalArrayType<oatpp::Boolean>(data);
292+
293+
case TIMESTAMPARRAYOID: return generateMultidimensionalArrayType<oatpp::UInt64>(data);
294+
295+
case UUIDARRAYOID: return generateMultidimensionalArrayType<oatpp::postgresql::Uuid>(data);
296+
284297
}
285298

286299
return nullptr;
@@ -290,7 +303,11 @@ oatpp::Void Deserializer::deserializeAny(const Deserializer* _this, const InData
290303

291304
(void) type;
292305

293-
const Type* valueType = guessAnyType(data.oid);
306+
if(data.isNull) {
307+
return oatpp::Any();
308+
}
309+
310+
const Type* valueType = guessAnyType(data);
294311
if(valueType == nullptr) {
295312
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeAny()]: Error. Unknown OID.");
296313
}
@@ -314,4 +331,25 @@ oatpp::Void Deserializer::deserializeUuid(const Deserializer* _this, const InDat
314331

315332
}
316333

334+
oatpp::Void Deserializer::deserializeSubArray(const Type* type,
335+
ArrayDeserializationMeta& meta,
336+
v_int32 dimension)
337+
{
338+
339+
if(data::mapping::type::__class::AbstractVector::CLASS_ID.id == type->classId.id) {
340+
return deserializeSubArray<oatpp::AbstractVector>(type, meta, dimension);
341+
342+
} else if(data::mapping::type::__class::AbstractList::CLASS_ID.id == type->classId.id) {
343+
return deserializeSubArray<oatpp::AbstractList>(type, meta, dimension);
344+
345+
} else if(data::mapping::type::__class::AbstractUnorderedSet::CLASS_ID.id == type->classId.id) {
346+
return deserializeSubArray<oatpp::AbstractUnorderedSet>(type, meta, dimension);
347+
348+
}
349+
350+
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeSubArray()]: "
351+
"Error. Unknown 1D collection type.");
352+
353+
}
354+
317355
}}}

src/oatpp-postgresql/mapping/Deserializer.hpp

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,20 @@
2525
#ifndef oatpp_postgresql_mapping_Deserializer_hpp
2626
#define oatpp_postgresql_mapping_Deserializer_hpp
2727

28+
#include "PgArray.hpp"
29+
30+
#include "oatpp/core/data/stream/BufferStream.hpp"
2831
#include "oatpp/core/data/mapping/TypeResolver.hpp"
2932
#include "oatpp/core/Types.hpp"
3033

3134
#include <libpq-fe.h>
3235

36+
#if defined(WIN32) || defined(_WIN32)
37+
#include <WinSock2.h>
38+
#else
39+
#include <arpa/inet.h>
40+
#endif
41+
3342
namespace oatpp { namespace postgresql { namespace mapping {
3443

3544
/**
@@ -40,6 +49,8 @@ class Deserializer {
4049

4150
struct InData {
4251

52+
InData() = default;
53+
4354
InData(PGresult* dbres, int row, int col, const std::shared_ptr<const data::mapping::TypeResolver>& pTypeResolver);
4455

4556
std::shared_ptr<const data::mapping::TypeResolver> typeResolver;
@@ -59,7 +70,7 @@ class Deserializer {
5970
static v_int64 deInt8(const InData& data);
6071
static v_int64 deInt(const InData& data);
6172

62-
static const oatpp::Type* guessAnyType(Oid oid);
73+
static const oatpp::Type* guessAnyType(const InData& data);
6374
private:
6475
std::vector<DeserializerMethod> m_methods;
6576
public:
@@ -96,6 +107,139 @@ class Deserializer {
96107

97108
static oatpp::Void deserializeUuid(const Deserializer* _this, const InData& data, const Type* type);
98109

110+
template<typename T>
111+
static const oatpp::Type* generateMultidimensionalArrayType(const InData& data) {
112+
113+
if(data.size < sizeof(v_int32)) {
114+
return nullptr;
115+
}
116+
117+
auto ndim = (v_int32) ntohl(*((p_int32)data.data));
118+
119+
switch (ndim) {
120+
121+
case 0: return MultidimensionalArray<T, 1>::getClassType();
122+
case 1: return MultidimensionalArray<T, 1>::getClassType();
123+
case 2: return MultidimensionalArray<T, 2>::getClassType();
124+
case 3: return MultidimensionalArray<T, 3>::getClassType();
125+
case 4: return MultidimensionalArray<T, 4>::getClassType();
126+
case 5: return MultidimensionalArray<T, 5>::getClassType();
127+
case 6: return MultidimensionalArray<T, 6>::getClassType();
128+
case 7: return MultidimensionalArray<T, 7>::getClassType();
129+
case 8: return MultidimensionalArray<T, 8>::getClassType();
130+
case 9: return MultidimensionalArray<T, 9>::getClassType();
131+
case 10: return MultidimensionalArray<T, 10>::getClassType(); // Max 10 dimensions should be enough :)
132+
133+
default:
134+
break;
135+
136+
}
137+
138+
return nullptr;
139+
140+
}
141+
142+
struct ArrayDeserializationMeta {
143+
144+
ArrayDeserializationMeta(const Deserializer* p_this,
145+
const InData* pData)
146+
: _this(p_this)
147+
, data(pData)
148+
, stream(nullptr, (p_char8)pData->data, pData->size)
149+
{
150+
ArrayUtils::readArrayHeader(&stream, arrayHeader, dimensions);
151+
}
152+
153+
const Deserializer* _this;
154+
const InData* data;
155+
data::stream::BufferInputStream stream;
156+
PgArrayHeader arrayHeader;
157+
std::vector<v_int32> dimensions;
158+
159+
};
160+
161+
static oatpp::Void deserializeSubArray(const Type* type,
162+
ArrayDeserializationMeta& meta,
163+
v_int32 dimension);
164+
165+
template<class Collection>
166+
static oatpp::Void deserializeSubArray(const Type* type,
167+
ArrayDeserializationMeta& meta,
168+
v_int32 dimension)
169+
{
170+
171+
if(dimension < meta.dimensions.size() - 1) {
172+
173+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
174+
auto itemType = *type->params.begin();
175+
auto listWrapper = polymorphicDispatcher->createObject();
176+
177+
auto size = meta.dimensions[dimension];
178+
179+
for(v_int32 i = 0; i < size; i ++) {
180+
const auto& item = deserializeSubArray(itemType, meta, dimension + 1);
181+
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
182+
}
183+
184+
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
185+
186+
} else if(dimension == meta.dimensions.size() - 1) {
187+
188+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
189+
auto itemType = *type->params.begin();
190+
auto listWrapper = polymorphicDispatcher->createObject();
191+
192+
auto size = meta.dimensions[dimension];
193+
194+
for(v_int32 i = 0; i < size; i ++) {
195+
196+
v_int32 dataSize;
197+
meta.stream.readSimple(&dataSize, sizeof(v_int32));
198+
199+
InData itemData;
200+
itemData.typeResolver = meta.data->typeResolver;
201+
itemData.size = (v_int32) ntohl(dataSize);
202+
itemData.data = (const char*) &meta.stream.getData()[meta.stream.getCurrentPosition()];
203+
itemData.oid = meta.arrayHeader.oid;
204+
itemData.isNull = itemData.size < 0;
205+
206+
if(itemData.size > 0) {
207+
meta.stream.setCurrentPosition(meta.stream.getCurrentPosition() + itemData.size);
208+
}
209+
210+
const auto& item = meta._this->deserialize(itemData, itemType);
211+
212+
polymorphicDispatcher->addPolymorphicItem(listWrapper, item);
213+
214+
}
215+
216+
return oatpp::Void(listWrapper.getPtr(), listWrapper.valueType);
217+
218+
}
219+
220+
throw std::runtime_error("[oatpp::postgresql::mapping::Deserializer::deserializeSubArray()]: "
221+
"Error. Invalid state: dimension >= dimensions.size().");
222+
223+
}
224+
225+
template<class Collection>
226+
static oatpp::Void deserializeArray(const Deserializer* _this, const InData& data, const Type* type) {
227+
228+
if(data.isNull) {
229+
return oatpp::Void(nullptr, type);
230+
}
231+
232+
auto ndim = (v_int32) ntohl(*((p_int32)data.data));
233+
if(ndim == 0) {
234+
auto polymorphicDispatcher = static_cast<const typename Collection::Class::PolymorphicDispatcher*>(type->polymorphicDispatcher);
235+
return polymorphicDispatcher->createObject(); // empty array
236+
}
237+
238+
ArrayDeserializationMeta meta(_this, &data);
239+
return deserializeSubArray(type, meta, 0);
240+
241+
}
242+
99243
};
100244

101245
}}}

0 commit comments

Comments
 (0)