1 | /**
|
2 | * Load dependencies
|
3 | */
|
4 | var querystring = require('querystring'),
|
5 | format = require('./utils/format');
|
6 |
|
7 |
|
8 | /**
|
9 | * Expose `Query`
|
10 | */
|
11 |
|
12 | module.exports = exports = Query;
|
13 |
|
14 | /**
|
15 | * Create a new `Query`
|
16 | * @constructor
|
17 | *
|
18 | * @return {Query}
|
19 | * @api private
|
20 | */
|
21 |
|
22 | function Query(){
|
23 | this.parameters = [];
|
24 | }
|
25 |
|
26 | /**
|
27 | * Set a new parameter
|
28 | * Since all possibilities provided by Solr are not available in the `Query` object, `set()` is there to fit this gap.
|
29 | *
|
30 | * @param {String} parameter - string, special characters have to be correctly encoded or the request will fail.
|
31 | *
|
32 | * @return {Query} - allow chaining
|
33 | * @api public
|
34 | */
|
35 | Query.prototype.set = function(parameter){
|
36 | var self = this;
|
37 | this.parameters.push(parameter);
|
38 | return self;
|
39 | }
|
40 |
|
41 | /**
|
42 | * Set the query parser to use with this request.
|
43 | *
|
44 | * @param {String} type - name of the query parser e.g: 'dismax'
|
45 | *
|
46 | * @return {Query}
|
47 | * @api public
|
48 | */
|
49 |
|
50 | Query.prototype.defType = function(type){
|
51 | var self = this;
|
52 | var parameter = 'defType=' + type;
|
53 | this.parameters.push(parameter);
|
54 | return self;
|
55 | }
|
56 |
|
57 | /**
|
58 | * Set the Request Handler used to process the request based on its `name`.
|
59 | * Works only if no Request Handler has been configured with `/select` as its name in solrconfig.xml.
|
60 | *
|
61 | * @param {String} name - name of the Request Handler
|
62 | *
|
63 | * @return {Query}
|
64 | * @api public
|
65 | */
|
66 |
|
67 | Query.prototype.requestHandler =
|
68 | Query.prototype.qt = function(name){
|
69 | var self = this;
|
70 | var parameter = 'qt=' + name;
|
71 | this.parameters.push(parameter);
|
72 | return self;
|
73 | }
|
74 |
|
75 | /**
|
76 | * Set the main query
|
77 | *
|
78 | * @param {String|Object} q -
|
79 | *
|
80 | * @return {Query}
|
81 | * @api public
|
82 | */
|
83 |
|
84 | Query.prototype.q = function(q){
|
85 | var self = this;
|
86 | var parameter ='q=';
|
87 | if ( typeof(q) === 'string' ){
|
88 | parameter += encodeURIComponent(q);
|
89 | }else{
|
90 | parameter += querystring.stringify(q, '%20AND%20',':');
|
91 | }
|
92 | this.parameters.push(parameter);
|
93 | return self;
|
94 | }
|
95 |
|
96 | /**
|
97 | * Set the offset where the set of returned documents should begin.
|
98 | *
|
99 | * @param {Number} start - the offset where the set of returned documents should begin.
|
100 | *
|
101 | * @return {Query}
|
102 | * @api public
|
103 | */
|
104 |
|
105 | Query.prototype.start = function(start){
|
106 | var self = this;
|
107 | var parameter = 'start=' + start ;
|
108 | this.parameters.push(parameter);
|
109 | return self;
|
110 | }
|
111 |
|
112 | /**
|
113 | * Set the maximum number of documents returned
|
114 | *
|
115 | * @param {Number} rows - number of documents
|
116 | *
|
117 | * @return {Query}
|
118 | * @api public
|
119 | */
|
120 | Query.prototype.rows = function(rows){
|
121 | var self = this;
|
122 | var parameter = 'rows=' + rows ;
|
123 | this.parameters.push(parameter);
|
124 | return self;
|
125 | }
|
126 |
|
127 | /**
|
128 | * Sort a result in descending or ascending order based on one or more fields.
|
129 | *
|
130 | * @param {Object} options -
|
131 | *
|
132 | * @return {Query}
|
133 | * @api public
|
134 | */
|
135 |
|
136 | Query.prototype.sort = function(options){
|
137 | var self = this;
|
138 | var parameter = 'sort=';
|
139 | parameter += querystring.stringify(options, ',' , '%20');
|
140 | this.parameters.push(parameter);
|
141 | return self;
|
142 | }
|
143 |
|
144 | /**
|
145 | * Filter the set of documents found before to return the result with the given range determined by `field`, `start` and `end`.
|
146 | *
|
147 | * @param {Array|Object} options -
|
148 | * @param {String} options.field - the name of the field where the range is applied
|
149 | * @param {String|Number|Date} options.start - the offset where the range starts
|
150 | * @param {String|Number|Date} options.end - the offset where the range ends
|
151 | *
|
152 | * @return {Query}
|
153 | * @api public
|
154 | *
|
155 | * @example
|
156 | * var query = client.createQuery();
|
157 | * query.q({ '*' : '*' }).rangeFilter({ field : 'id', start : 100, end : 200})
|
158 | * // also works
|
159 | * query.q({ '*' : '*' }).rangeFilter([{ field : 'id', start : 100, end : 200},{ field : 'date', start : new Date(), end : new Date() - 3600}]);
|
160 | */
|
161 |
|
162 | Query.prototype.rangeFilter = function(options){
|
163 | var self = this;
|
164 | options = format.dateISOify(options);
|
165 | var parameter = 'fq=';
|
166 | if(Array.isArray(options)){
|
167 | parameter += "(";
|
168 | var filters = options.map(function(option){
|
169 | var key = option.field;
|
170 | var filter = {};
|
171 | filter[key] = '[' + encodeURIComponent(option.start) + '%20TO%20' + encodeURIComponent(option.end) + ']';
|
172 | return format.stringify(filter, '',':');
|
173 | });
|
174 | parameter += filters.join('%20AND%20');
|
175 | parameter += ")";
|
176 | }else{
|
177 | var key = options.field;
|
178 | var filter = {};
|
179 | filter[key] = '[' + encodeURIComponent(options.start) + '%20TO%20' + encodeURIComponent(options.end) + ']';
|
180 | parameter += format.stringify(filter, '',':');
|
181 | }
|
182 | this.parameters.push(parameter);
|
183 | return self;
|
184 | }
|
185 |
|
186 | /**
|
187 | * Filter the set of documents found before to return the result with the given `field` and `value`.
|
188 | *
|
189 | * @param {String} field - name of field
|
190 | * @param {String|Number|Date} value - value of the field that must match
|
191 | *
|
192 | * @return {Query}
|
193 | * @api public
|
194 | *
|
195 | * @example
|
196 | * var query = client.createQuery();
|
197 | * query.q({ '*' : '*' }).matchFilter('id', 100)
|
198 | */
|
199 |
|
200 | Query.prototype.matchFilter = function(field,value){
|
201 | var self = this;
|
202 | value = format.dateISOify(value);
|
203 | var parameter = 'fq=';
|
204 | parameter += field + ':' + encodeURIComponent(value);
|
205 | this.parameters.push(parameter);
|
206 | return self;
|
207 | }
|
208 |
|
209 | /**
|
210 | * Specify a set of fields to return.
|
211 | *
|
212 | * @param {String|Array} field - field name
|
213 | *
|
214 | * @return {Query}
|
215 | * @api public
|
216 | */
|
217 |
|
218 | Query.prototype.fl =
|
219 | Query.prototype.restrict = function(fields){
|
220 | var self = this;
|
221 | var parameter = 'fl=';
|
222 | if(typeof(fields) === 'string'){
|
223 | parameter += fields;
|
224 | }else{
|
225 | parameter += fields.join(',');
|
226 | }
|
227 | this.parameters.push(parameter);
|
228 | return self;
|
229 | }
|
230 |
|
231 | /**
|
232 | * Set the time allowed for a search to finish.
|
233 | * Partial results may be returned (if there are any).
|
234 | *
|
235 | * @param {String|Number} time - time is in milliseconds. Values <= 0 mean no time restriction.
|
236 | *
|
237 | * @return {Query}
|
238 | * @api public
|
239 | */
|
240 |
|
241 | Query.prototype.timeout = function(time){
|
242 | var self = this;
|
243 | var parameter = 'timeAllowed=' + time;
|
244 | this.parameters.push(parameter);
|
245 | return self;
|
246 | }
|
247 |
|
248 | /**
|
249 | * Group documents with the given `field`
|
250 | *
|
251 | * @param {String} field - field name
|
252 | *
|
253 | * @return {Query}
|
254 | * @api public
|
255 | */
|
256 |
|
257 | Query.prototype.groupBy = function(field){
|
258 | var self = this;
|
259 | this.group({
|
260 | 'field': field
|
261 | });
|
262 | return self;
|
263 | }
|
264 |
|
265 | /**
|
266 | * Group documents using field collapsing or result grouping feature.
|
267 | * Field Collapsing collapses a group of results with the same field value down to a single (or fixed number) of entries.
|
268 | * Result Grouping groups documents with a common field value into groups, returning the top documents per group, and the top groups based on what documents are in the groups.
|
269 | *
|
270 | * @param {Object} options
|
271 | * @param {Boolean} [options.on=true] - if false, turn off result grouping, otherwise turn on.
|
272 | * @param {String} options.field - Group based on the unique values of a field.
|
273 | * @param {Number} [options.limit=1] - The number of results (documents) to return for each group. Solr's default value is 1.
|
274 | * @param {Number} options.offset - The offset into the document list of each group.
|
275 | * @param {String} [options.sort="score desc"] - How to sort documents within a single group. Defaults to the same value as the sort parameter.
|
276 | * @param {String} options.format - if simple, the grouped documents are presented in a single flat list. The start and rows parameters refer to numbers of documents instead of numbers of groups.
|
277 | * @param {Boolean} options.main - If true, the result of the last field grouping command is used as the main result list in the response, using group.format=simple.
|
278 | * @param {Boolean} [options.ngroups=false] - If true, includes the number of groups that have matched the query. Default is false.
|
279 | * @param {Boolean} options.truncate - If true, facet counts are based on the most relevant document of each group matching the query. Same applies for StatsComponent. Default is false.
|
280 | * @param {Number} [options.cache=0] - If > 0 enables grouping cache. Grouping is executed actual two searches. This option caches the second search. A value of 0 disables grouping caching. Default is 0.
|
281 | *
|
282 | * @return {Query}
|
283 | * @api public
|
284 | */
|
285 |
|
286 | Query.prototype.group = function(options){
|
287 | var self = this;
|
288 | if(options.on === false){
|
289 | this.parameters.push('group=false');
|
290 | }else{
|
291 | this.parameters.push('group=true');
|
292 | }
|
293 | if( options.field ){
|
294 | this.parameters.push('group.field=' + options.field);
|
295 | }
|
296 | if( options.limit !== undefined){
|
297 | this.parameters.push('group.limit=' + options.limit);
|
298 | }
|
299 | if( options.offset !== undefined){
|
300 | this.parameters.push('group.offset=' + options.offset);
|
301 | }
|
302 | if( options.sort ){
|
303 | this.parameters.push('group.sort=' + encodeURIComponent(options.sort));
|
304 | }
|
305 | if( options.format ){
|
306 | this.parameters.push('group.format=' + encodeURIComponent(options.format));
|
307 | }
|
308 | if( options.main !== undefined){
|
309 | this.parameters.push('group.main=' + options.main);
|
310 | }
|
311 | if( options.ngroups !== undefined){
|
312 | this.parameters.push('group.ngroups=' + options.ngroups);
|
313 | }
|
314 | if( options.truncate !== undefined){
|
315 | this.parameters.push('group.truncate=' + options.truncate);
|
316 | }
|
317 | if( options.cache !== undefined){
|
318 | this.parameters.push('group.cache.percent=' + options.cache);
|
319 | }
|
320 | return self;
|
321 | }
|
322 |
|
323 | /**
|
324 | * Create a facet
|
325 | *
|
326 | * @param {Object} options - set of options to create a facet
|
327 | * @param {Boolean} [options.on=true] - Turn on or off facet
|
328 | * @param {String} [options.query] - This parameter allows you to specify an arbitrary query in the Lucene default syntax to generate a facet count. By default, faceting returns a count of the unique terms for a "field", while facet.query allows you to determine counts for arbitrary terms or expressions.
|
329 | * @param {String} options.field - This parameter allows you to specify a field which should be treated as a facet. It will iterate over each Term in the field and generate a facet count using that Term as the constraint.
|
330 | * @param {String} [options.prefix] - Limits the terms on which to facet to those starting with the given string prefix.
|
331 | * @param {String} [options.sort] - This param determines the ordering of the facet field constraints.count
|
332 | * @param {Number} [options.limit=100] - This parameter indicates the maximum number of constraint counts that should be returned for the facet fields. A negative value means unlimited.The solr's default value is 100.
|
333 | * @param {Number} [options.offset=0] - This param indicates an offset into the list of constraints to allow paging.The solr's default value is 0.
|
334 | * @param {Number} [options.mincount=0] - This parameter indicates the minimum counts for facet fields should be included in the response. The solr's default value is 0.
|
335 | * @param {Boolean} [options.missing=false] - Set to `true` this param indicates that in addition to the Term based constraints of a facet field, a count of all matching results which have no value for the field should be computed. The solr's default value is false.
|
336 | * @param {String} [options.method="fc"] - This parameter indicates what type of algorithm/method to use when faceting a field.The solr's default value is fc (except for BoolField).
|
337 | *
|
338 | * @return {Query}
|
339 | * @api public
|
340 | */
|
341 | Query.prototype.facet = function(options){
|
342 | var self = this;
|
343 | if(options.on === false){
|
344 | this.parameters.push('facet=false');
|
345 | }else{
|
346 | this.parameters.push('facet=true');
|
347 | }
|
348 | if(options.query){
|
349 | this.parameters.push('facet.query=' + encodeURIComponent(options.query))
|
350 | }
|
351 | if(options.field){
|
352 | this.parameters.push('facet.field=' + options.field)
|
353 | }
|
354 | if(options.prefix){
|
355 | this.parameters.push('facet.prefix=' + encodeURIComponent(options.prefix))
|
356 | }
|
357 | if(options.sort){
|
358 | this.parameters.push('facet.sort=' + encodeURIComponent(options.sort))
|
359 | }
|
360 | if(options.limit !== undefined){
|
361 | this.parameters.push('facet.limit=' + options.limit);
|
362 | }
|
363 | if(options.offset !== undefined){
|
364 | this.parameters.push('facet.offset=' + options.offset);
|
365 | }
|
366 | if(options.mincount !== undefined){
|
367 | this.parameters.push('facet.mincount=' + options.mincount);
|
368 | }
|
369 | if(options.missing !== undefined){
|
370 | this.parameters.push('facet.missing=' + options.missing);
|
371 | }
|
372 | if(options.method){
|
373 | this.parameters.push('facet.method=' + options.method);
|
374 | }
|
375 | return self;
|
376 | }
|
377 |
|
378 | /**
|
379 | * Create a MoreLikeThis. MoreLikeThis constructs a lucene query based on terms within a document.
|
380 | *
|
381 | * @param {Object} options - set of options to create a morelikethis
|
382 | * @param {Boolean} [options.on=true] - Turn on or off morelikethis
|
383 | * @param {String|Array} [options.fl] - The fields to use for similarity. NOTE: if possible, these should have a stored TermVector
|
384 | * @param {Number} [options.count] - The number of similar documents to return for each result.
|
385 | * @param {Number} [options.mintf] - Minimum Term Frequency - the frequency below which terms will be ignored in the source doc.
|
386 | * @param {Number} [options.mindf] - Minimum Document Frequency - the frequency at which words will be ignored which do not occur in at least this many docs.
|
387 | * @param {Number} [options.minwl] - minimum word length below which words will be ignored.
|
388 | * @param {Number} [options.maxwl] - maximum word length above which words will be ignored.
|
389 | * @param {Number} [options.maxqt] - maximum number of query terms that will be included in any generated query.
|
390 | * @param {Number} [options.maxntp] - maximum number of tokens to parse in each example doc field that is not stored with TermVector support.
|
391 | * @param {Boolean} [options.boost] - set if the query will be boosted by the interesting term relevance.
|
392 | * @param {String|Object} [options.qf] - Query fields and their boosts using the same format as that used in DisMaxQParserPlugin. These fields must also be specified in mlt.fl.
|
393 | *
|
394 | * @return {Query}
|
395 | * @api public
|
396 | */
|
397 |
|
398 | Query.prototype.mlt = function(options){
|
399 | var self = this;
|
400 | if(options.on === false){
|
401 | this.parameters.push('mlt=false');
|
402 | }else{
|
403 | this.parameters.push('mlt=true');
|
404 | }
|
405 | if(options.fl){
|
406 | if(options.fl instanceof Array) options.fl = options.fl.join(',');
|
407 | this.parameters.push('mlt.fl=' + encodeURIComponent(options.fl))
|
408 | }
|
409 | if(options.count !== undefined){
|
410 | this.parameters.push('mlt.count=' + options.count)
|
411 | }
|
412 | if(options.mintf !== undefined){
|
413 | this.parameters.push('mlt.mintf=' + options.mintf)
|
414 | }
|
415 | if(options.mindf !== undefined){
|
416 | this.parameters.push('mlt.mindf=' + options.mindf);
|
417 | }
|
418 | if(options.minwl !== undefined){
|
419 | this.parameters.push('mlt.minwl=' + options.minwl)
|
420 | }
|
421 | if(options.maxwl !== undefined ){
|
422 | this.parameters.push('mlt.maxwl=' + options.maxwl)
|
423 | }
|
424 | if(options.maxqt !== undefined){
|
425 | this.parameters.push('mlt.maxqt=' + options.maxqt)
|
426 | }
|
427 | if(options.maxntp !== undefined){
|
428 | this.parameters.push('mlt.maxntp=' + options.maxntp);
|
429 | }
|
430 | if(options.boost !== undefined){
|
431 | this.parameters.push('mlt.boost=' + options.boost);
|
432 | }
|
433 | if(options.qf){
|
434 | if( typeof options.qf === 'object'){
|
435 | var parameter = querystring.stringify(options.qf, '%20' , '^');;
|
436 | }else{
|
437 | var parameter = encodeURIComponent(options.qf);
|
438 | }
|
439 | this.parameters.push('mlt.qf=' + parameter);
|
440 | }
|
441 | return self;
|
442 | }
|
443 |
|
444 | /**
|
445 | * DisMax parameters
|
446 | * do not forget to use `.dismax()` when using these parameters
|
447 | */
|
448 |
|
449 | /**
|
450 | * Use the DisMax query parser
|
451 | *
|
452 | * @return {Query}
|
453 | * @api public
|
454 | */
|
455 |
|
456 | Query.prototype.dismax = function(){
|
457 | var self = this;
|
458 | this.defType('dismax');
|
459 | return self;
|
460 | }
|
461 |
|
462 | /**
|
463 | * EDisMax parameters
|
464 | * do not forget to use `.edismax()` when using these parameters
|
465 | */
|
466 |
|
467 | /**
|
468 | * Use the EDisMax query parser
|
469 | *
|
470 | * @return {Query}
|
471 | * @api public
|
472 | */
|
473 |
|
474 | Query.prototype.edismax = function(){
|
475 | var self = this;
|
476 | this.defType('edismax');
|
477 | return self;
|
478 | }
|
479 |
|
480 | /**
|
481 | * Set the "boosts" to associate with each fields
|
482 | *
|
483 | * @param {Object} options -
|
484 | *
|
485 | * @return {Query}
|
486 | * @api public
|
487 | *
|
488 | * @example
|
489 | * var query = client.createQuery();
|
490 | * query.qf({title : 2.2, description : 0.5 });
|
491 | */
|
492 |
|
493 | Query.prototype.qf = function(options){
|
494 | var self = this;
|
495 | var parameter = 'qf=' ;
|
496 | parameter += querystring.stringify(options, '%20' , '^');
|
497 | this.parameters.push(parameter);
|
498 | return self;
|
499 | }
|
500 |
|
501 | /**
|
502 | * Set the minimum number or percent of clauses that must match.
|
503 | *
|
504 | * @param {String|Number} minimum - number or percent of clauses that must match
|
505 | *
|
506 | * @return {Query}
|
507 | * @api public
|
508 | *
|
509 | * @example
|
510 | * var query = client.createQuery();
|
511 | * query.mm(2); // or query.mm('75%');
|
512 | */
|
513 |
|
514 | Query.prototype.mm = function(minimum){
|
515 | var self = this;
|
516 | var parameter = 'mm=' + minimum;
|
517 | this.parameters.push(parameter);
|
518 | return self;
|
519 | }
|
520 |
|
521 | /**
|
522 | * Set the Phrase Fields parameter.
|
523 | * Once the list of matching documents has been identified using the "fq" and "qf" params, the "pf" param can be used to "boost" the score of documents in cases where all of the terms
|
524 | * in the "q" param appear in close proximity.
|
525 | *
|
526 | * @param {Object} options -
|
527 | *
|
528 | * @return {Query}
|
529 | * @api public
|
530 | */
|
531 |
|
532 | Query.prototype.pf = function(options){
|
533 | var self = this;
|
534 | var parameter = 'pf=' ;
|
535 | parameter += querystring.stringify(options, '%20' , '^');
|
536 | this.parameters.push(parameter);
|
537 | return self;
|
538 | }
|
539 |
|
540 | /**
|
541 | * Set the phrase slop allowed in a query.
|
542 | *
|
543 | * @param {Number} slop - Amount of phrase slop allowed by the query filter. This value should represent the maximum number of words allowed between words in a field that match a phrase in the query.
|
544 | *
|
545 | * @return {Query}
|
546 | * @api public
|
547 | */
|
548 |
|
549 | Query.prototype.ps = function(slop){
|
550 | var self = this;
|
551 | var parameter = 'ps=' + slop;
|
552 | this.parameters.push(parameter);
|
553 | return self;
|
554 | };
|
555 |
|
556 | /**
|
557 | * Set the query slop allowed in a query.
|
558 | *
|
559 | * @param {Number} slop - Amount of query slop allowed by the query filter. This value should be used to affect boosting of query strings.
|
560 | *
|
561 | * @return {Query}
|
562 | * @api public
|
563 | */
|
564 | Query.prototype.qs = function(slop){
|
565 | var self = this;
|
566 | var parameter = 'qs=' + slop;
|
567 | this.parameters.push(parameter);
|
568 | return self;
|
569 | };
|
570 |
|
571 | /**
|
572 | * Set the tiebreaker in DisjunctionMaxQueries (should be something much less than 1)
|
573 | *
|
574 | * @param {Float|Number} tiebreaker -
|
575 | *
|
576 | * @return {Query}
|
577 | * @api public
|
578 | */
|
579 |
|
580 | Query.prototype.tie = function(tiebreaker){
|
581 | var self = this;
|
582 | var parameter = 'tie=' + tiebreaker;
|
583 | this.parameters.push(parameter);
|
584 | return self;
|
585 | }
|
586 |
|
587 | /**
|
588 | * Set the Boost Query parameter.
|
589 | * A raw query string (in the SolrQuerySyntax) that will be included with the user's query to influence the score. If this is a BooleanQuery with a default boost (1.0f) then the individual clauses will be added directly to the main query. Otherwise, the query will be included as is.
|
590 | *
|
591 | * @param {Object} options -
|
592 | *
|
593 | * @return {Query}
|
594 | * @api public
|
595 | */
|
596 |
|
597 | Query.prototype.bq = function(options){
|
598 | var self = this;
|
599 | var parameter = 'bq=' ;
|
600 | parameter += querystring.stringify(options, '%20' , '^');
|
601 | this.parameters.push(parameter);
|
602 | return self;
|
603 | }
|
604 |
|
605 |
|
606 | /**
|
607 | * Set the Functions (with optional boosts) that will be included in the user's query to influence the score.
|
608 | * @param {String} functions - e.g.: `recip(rord(myfield),1,2,3)^1.5`
|
609 | *
|
610 | * @return {Query}
|
611 | * @api public
|
612 | */
|
613 |
|
614 | Query.prototype.bf = function(functions){
|
615 | var self = this;
|
616 | var parameter = 'bf=' + functions;
|
617 | this.parameters.push(parameter);
|
618 | return self;
|
619 | }
|
620 |
|
621 | /**
|
622 | * Set the Functions (with optional boosts) that will be included in the user's query to influence the score.
|
623 | * @param {String} functions - e.g.: `recip(rord(myfield),1,2,3)^1.5`
|
624 | *
|
625 | * @return {Query}
|
626 | * @api public
|
627 | */
|
628 |
|
629 | Query.prototype.boost = function(functions){
|
630 | var self = this;
|
631 | var parameter = 'boost=' + encodeURIComponent(functions);
|
632 | this.parameters.push(parameter);
|
633 | return self;
|
634 | }
|
635 |
|
636 | /**
|
637 | * Build a querystring with the array of `this.parameters`.
|
638 | *
|
639 | * @return {String}
|
640 | * @api private
|
641 | */
|
642 | Query.prototype.build = function(){
|
643 | return this.parameters.join('&');
|
644 | }
|
645 |
|