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+ 3342namespace 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 );
6374private:
6475 std::vector<DeserializerMethod> m_methods;
6576public:
@@ -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