1 | import d from 'debug';
|
2 |
|
3 | const debug = d('LC:ConversationQuery');
|
4 |
|
5 | export default class ConversationQuery {
|
6 | static _encode(value) {
|
7 | if (value instanceof Date) {
|
8 | return { __type: 'Date', iso: value.toJSON() };
|
9 | }
|
10 | if (value instanceof RegExp) {
|
11 | return value.source;
|
12 | }
|
13 | return value;
|
14 | }
|
15 |
|
16 | static _quote(s) {
|
17 | return `\\Q${s.replace('\\E', '\\E\\\\E\\Q')}\\E`;
|
18 | }
|
19 |
|
20 | static _calculateFlag(options) {
|
21 | return ['withLastMessagesRefreshed', 'compact'].reduce(
|
22 | // eslint-disable-next-line no-bitwise
|
23 | (prev, key) => (prev << 1) + Boolean(options[key]),
|
24 | 0
|
25 | );
|
26 | }
|
27 |
|
28 | /**
|
29 | * Create a ConversationQuery
|
30 | * @param {IMClient} client
|
31 | */
|
32 | constructor(client) {
|
33 | this._client = client;
|
34 | this._where = {};
|
35 | this._extraOptions = {};
|
36 | }
|
37 |
|
38 | _addCondition(key, condition, value) {
|
39 | // Check if we already have a condition
|
40 | if (!this._where[key]) {
|
41 | this._where[key] = {};
|
42 | }
|
43 | this._where[key][condition] = this.constructor._encode(value);
|
44 | return this;
|
45 | }
|
46 |
|
47 | toJSON() {
|
48 | const json = {
|
49 | where: this._where,
|
50 | flag: this.constructor._calculateFlag(this._extraOptions),
|
51 | };
|
52 | if (typeof this._skip !== 'undefined') json.skip = this._skip;
|
53 | if (typeof this._limit !== 'undefined') json.limit = this._limit;
|
54 | if (typeof this._order !== 'undefined') json.sort = this._order;
|
55 | debug(json);
|
56 | return json;
|
57 | }
|
58 |
|
59 | /**
|
60 | * 增加查询条件,指定聊天室的组员包含某些成员即可返回
|
61 | * @param {string[]} peerIds - 成员 ID 列表
|
62 | * @return {ConversationQuery} self
|
63 | */
|
64 | containsMembers(peerIds) {
|
65 | return this.containsAll('m', peerIds);
|
66 | }
|
67 |
|
68 | /**
|
69 | * 增加查询条件,指定聊天室的组员条件满足条件的才返回
|
70 | *
|
71 | * @param {string[]} - 成员 ID 列表
|
72 | * @param {Boolean} includeSelf - 是否包含自己
|
73 | * @return {ConversationQuery} self
|
74 | */
|
75 | withMembers(peerIds, includeSelf) {
|
76 | const peerIdsSet = new Set(peerIds);
|
77 | if (includeSelf) {
|
78 | peerIdsSet.add(this._client.id);
|
79 | }
|
80 | this.sizeEqualTo('m', peerIdsSet.size);
|
81 | return this.containsMembers(Array.from(peerIdsSet));
|
82 | }
|
83 |
|
84 | /**
|
85 | * 增加查询条件,当 conversation 的属性中对应的字段满足等于条件时即可返回
|
86 | *
|
87 | * @param {string} key
|
88 | * @param value
|
89 | * @return {ConversationQuery} self
|
90 | */
|
91 | equalTo(key, value) {
|
92 | this._where[key] = this.constructor._encode(value);
|
93 | return this;
|
94 | }
|
95 |
|
96 | /**
|
97 | * 增加查询条件,当 conversation 的属性中对应的字段满足小于条件时即可返回
|
98 | * @param {string} key
|
99 | * @param value
|
100 | * @return {ConversationQuery} self
|
101 | */
|
102 | lessThan(key, value) {
|
103 | return this._addCondition(key, '$lt', value);
|
104 | }
|
105 |
|
106 | /**
|
107 | * 增加查询条件,当 conversation 的属性中对应的字段满足小于等于条件时即可返回
|
108 |
|
109 | * @param {string} key
|
110 | * @param value
|
111 | * @return {ConversationQuery} self
|
112 | */
|
113 | lessThanOrEqualTo(key, value) {
|
114 | return this._addCondition(key, '$lte', value);
|
115 | }
|
116 |
|
117 | /**
|
118 | * 增加查询条件,当 conversation 的属性中对应的字段满足大于条件时即可返回
|
119 | *
|
120 | * @param {string} key
|
121 | * @param value
|
122 | * @return {ConversationQuery} self
|
123 | */
|
124 |
|
125 | greaterThan(key, value) {
|
126 | return this._addCondition(key, '$gt', value);
|
127 | }
|
128 |
|
129 | /**
|
130 | * 增加查询条件,当 conversation 的属性中对应的字段满足大于等于条件时即可返回
|
131 | *
|
132 | * @param {string} key
|
133 | * @param value
|
134 | * @return {ConversationQuery} self
|
135 | */
|
136 |
|
137 | greaterThanOrEqualTo(key, value) {
|
138 | return this._addCondition(key, '$gte', value);
|
139 | }
|
140 |
|
141 | /**
|
142 | * 增加查询条件,当 conversation 的属性中对应的字段满足不等于条件时即可返回
|
143 | *
|
144 | * @param {string} key
|
145 | * @param value
|
146 | * @return {ConversationQuery} self
|
147 | */
|
148 | notEqualTo(key, value) {
|
149 | return this._addCondition(key, '$ne', value);
|
150 | }
|
151 |
|
152 | /**
|
153 | * 增加查询条件,当 conversation 存在指定的字段时即可返回
|
154 | *
|
155 | * @since 3.5.0
|
156 | * @param {string} key
|
157 | * @return {ConversationQuery} self
|
158 | */
|
159 | exists(key) {
|
160 | return this._addCondition(key, '$exists', true);
|
161 | }
|
162 |
|
163 | /**
|
164 | * 增加查询条件,当 conversation 不存在指定的字段时即可返回
|
165 | *
|
166 | * @since 3.5.0
|
167 | * @param {string} key
|
168 | * @return {ConversationQuery} self
|
169 | */
|
170 | doesNotExist(key) {
|
171 | return this._addCondition(key, '$exists', false);
|
172 | }
|
173 |
|
174 | /**
|
175 | * 增加查询条件,当 conversation 的属性中对应的字段对应的值包含在指定值中时即可返回
|
176 | *
|
177 | * @param {string} key
|
178 | * @param values
|
179 | * @return {ConversationQuery} self
|
180 | */
|
181 | containedIn(key, values) {
|
182 | return this._addCondition(key, '$in', values);
|
183 | }
|
184 |
|
185 | /**
|
186 | * 增加查询条件,当 conversation 的属性中对应的字段对应的值不包含在指定值中时即可返回
|
187 | *
|
188 | * @param {string} key
|
189 | * @param values
|
190 | * @return {ConversationQuery} self
|
191 | */
|
192 | notContainsIn(key, values) {
|
193 | return this._addCondition(key, '$nin', values);
|
194 | }
|
195 |
|
196 | /**
|
197 | * 增加查询条件,当conversation的属性中对应的字段中的元素包含所有的值才可返回
|
198 | *
|
199 | * @param {string} key
|
200 | * @param values
|
201 | * @return {ConversationQuery} self
|
202 | */
|
203 | containsAll(key, values) {
|
204 | return this._addCondition(key, '$all', values);
|
205 | }
|
206 |
|
207 | /**
|
208 | * 增加查询条件,当 conversation 的属性中对应的字段对应的值包含此字符串即可返回
|
209 | *
|
210 | * @param {string} key
|
211 | * @param {string} subString
|
212 | * @return {ConversationQuery} self
|
213 | */
|
214 | contains(key, subString) {
|
215 | return this._addCondition(
|
216 | key,
|
217 | '$regex',
|
218 | ConversationQuery._quote(subString)
|
219 | );
|
220 | }
|
221 |
|
222 | /**
|
223 | * 增加查询条件,当 conversation 的属性中对应的字段对应的值以此字符串起始即可返回
|
224 | *
|
225 | * @param {string} key
|
226 | * @param {string} prefix
|
227 | * @return {ConversationQuery} self
|
228 | */
|
229 | startsWith(key, prefix) {
|
230 | return this._addCondition(
|
231 | key,
|
232 | '$regex',
|
233 | `^${ConversationQuery._quote(prefix)}`
|
234 | );
|
235 | }
|
236 |
|
237 | /**
|
238 | * 增加查询条件,当 conversation 的属性中对应的字段对应的值以此字符串结束即可返回
|
239 | *
|
240 | * @param {string} key
|
241 | * @param {string} suffix
|
242 | * @return {ConversationQuery} self
|
243 | */
|
244 | endsWith(key, suffix) {
|
245 | return this._addCondition(
|
246 | key,
|
247 | '$regex',
|
248 | `${ConversationQuery._quote(suffix)}$`
|
249 | );
|
250 | }
|
251 |
|
252 | /**
|
253 | * 增加查询条件,当 conversation 的属性中对应的字段对应的值满足提供的正则表达式即可返回
|
254 | *
|
255 | * @param {string} key
|
256 | * @param {RegExp} regex
|
257 | * @return {ConversationQuery} self
|
258 | */
|
259 | matches(key, regex) {
|
260 | this._addCondition(key, '$regex', regex);
|
261 | // Javascript regex options support mig as inline options but store them
|
262 | // as properties of the object. We support mi & should migrate them to
|
263 | // modifiers
|
264 | let _modifiers = '';
|
265 | if (regex.ignoreCase) {
|
266 | _modifiers += 'i';
|
267 | }
|
268 | if (regex.multiline) {
|
269 | _modifiers += 'm';
|
270 | }
|
271 |
|
272 | if (_modifiers && _modifiers.length) {
|
273 | this._addCondition(key, '$options', _modifiers);
|
274 | }
|
275 | return this;
|
276 | }
|
277 |
|
278 | /**
|
279 | * 添加查询约束条件,查找 key 类型是数组,该数组的长度匹配提供的数值
|
280 | *
|
281 | * @param {string} key
|
282 | * @param {Number} length
|
283 | * @return {ConversationQuery} self
|
284 | */
|
285 | sizeEqualTo(key, length) {
|
286 | return this._addCondition(key, '$size', length);
|
287 | }
|
288 |
|
289 | /**
|
290 | * 设置返回集合的大小上限
|
291 | *
|
292 | * @param {Number} limit - 上限
|
293 | * @return {ConversationQuery} self
|
294 | */
|
295 | limit(limit) {
|
296 | this._limit = limit;
|
297 | return this;
|
298 | }
|
299 |
|
300 | /**
|
301 | * 设置返回集合的起始位置,一般用于分页
|
302 | *
|
303 | * @param {Number} skip - 起始位置跳过几个对象
|
304 | * @return {ConversationQuery} self
|
305 | */
|
306 | skip(skip) {
|
307 | this._skip = skip;
|
308 | return this;
|
309 | }
|
310 |
|
311 | /**
|
312 | * 设置返回集合按照指定key进行增序排列
|
313 | *
|
314 | * @param {string} key
|
315 | * @return {ConversationQuery} self
|
316 | */
|
317 | ascending(key) {
|
318 | this._order = key;
|
319 | return this;
|
320 | }
|
321 |
|
322 | /**
|
323 | * 设置返回集合按照指定key进行增序排列,如果已设置其他排序,原排序的优先级较高
|
324 | *
|
325 | * @param {string} key
|
326 | * @return {ConversationQuery} self
|
327 | */
|
328 | addAscending(key) {
|
329 | if (this._order) {
|
330 | this._order += `,${key}`;
|
331 | } else {
|
332 | this._order = key;
|
333 | }
|
334 | return this;
|
335 | }
|
336 |
|
337 | /**
|
338 | * 设置返回集合按照指定 key 进行降序排列
|
339 | *
|
340 | * @param {string} key
|
341 | * @return {ConversationQuery} self
|
342 | */
|
343 | descending(key) {
|
344 | this._order = `-${key}`;
|
345 | return this;
|
346 | }
|
347 |
|
348 | /**
|
349 | * 设置返回集合按照指定 key 进行降序排列,如果已设置其他排序,原排序的优先级较高
|
350 | *
|
351 | * @param {string} key
|
352 | * @return {ConversationQuery} self
|
353 | */
|
354 | addDescending(key) {
|
355 | if (this._order) {
|
356 | this._order += `,-${key}`;
|
357 | } else {
|
358 | this._order = `-${key}`;
|
359 | }
|
360 | return this;
|
361 | }
|
362 |
|
363 | /**
|
364 | * 设置返回的 conversations 刷新最后一条消息
|
365 | * @param {Boolean} [enabled=true]
|
366 | * @return {ConversationQuery} self
|
367 | */
|
368 | withLastMessagesRefreshed(enabled = true) {
|
369 | this._extraOptions.withLastMessagesRefreshed = enabled;
|
370 | return this;
|
371 | }
|
372 |
|
373 | /**
|
374 | * 设置返回的 conversations 为精简模式,即不含成员列表
|
375 | * @param {Boolean} [enabled=true]
|
376 | * @return {ConversationQuery} self
|
377 | */
|
378 | compact(enabled = true) {
|
379 | this._extraOptions.compact = enabled;
|
380 | return this;
|
381 | }
|
382 |
|
383 | /**
|
384 | * 执行查询
|
385 | * @return {Promise.<ConversationBase[]>}
|
386 | */
|
387 | async find() {
|
388 | return this._client._executeQuery(this);
|
389 | }
|
390 | }
|