@@ -200,105 +200,80 @@ msgpacks. See section below to understand how to decode tuples.
200200### Data manipulation  
201201
202202Now let's consider a bit more sophisticated requests.
203- Assume we have space with ` id = 512 `  and following format on the server:
204- ` CREATE TABLE t(id INT PRIMARY KEY, a  TEXT, b  DOUBLE); `    
205- Preparing analogue of ` t:replace( 1, "111", 1.01) ; `  request can be done this way:
203+ Assume we have a  space with ` id = 512 `  and following format on the server:
204+ ` CREATE TABLE t(id INT PRIMARY KEY, name  TEXT, coef  DOUBLE); ` 
205+ Preparing analogue of ` t:replace{ 1, "111", 1.01} ; `  request can be done this way:
206206
207207``` 
208- std::tuple data = std::make_tuple(1 /* field 1 */, "111" /* field 2 */, 1.01 /* field 3 */); 
209- rid_t replace  = conn.space[512].replace(data); 
208+ std::tuple data = std::make_tuple(1 /*id */, "111" /*name */, 1.01 /*coef */); 
209+ rid_t my_replace  = conn.space[512].replace(data); 
210210``` 
211- To execute select query ` t.index[1]:select({1}, {limit = 1}) ` :
212- 
213- ``` 
214- auto i = conn.space[512].index[1]; 
215- rid_t select = i.select(std::make_tuple(1), 1, 0 /*offset*/, IteratorType::EQ); 
216- ``` 
217- 
218- ### Data readers  
219211
220- Responses from server contain raw data (i.e. encoded into msgpuck tuples). To
221- decode client's data, users have to write their own decoders (based on featured
222- schema). Let's define structure describing data stored in space ` t ` :
212+ As a good alternative, we could use structure instead of std::tuple, but we
213+ would have to provide once a way how it must be encoded:
223214
224215``` 
225216struct UserTuple { 
226-     uint64_t field1; 
227-     std::string field2; 
228-     double field3; 
217+     uint64_t id; 
218+     std::string name; 
219+     double coef; 
220+ 
221+     static constexpr auto mpp = std::make_tuple( 
222+         &UserTuple::id, &UserTuple::name, &UserTuple::coef); 
229223}; 
224+ 
225+ ... 
226+ 
227+ UserTuple tuple{.id = 1, .name = "aa", .coef = 1.01}; 
228+ rid_t my_replace = conn.space[512].replace(data); 
230229``` 
231230
232- Prototype of the base reader is given in ` src/mpp/Dec.hpp ` :
231+ To execute select query ` t.index[1]:select({1}, {limit = 1}) ` :
232+ 
233233``` 
234- template <class BUFFER, Type TYPE> 
235- struct SimpleReaderBase : DefaultErrorHandler { 
236-     using BufferIterator_t = typename BUFFER::iterator; 
237-     /* Allowed type of values to be parsed. */ 
238-     static constexpr Type VALID_TYPES = TYPE; 
239-     BufferIterator_t* StoreEndIterator() { return nullptr; } 
240- }; 
234+ auto i = conn.space[512].index[1]; 
235+ rid_t my_select = i.select(std::make_tuple(1), 1, 0 /*offset*/, IteratorType::EQ); 
241236``` 
242- So every new reader should inherit from it or directly from ` DefaultErrorHandler ` .
243- To parse particular value, we should define ` Value() `  method. First two arguments
244- are common and unused as a rule, but the third - defines parsed value. So in
245- case of POD stuctures it's enough to provide byte-to-byte copy. Since in our
246- schema there are fields of three different types, let's descripe three ` Value() ` 
247- functions:
237+ 
238+ ### Decoding result  
239+ 
240+ Responses from server contain raw data (i.e. encoded into msgpuck tuples).
241+ To decode client's data, we have to provide user storage that implicitly 
242+ describes tuple format. For example, we know that the space (and each tuple)
243+ has three fields: unsigned, string and number.
244+ Then std::tuple<uint64_t, std::string, double> can be used as complete storage 
245+ for decoding tuples of such space. Since select returns a dynamic array of
246+ tuples, the storage also must be a dynamic array (for example, vector):
247+ 
248248``` 
249- struct UserTupleValueReader : mpp::DefaultErrorHandler { 
250-     /* Store instance of tuple to be parsed. */ 
251-     UserTuple& tuple; 
252-     /* Enumerate all types which can be parsed. Otherwise */ 
253-     static constexpr mpp::Type VALID_TYPES = mpp::MP_UINT | mpp::MP_STR | mpp::MP_DBL; 
254-     UserTupleValueReader(UserTuple& t) : tuple(t) {} 
255- 
256-     /* Value's extractors. */ 
257-     void Value(const BufIter_t&, mpp::compact::Type, uint64_t u) 
258-     { 
259-        tuple.field1 = u; 
260-     } 
261-     void Value(const BufIter_t&, mpp::compact::Type, double d) 
262-     { 
263-         tuple.field3 = d; 
264-     } 
265-     void Value(const BufIter_t& itr, mpp::compact::Type, mpp::StrValue v) 
266-     { 
267-         BufIter_t tmp = itr; 
268-         tmp += v.offset; 
269-         std::string &dst = tuple.field2; 
270-         while (v.size) { 
271-             dst.push_back(*tmp); 
272-             ++tmp; 
273-             --v.size; 
274-         } 
275-     } 
276- }; 
249+ rid_t my_select = i.select(....); 
250+ // wait for response... 
251+ assert(conn.futureIsReady(my_select)); 
252+ auto response = conn.getResponse(my_select); 
253+ std::vector<std::tuple<uint64_t, std::string, double>> results; 
254+ response.body.data.decode(results); 
255+ // use results... 
277256``` 
278- It is worth mentioning that tuple itself is wrapped into array, so in fact
279- firstly we should parse array. Let's define another one reader:
257+ 
258+ std::tuple is good since it has clearly readable format, but common structures
259+ are much more convenient to use. To decode structures we have to declare their
260+ format for decoder:
261+ 
280262``` 
281- template <class BUFFER> 
282- struct UserTupleReader : mpp::SimpleReaderBase<BUFFER, mpp::MP_ARR> { 
283-     mpp::Dec<BUFFER>& dec; 
284-     UserTuple& tuple; 
285- 
286-     UserTupleReader(mpp::Dec<BUFFER>& d, UserTuple& t) : dec(d), tuple(t) {} 
287-     void Value(const iterator_t<BUFFER>&, mpp::compact::Type, mpp::ArrValue) 
288-     { 
289-         dec.SetReader(false, UserTupleValueReader{tuple}); 
290-     } 
263+ struct UserTuple { 
264+     uint64_t id; 
265+     std::string name; 
266+     double coef; 
267+ 
268+     static constexpr auto mpp = std::make_tuple( 
269+         &UserTuple::id, &UserTuple::name, &UserTuple::coef); 
291270}; 
292- ``` 
293- ` SetReader(); `  sets the reader which is invoked while every entry of the array is
294- parsed. Now, to make these two readers work, we should create decoder, set
295- its iterator to the position of encoded tuple and invoke ` Read() `  method:
296- ``` 
297-     UserTuple tuple; 
298-     mpp::Dec dec(conn.getInBuf()); 
299-     dec.SetPosition(*t.begin); 
300-     dec.SetReader(false, UserTupleReader<BUFFER>{dec, tuple}); 
301-     dec.Read(); 
271+ 
272+ // Perform select and wait for result... 
273+ auto response = conn.getResponse(my_select); 
274+ std::vector<UserTuple> results; 
275+ response.body.data.decode(results); 
276+ // use results... 
302277``` 
303278
304279### Writing custom buffer and network provider  
0 commit comments