forked from leancloud/javascript-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.js
More file actions
288 lines (263 loc) · 8.19 KB
/
Copy pathsearch.js
File metadata and controls
288 lines (263 loc) · 8.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/**
* 每位工程师都有保持代码优雅的义务
* Each engineer has a duty to keep the code elegant
**/
const _ = require('underscore');
const AVRequest = require('./request').request;
module.exports = function(AV) {
/**
* A builder to generate sort string for app searching.For example:
* <pre><code>
* var builder = new AV.SearchSortBuilder();
* builder.ascending('key1').descending('key2','max');
* var query = new AV.SearchQuery('Player');
* query.sortBy(builder);
* query.find().then ...
* </code></pre>
* @class
* @since 0.5.1
*/
AV.SearchSortBuilder = function() {
this._sortFields = [];
};
AV.SearchSortBuilder.prototype = {
_addField: function(key, order, mode, missing) {
var field = {};
field[key] = {
order: order || 'asc',
mode: mode ||'avg',
missing: '_' + (missing || 'last')
};
this._sortFields.push(field);
return this;
},
/**
* Sorts the results in ascending order by the given key and options.
*
* @param {String} key The key to order by.
* @param {String} mode The sort mode, default is 'avg', you can choose
* 'max' or 'min' too.
* @param {String} missing The missing key behaviour, default is 'last',
* you can choose 'first' too.
* @return {AV.SearchSortBuilder} Returns the builder, so you can chain this call.
*/
ascending: function(key, mode, missing) {
return this._addField(key, 'asc', mode, missing);
},
/**
* Sorts the results in descending order by the given key and options.
*
* @param {String} key The key to order by.
* @param {String} mode The sort mode, default is 'avg', you can choose
* 'max' or 'min' too.
* @param {String} missing The missing key behaviour, default is 'last',
* you can choose 'first' too.
* @return {AV.SearchSortBuilder} Returns the builder, so you can chain this call.
*/
descending: function(key, mode, missing) {
return this._addField(key, 'desc', mode, missing);
},
/**
* Add a proximity based constraint for finding objects with key point
* values near the point given.
* @param {String} key The key that the AV.GeoPoint is stored in.
* @param {AV.GeoPoint} point The reference AV.GeoPoint that is used.
* @param {Object} options The other options such as mode,order, unit etc.
* @return {AV.SearchSortBuilder} Returns the builder, so you can chain this call.
*/
whereNear: function(key, point, options) {
options = options || {};
var field = {};
var geo = {
lat: point.latitude,
lon: point.longitude
};
var m = {
order: options.order || 'asc',
mode: options.mode || 'avg',
unit: options.unit || 'km'
};
m[key] = geo;
field['_geo_distance'] = m;
this._sortFields.push(field);
return this;
},
/**
* Build a sort string by configuration.
* @return {String} the sort string.
*/
build: function() {
return JSON.stringify(AV._encode(this._sortFields));
}
};
/**
* App searching query.Use just like AV.Query:
* <pre><code>
* var query = new AV.SearchQuery('Player');
* query.queryString('*');
* query.find().then(function(results) {
* console.log('Found %d objects', query.hits());
* //Process results
* });
*
* </code></pre>
* Visite <a href='https://leancloud.cn/docs/app_search_guide.html'>App Searching Guide</a>
* for more details.
* @class
* @since 0.5.1
*
*/
AV.SearchQuery = AV.Query._extend(/** @lends AV.SearchQuery.prototype */{
_sid: null,
_hits: 0,
_queryString: null,
_highlights: null,
_sortBuilder: null,
_createRequest: function(params, options){
return AVRequest('search/select', null, null, 'GET',
params || this.toJSON(), options && options.sessionToken);
},
/**
* Sets the sid of app searching query.Default is null.
* @param {String} sid Scroll id for searching.
* @return {AV.SearchQuery} Returns the query, so you can chain this call.
*/
sid: function(sid) {
this._sid = sid;
return this;
},
/**
* Sets the query string of app searching.
* @param {String} q The query string.
* @return {AV.SearchQuery} Returns the query, so you can chain this call.
*/
queryString: function(q) {
this._queryString = q;
return this;
},
/**
* Sets the highlight fields. Such as
* <pre><code>
* query.highlights('title');
* //or pass an array.
* query.highlights(['title', 'content'])
* </code></pre>
* @param {Array} highlights a list of fields.
* @return {AV.SearchQuery} Returns the query, so you can chain this call.
*/
highlights: function(highlights) {
var objects;
if (highlights && _.isString(highlights)) {
objects = arguments;
} else {
objects = highlights;
}
this._highlights = objects;
return this;
},
/**
* Sets the sort builder for this query.
* @see AV.SearchSortBuilder
* @param { AV.SearchSortBuilder} builder The sort builder.
* @return {AV.SearchQuery} Returns the query, so you can chain this call.
*
*/
sortBy: function(builder) {
this._sortBuilder = builder;
return this;
},
/**
* Returns the number of objects that match this query.
* @return {Number}
*/
hits: function() {
if (!this._hits) {
this._hits = 0;
}
return this._hits;
},
_processResult: function(json){
delete json['className'];
delete json['_app_url'];
delete json['_deeplink'];
return json;
},
/**
* Returns true when there are more documents can be retrieved by this
* query instance, you can call find function to get more results.
* @see AV.SearchQuery#find
* @return {Boolean}
*/
hasMore: function() {
return !this._hitEnd;
},
/**
* Reset current query instance state(such as sid, hits etc) except params
* for a new searching. After resetting, hasMore() will return true.
*/
reset: function() {
this._hitEnd = false;
this._sid = null;
this._hits = 0;
},
/**
* Retrieves a list of AVObjects that satisfy this query.
* Either options.success or options.error is called when the find
* completes.
*
* @see AV.Query#find
* @param {Object} options A Backbone-style options object.
* @return {AV.Promise} A promise that is resolved with the results when
* the query completes.
*/
find: function(options) {
var self = this;
var request = this._createRequest();
return request.then(function(response) {
//update sid for next querying.
if(response.sid) {
self._oldSid = self._sid;
self._sid = response.sid;
} else {
self._sid = null;
self._hitEnd = true;
}
self._hits = response.hits || 0;
return _.map(response.results, function(json) {
if(json.className) {
response.className = json.className;
}
var obj = self._newObject(response);
obj.appURL = json['_app_url'];
obj._finishFetch(self._processResult(json), true);
return obj;
});
})._thenRunCallbacks(options);
},
toJSON: function(){
var params = AV.SearchQuery.__super__.toJSON.call(this);
delete params.where;
if(this.className) {
params.clazz = this.className;
}
if(this._sid) {
params.sid = this._sid;
}
if(!this._queryString) {
throw 'Please set query string.';
} else {
params.q = this._queryString;
}
if(this._highlights) {
params.highlights = this._highlights.join(',');
}
if(this._sortBuilder && params.order) {
throw 'sort and order can not be set at same time.';
}
if(this._sortBuilder) {
params.sort = this._sortBuilder.build();
}
return params;
}
});
};