55  getKeys  =  { getter : true ,  required : [ 'keys' ] } , 
66  getMember  =  { getter : true ,  required : [ '_id' ,  'member' ] } , 
77  getxScan  =  { getter : true ,  required : [ '_id' ,  'cursor' ] ,  opts : [ 'match' ,  'count' ] } , 
8-   getZrange  =  { getter : true ,  required : [ '_id' ,  'min' ,  'max' ] ,  opts : [ 'limit' ,  'options' ] } , 
8+   getZrange  =  { 
9+     getter : true , 
10+     required : [ '_id' ,  'start' ,  'stop' ] , 
11+     opts : assignZrangeOptions , 
12+     mapResults : mapZrangeResults 
13+   } , 
14+   getZrangeBy  =  { 
15+     getter : true , 
16+     required : [ '_id' ,  'min' ,  'max' ] , 
17+     opts : assignZrangeOptions , 
18+     mapResults : mapZrangeResults 
19+   } , 
920  setId  =  { required : [ '_id' ] } , 
1021  setIdValue  =  { required : [ '_id' ,  'value' ] } , 
1122  setIdFieldValue  =  { required : [ '_id' ,  'field' ,  'value' ] } , 
12-   setIdEntries  =  { required : [ '_id' ,   'entries' ] } ; 
23+   setEntries  =  { required : [ 'entries' ] } ; 
1324
1425// Redis commands 
1526var 
5465    hdel : { required : [ '_id' ,  'fields' ] } , 
5566    hexists : getIdField , 
5667    hget : getIdField , 
57-     hgetall : getId , 
68+     hgetall : { getter :  true ,   required :  [ '_id' ] ,   mapResults :  mapKeyValueResults } , 
5869    hincrby : setIdFieldValue , 
5970    hincrbyfloat : { required : [ '_id' ,  'field' ,  'value' ] ,  mapResults : parseFloat } , 
6071    hkeys : getId , 
6172    hlen : getId , 
6273    hmget : { getter : true ,  required : [ '_id' ,  'fields' ] } , 
63-     hmset : setIdEntries , 
74+     hmset : { required :  [ '_id' ,   'entries' ] } , 
6475    hscan : getxScan , 
6576    hset : setIdFieldValue , 
6677    hsetnx : setIdFieldValue , 
6980    incr : setId , 
7081    incrby : setIdValue , 
7182    incrbyfloat : { required : [ '_id' ,  'value' ] ,  mapResults : parseFloat } , 
72-     keys : { getter : true ,  required : [ '_id'  ,   ' pattern'] } , 
83+     keys : { getter : true ,  required : [ 'pattern' ] } , 
7384    lindex : { getter : true ,  required : [ '_id' ,  'index' ] } , 
7485    linsert : { required : [ '_id' ,  'position' ,  'pivot' ,  'value' ] } , 
7586    llen : getId , 
8192    lset : { required : [ '_id' ,  'index' ,  'value' ] } , 
8293    ltrim : { required : [ '_id' ,  'start' ,  'stop' ] } , 
8394    mget : getKeys , 
84-     mset : setIdEntries , 
85-     msetnx : setIdEntries , 
95+     mset : setEntries , 
96+     msetnx : setEntries , 
8697    object : { getter : true ,  required : [ '_id' ,  'subcommand' ] } , 
8798    persist : setId , 
8899    pexpire : { required : [ '_id' ,  'milliseconds' ] } , 
103114    sadd : { required : [ '_id' ,  'members' ] } , 
104115    scan : { getter : true ,  required : [ 'cursor' ] ,  opts : [ 'match' ,  'count' ] } , 
105116    scard : getId , 
106-     sdiff : getKeys , 
117+     sdiff : { getter :  true ,   required :  [ '_id' ,   'keys' ] } , 
107118    sdiffstore : { required : [ '_id' ,  'keys' ,  'destination' ] } , 
108119    set : { required : [ '_id' ,  'value' ] ,  opts : [ 'ex' ,  'px' ,  'nx' ,  'xx' ] } , 
109120    setex : { required : [ '_id' ,  'value' ,  'seconds' ] } , 
@@ -113,15 +124,15 @@ var
113124    sismember : getMember , 
114125    smembers : getId , 
115126    smove : { required : [ '_id' ,  'destination' ,  'member' ] } , 
116-     sort : { required : [ '_id' ] ,  opts : [ 'alpha' ,  'by' ,  'direction' ,  'get' ,  'limit' ] } , 
127+     sort : { getter :  true ,   required : [ '_id' ] ,  opts : [ 'alpha' ,  'by' ,  'direction' ,  'get' ,  'limit' ] } , 
117128    spop : { required : [ '_id' ] ,  opts : [ 'count' ] ,  mapResults : mapStringToArray  } , 
118-     srandmember : { getter : true ,  required : [ '_id' ] ,  opts : [ 'count' ] } , 
129+     srandmember : { getter : true ,  required : [ '_id' ] ,  opts : [ 'count' ] ,   mapResults :  mapStringToArray } , 
119130    srem : { required : [ '_id' ,  'members' ] } , 
120131    sscan : getxScan , 
121132    strlen : getId , 
122133    sunion : getKeys , 
123-     sunionstore : { required : [ 'keys ' ,  'destination ' ] } , 
124-     time : { getter : true } , 
134+     sunionstore : { required : [ 'destination ' ,  'keys ' ] } , 
135+     time : { getter : true ,   mapResults :  mapArrayStringToArrayInt } , 
125136    touch : { required : [ 'keys' ] } , 
126137    ttl : getId , 
127138    type : getId , 
@@ -131,17 +142,17 @@ var
131142    zincrby : { required : [ '_id' ,  'member' ,  'value' ] } , 
132143    zinterstore : { required : [ '_id' ,  'keys' ] ,  opts : [ 'weights' ,  'aggregate' ] } , 
133144    zlexcount : { getter : true ,  required : [ '_id' ,  'min' ,  'max' ] } , 
134-     zrange : { getter :  true ,   required :  [ '_id' ,   'start' ,   'stop' ] ,   opts :  [ 'options' ] } , 
145+     zrange : getZrange , 
135146    zrangebylex : { getter : true ,  required : [ '_id' ,  'min' ,  'max' ] ,  opts : [ 'limit' ] } , 
136147    zrevrangebylex : { getter : true ,  required : [ '_id' ,  'min' ,  'max' ] ,  opts : [ 'limit' ] } , 
137-     zrangebyscore : getZrange , 
148+     zrangebyscore : getZrangeBy , 
138149    zrank : getMember , 
139150    zrem : { required : [ '_id' ,  'members' ] } , 
140151    zremrangebylex : { required : [ '_id' ,  'min' ,  'max' ] } , 
141152    zremrangebyrank : { required : [ '_id' ,  'start' ,  'stop' ] } , 
142153    zremrangebyscore : { required : [ '_id' ,  'min' ,  'max' ] } , 
143-     zrevrange : { getter :  true ,   required :  [ '_id' ,   'start' ,   'stop' ] ,   opts :  [ 'options' ] } , 
144-     zrevrangebyscore : getZrange , 
154+     zrevrange : getZrange , 
155+     zrevrangebyscore : getZrangeBy , 
145156    zrevrank : getMember , 
146157    zscan : getxScan , 
147158    zscore : getMember , 
@@ -221,9 +232,10 @@ function MemoryStorage(kuzzle) {
221232
222233      if  ( args . length  &&  typeof  args [ args . length  -  1 ]  ===  'function' )  { 
223234        cb  =  args . pop ( ) ; 
224-         commands [ command ] . getter  &&  this . kuzzle . callbackRequired ( 'MemoryStorage.'  +  command ,  cb ) ; 
225235      } 
226236
237+       commands [ command ] . getter  &&  this . kuzzle . callbackRequired ( 'MemoryStorage.'  +  command ,  cb ) ; 
238+ 
227239      if  ( ! commands [ command ] . getter )  { 
228240        data . body  =  { } ; 
229241      } 
@@ -248,13 +260,10 @@ function MemoryStorage(kuzzle) {
248260        throw  new  Error ( 'MemoryStorage.'  +  command  +  ': Invalid optional parameter (expected an object)' ) ; 
249261      } 
250262
251-       options  =  args [ 0 ] ; 
263+       if  ( args . length )  { 
264+         options  =  Object . assign ( { } ,  args [ 0 ] ) ; 
252265
253-       if  ( args . length  &&  commands [ command ] . opts )  { 
254-         if  ( typeof  commands [ command ] . opts  ===  'function' )  { 
255-           commands [ command ] . opts ( data ,  options ) ; 
256-         } 
257-         else  { 
266+         if  ( Array . isArray ( commands [ command ] . opts ) )  { 
258267          commands [ command ] . opts . forEach ( function  ( opt )  { 
259268            if  ( options [ opt ]  !==  null  &&  options [ opt ]  !==  undefined )  { 
260269              assignParameter ( data ,  commands [ command ] . getter ,  opt ,  options [ opt ] ) ; 
@@ -264,6 +273,14 @@ function MemoryStorage(kuzzle) {
264273        } 
265274      } 
266275
276+       /* 
277+        Options function mapper does not necessarily need 
278+        options to be passed by clients. 
279+        */ 
280+       if  ( typeof  commands [ command ] . opts  ===  'function' )  { 
281+         commands [ command ] . opts ( data ,  options  ||  { } ) ; 
282+       } 
283+ 
267284      this . kuzzle . query ( query ,  data ,  options ,  cb  &&  function  ( err ,  res )  { 
268285        if  ( err )  { 
269286          return  cb ( err ) ; 
@@ -303,7 +320,7 @@ function assignParameter(data, getter, name, value) {
303320 * Assign the provided options for the georadius* redis functions 
304321 * to the request object, as expected by Kuzzle API 
305322 * 
306-  * Mutates the provided options object  
323+  * Mutates the provided data and  options objects  
307324 * 
308325 * @param  {object } data 
309326 * @param  {object } options 
@@ -336,6 +353,23 @@ function assignGeoRadiusOptions(data, options) {
336353  } 
337354} 
338355
356+ /** 
357+  * Force the WITHSCORES option on z*range* routes 
358+  * 
359+  * Mutates the provided data and options objects 
360+  * 
361+  * @param  {object } data 
362+  * @param  {object } options 
363+  */ 
364+ function  assignZrangeOptions ( data ,  options )  { 
365+   data . options  =  [ 'withscores' ] ; 
366+ 
367+   if  ( options . limit )  { 
368+     data . limit  =  options . limit ; 
369+     delete  options . limit ; 
370+   } 
371+ } 
372+ 
339373/** 
340374 * Maps geopos results, from array<array<string>> to array<array<number>> 
341375 * 
@@ -407,4 +441,78 @@ function mapStringToArray (results) {
407441  return  Array . isArray ( results )  ? results  : [ results ] ; 
408442} 
409443
444+ /** 
445+  * Map an array of strings to an array of integers 
446+  * 
447+  * @param  {Array.<string> } results 
448+  * @return  {Array.<Number> } 
449+  */ 
450+ function  mapArrayStringToArrayInt ( results )  { 
451+   return  results . map ( function  ( value )  { 
452+     return  parseInt ( value ) ; 
453+   } ) ; 
454+ } 
455+ 
456+ /** 
457+  * Map results like ['key', 'value', 'key', 'value', ...] 
458+  * to a JSON object {key: 'value', ...} 
459+  * 
460+  * @param  {Array.<string> } results 
461+  * @return  {Object } 
462+  */ 
463+ function  mapKeyValueResults ( results )  { 
464+   var 
465+     buffer  =  null , 
466+     mapped  =  { } ; 
467+ 
468+   results . forEach ( function  ( value )  { 
469+     if  ( buffer  ===  null )  { 
470+       buffer  =  value ; 
471+     } 
472+     else  { 
473+       mapped [ buffer ]  =  value ; 
474+       buffer  =  null ; 
475+     } 
476+   } ) ; 
477+ 
478+   return  mapped ; 
479+ } 
480+ 
481+ /** 
482+  * Map zrange results with WITHSCORES: 
483+  * [ 
484+  *  "member1", 
485+  *  "score of member1", 
486+  *  "member2", 
487+  *  "score of member2" 
488+  * ] 
489+  * 
490+  * into the following format: 
491+  * [ 
492+  *  {"member": "member1", "score": <score of member1>}, 
493+  *  {"member": "member2", "score": <score of member2>}, 
494+  * ] 
495+  * 
496+  * 
497+  * @param  {Array.<string> } results 
498+  * @return  {Array.<Object> } 
499+  */ 
500+ function  mapZrangeResults ( results )  { 
501+   var 
502+     buffer  =  null , 
503+     mapped  =  [ ] ; 
504+ 
505+   results . forEach ( function  ( value )  { 
506+     if  ( buffer  ===  null )  { 
507+       buffer  =  value ; 
508+     } 
509+     else  { 
510+       mapped . push ( { member : buffer ,  score : parseFloat ( value ) } ) ; 
511+       buffer  =  null ; 
512+     } 
513+   } ) ; 
514+ 
515+   return  mapped ; 
516+ } 
517+ 
410518module . exports  =  MemoryStorage ; 
0 commit comments