UNPKG

20.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.QueryIndexManager = exports.CollectionQueryIndexManager = exports.QueryIndex = void 0;
4const bindingutilities_1 = require("./bindingutilities");
5const errors_1 = require("./errors");
6const utilities_1 = require("./utilities");
7/**
8 * Contains a specific index configuration for the query service.
9 *
10 * @category Management
11 */
12class QueryIndex {
13 /**
14 * @internal
15 */
16 constructor(data) {
17 this.name = data.name;
18 this.isPrimary = data.isPrimary;
19 this.type = data.type;
20 this.state = data.state;
21 this.indexKey = data.indexKey;
22 this.condition = data.condition;
23 this.partition = data.partition;
24 this.collectionName = data.collectionName;
25 this.scopeName = data.scopeName;
26 this.bucketName = data.bucketName;
27 }
28}
29exports.QueryIndex = QueryIndex;
30/**
31 * @internal
32 */
33class InternalQueryIndexManager {
34 /**
35 * @internal
36 */
37 constructor(cluster) {
38 this._cluster = cluster;
39 this._queryContext = {
40 bucket_name: '',
41 scope_name: '',
42 };
43 }
44 /**
45 * @internal
46 */
47 async createIndex(bucketName, isPrimary, options, callback) {
48 const timeout = options.timeout || this._cluster.managementTimeout;
49 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
50 this._cluster.conn.managementQueryIndexCreate({
51 bucket_name: bucketName,
52 scope_name: options.scopeName || '',
53 collection_name: options.collectionName || '',
54 index_name: options.name || '',
55 keys: options.keys || [],
56 query_ctx: options.queryContext || this._queryContext,
57 is_primary: isPrimary,
58 ignore_if_exists: options.ignoreIfExists || false,
59 deferred: options.deferred,
60 num_replicas: options.numReplicas,
61 timeout: timeout,
62 condition: undefined,
63 }, (cppErr) => {
64 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
65 if (err) {
66 return wrapCallback(err, null);
67 }
68 wrapCallback(err);
69 });
70 }, callback);
71 }
72 /**
73 * @internal
74 */
75 async dropIndex(bucketName, isPrimary, options, callback) {
76 const timeout = options.timeout || this._cluster.managementTimeout;
77 // BUG(JSCBC-1066): We need to use a normal drop index for named primary indexes.
78 if (options.name) {
79 isPrimary = false;
80 }
81 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
82 this._cluster.conn.managementQueryIndexDrop({
83 bucket_name: bucketName,
84 scope_name: options.scopeName || '',
85 collection_name: options.collectionName || '',
86 index_name: options.name || '',
87 query_ctx: options.queryContext || this._queryContext,
88 is_primary: isPrimary,
89 ignore_if_does_not_exist: options.ignoreIfNotExists || false,
90 timeout: timeout,
91 }, (cppErr) => {
92 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
93 if (err) {
94 return wrapCallback(err, null);
95 }
96 wrapCallback(err);
97 });
98 }, callback);
99 }
100 /**
101 * @internal
102 */
103 async getAllIndexes(bucketName, options, callback) {
104 const timeout = options.timeout || this._cluster.managementTimeout;
105 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
106 this._cluster.conn.managementQueryIndexGetAll({
107 bucket_name: bucketName,
108 scope_name: options.scopeName || '',
109 collection_name: options.collectionName || '',
110 query_ctx: options.queryContext || this._queryContext,
111 timeout: timeout,
112 }, (cppErr, resp) => {
113 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
114 if (err) {
115 return wrapCallback(err, null);
116 }
117 const indexes = resp.indexes.map((row) => new QueryIndex({
118 isPrimary: row.is_primary,
119 name: row.name,
120 state: row.state,
121 type: row.type,
122 indexKey: row.index_key,
123 partition: row.partition,
124 condition: row.condition,
125 bucketName: row.bucket_name,
126 scopeName: row.scope_name,
127 collectionName: row.collection_name,
128 }));
129 wrapCallback(null, indexes);
130 });
131 }, callback);
132 }
133 /**
134 * @internal
135 */
136 async buildDeferredIndexes(bucketName, options, callback) {
137 const timeout = options.timeout || this._cluster.managementTimeout;
138 return utilities_1.PromiseHelper.wrap((wrapCallback) => {
139 this._cluster.conn.managementQueryIndexBuildDeferred({
140 bucket_name: bucketName,
141 scope_name: options.scopeName || '',
142 collection_name: options.collectionName || '',
143 query_ctx: options.queryContext || this._queryContext,
144 timeout: timeout,
145 }, (cppErr) => {
146 const err = (0, bindingutilities_1.errorFromCpp)(cppErr);
147 if (err) {
148 return wrapCallback(err, null);
149 }
150 wrapCallback(null, null);
151 });
152 }, callback);
153 }
154 /**
155 * @internal
156 */
157 async watchIndexes(bucketName, indexNames, timeout, options, callback) {
158 if (options.watchPrimary) {
159 indexNames = [...indexNames, '#primary'];
160 }
161 const timer = new utilities_1.CompoundTimeout(timeout);
162 return utilities_1.PromiseHelper.wrapAsync(async () => {
163 let curInterval = 50;
164 for (;;) {
165 // Get all the indexes that are currently registered
166 const foundIdxs = await this.getAllIndexes(bucketName, {
167 timeout: timer.left(),
168 });
169 const foundIndexNames = foundIdxs.map((idx) => idx.name);
170 const onlineIdxs = foundIdxs.filter((idx) => idx.state === 'online');
171 const onlineIdxNames = onlineIdxs.map((idx) => idx.name);
172 // Check if all the indexes we want are online
173 let allOnline = true;
174 indexNames.forEach((indexName) => {
175 if (!foundIndexNames.includes(indexName)) {
176 throw new errors_1.IndexNotFoundError(new Error(`Cannot find index with name ${indexName}`));
177 }
178 allOnline = allOnline && onlineIdxNames.indexOf(indexName) !== -1;
179 });
180 // If all the indexes are online, we've succeeded
181 if (allOnline) {
182 break;
183 }
184 // Add 500 to our interval to a max of 1000
185 curInterval = Math.min(1000, curInterval + 500);
186 // Make sure we don't go past our user-specified duration
187 const userTimeLeft = timer.left();
188 if (userTimeLeft !== undefined) {
189 curInterval = Math.min(curInterval, userTimeLeft);
190 }
191 if (curInterval <= 0) {
192 throw new errors_1.CouchbaseError('Failed to find all indexes online within the alloted time.');
193 }
194 // Wait until curInterval expires
195 await new Promise((resolve) => setTimeout(() => resolve(true), curInterval));
196 }
197 }, callback);
198 }
199}
200/**
201 * CollectionQueryIndexManager provides an interface for managing the
202 * query indexes on the collection.
203 *
204 * @category Management
205 */
206class CollectionQueryIndexManager {
207 /**
208 * @internal
209 */
210 constructor(collection) {
211 this._bucketName = collection.scope.bucket.name;
212 this._collectionName = collection.name;
213 this._scopeName = collection.scope.name;
214 this._manager = new InternalQueryIndexManager(collection.cluster);
215 }
216 /**
217 * Creates a new query index.
218 *
219 * @param indexName The name of the new index.
220 * @param keys The keys which this index should cover.
221 * @param options Optional parameters for this operation.
222 * @param callback A node-style callback to be invoked after execution.
223 */
224 async createIndex(indexName, keys, options, callback) {
225 if (options instanceof Function) {
226 callback = arguments[2];
227 options = undefined;
228 }
229 if (!options) {
230 options = {};
231 }
232 return this._manager.createIndex(this._bucketName, false, {
233 collectionName: this._collectionName,
234 scopeName: this._scopeName,
235 name: indexName,
236 keys: keys,
237 ignoreIfExists: options.ignoreIfExists,
238 numReplicas: options.numReplicas,
239 deferred: options.deferred,
240 timeout: options.timeout,
241 }, callback);
242 }
243 /**
244 * Creates a new primary query index.
245 *
246 * @param options Optional parameters for this operation.
247 * @param callback A node-style callback to be invoked after execution.
248 */
249 async createPrimaryIndex(options, callback) {
250 if (options instanceof Function) {
251 callback = arguments[0];
252 options = undefined;
253 }
254 if (!options) {
255 options = {};
256 }
257 return this._manager.createIndex(this._bucketName, true, {
258 collectionName: this._collectionName,
259 scopeName: this._scopeName,
260 name: options.name,
261 ignoreIfExists: options.ignoreIfExists,
262 deferred: options.deferred,
263 timeout: options.timeout,
264 }, callback);
265 }
266 /**
267 * Drops an existing query index.
268 *
269 * @param indexName The name of the index to drop.
270 * @param options Optional parameters for this operation.
271 * @param callback A node-style callback to be invoked after execution.
272 */
273 async dropIndex(indexName, options, callback) {
274 if (options instanceof Function) {
275 callback = arguments[1];
276 options = undefined;
277 }
278 if (!options) {
279 options = {};
280 }
281 return this._manager.dropIndex(this._bucketName, false, {
282 collectionName: this._collectionName,
283 scopeName: this._scopeName,
284 name: indexName,
285 ignoreIfNotExists: options.ignoreIfNotExists,
286 timeout: options.timeout,
287 }, callback);
288 }
289 /**
290 * Drops an existing primary index.
291 *
292 * @param options Optional parameters for this operation.
293 * @param callback A node-style callback to be invoked after execution.
294 */
295 async dropPrimaryIndex(options, callback) {
296 if (options instanceof Function) {
297 callback = arguments[0];
298 options = undefined;
299 }
300 if (!options) {
301 options = {};
302 }
303 return this._manager.dropIndex(this._bucketName, true, {
304 collectionName: this._collectionName,
305 scopeName: this._scopeName,
306 name: options.name,
307 ignoreIfNotExists: options.ignoreIfNotExists,
308 timeout: options.timeout,
309 }, callback);
310 }
311 /**
312 * Returns a list of indexes for a specific bucket.
313 *
314 * @param options Optional parameters for this operation.
315 * @param callback A node-style callback to be invoked after execution.
316 */
317 async getAllIndexes(options, callback) {
318 if (options instanceof Function) {
319 callback = arguments[0];
320 options = undefined;
321 }
322 if (!options) {
323 options = {};
324 }
325 return this._manager.getAllIndexes(this._bucketName, {
326 collectionName: this._collectionName,
327 scopeName: this._scopeName,
328 timeout: options.timeout,
329 }, callback);
330 }
331 /**
332 * Starts building any indexes which were previously created with deferred=true.
333 *
334 * @param options Optional parameters for this operation.
335 * @param callback A node-style callback to be invoked after execution.
336 */
337 async buildDeferredIndexes(options, callback) {
338 if (options instanceof Function) {
339 callback = arguments[0];
340 options = undefined;
341 }
342 if (!options) {
343 options = {};
344 }
345 return this._manager.buildDeferredIndexes(this._bucketName, {
346 collectionName: this._collectionName,
347 scopeName: this._scopeName,
348 timeout: options.timeout,
349 }, callback);
350 }
351 /**
352 * Waits for a number of indexes to finish creation and be ready to use.
353 *
354 * @param indexNames The names of the indexes to watch.
355 * @param timeout The maximum time to wait for the index, expressed in milliseconds.
356 * @param options Optional parameters for this operation.
357 * @param callback A node-style callback to be invoked after execution.
358 */
359 async watchIndexes(indexNames, timeout, options, callback) {
360 if (options instanceof Function) {
361 callback = arguments[2];
362 options = undefined;
363 }
364 if (!options) {
365 options = {};
366 }
367 return this._manager.watchIndexes(this._bucketName, indexNames, timeout, {
368 collectionName: this._collectionName,
369 scopeName: this._scopeName,
370 watchPrimary: options.watchPrimary,
371 }, callback);
372 }
373}
374exports.CollectionQueryIndexManager = CollectionQueryIndexManager;
375/**
376 * QueryIndexManager provides an interface for managing the
377 * query indexes on the cluster.
378 *
379 * @category Management
380 */
381class QueryIndexManager {
382 /**
383 * @internal
384 */
385 constructor(cluster) {
386 this._manager = new InternalQueryIndexManager(cluster);
387 }
388 /**
389 * Creates a new query index.
390 *
391 * @param bucketName The name of the bucket this index is for.
392 * @param indexName The name of the new index.
393 * @param keys The keys which this index should cover.
394 * @param options Optional parameters for this operation.
395 * @param callback A node-style callback to be invoked after execution.
396 */
397 async createIndex(bucketName, indexName, keys, options, callback) {
398 if (options instanceof Function) {
399 callback = arguments[3];
400 options = undefined;
401 }
402 if (!options) {
403 options = {};
404 }
405 return this._manager.createIndex(bucketName, false, {
406 collectionName: options.collectionName,
407 scopeName: options.scopeName,
408 name: indexName,
409 keys: keys,
410 ignoreIfExists: options.ignoreIfExists,
411 numReplicas: options.numReplicas,
412 deferred: options.deferred,
413 timeout: options.timeout,
414 }, callback);
415 }
416 /**
417 * Creates a new primary query index.
418 *
419 * @param bucketName The name of the bucket this index is for.
420 * @param options Optional parameters for this operation.
421 * @param callback A node-style callback to be invoked after execution.
422 */
423 async createPrimaryIndex(bucketName, options, callback) {
424 if (options instanceof Function) {
425 callback = arguments[1];
426 options = undefined;
427 }
428 if (!options) {
429 options = {};
430 }
431 return this._manager.createIndex(bucketName, true, {
432 collectionName: options.collectionName,
433 scopeName: options.scopeName,
434 name: options.name,
435 ignoreIfExists: options.ignoreIfExists,
436 deferred: options.deferred,
437 timeout: options.timeout,
438 }, callback);
439 }
440 /**
441 * Drops an existing query index.
442 *
443 * @param bucketName The name of the bucket containing the index to drop.
444 * @param indexName The name of the index to drop.
445 * @param options Optional parameters for this operation.
446 * @param callback A node-style callback to be invoked after execution.
447 */
448 async dropIndex(bucketName, indexName, options, callback) {
449 if (options instanceof Function) {
450 callback = arguments[2];
451 options = undefined;
452 }
453 if (!options) {
454 options = {};
455 }
456 return this._manager.dropIndex(bucketName, false, {
457 collectionName: options.collectionName,
458 scopeName: options.scopeName,
459 name: indexName,
460 ignoreIfNotExists: options.ignoreIfNotExists,
461 timeout: options.timeout,
462 }, callback);
463 }
464 /**
465 * Drops an existing primary index.
466 *
467 * @param bucketName The name of the bucket containing the primary index to drop.
468 * @param options Optional parameters for this operation.
469 * @param callback A node-style callback to be invoked after execution.
470 */
471 async dropPrimaryIndex(bucketName, options, callback) {
472 if (options instanceof Function) {
473 callback = arguments[1];
474 options = undefined;
475 }
476 if (!options) {
477 options = {};
478 }
479 return this._manager.dropIndex(bucketName, true, {
480 collectionName: options.collectionName,
481 scopeName: options.scopeName,
482 name: options.name,
483 ignoreIfNotExists: options.ignoreIfNotExists,
484 timeout: options.timeout,
485 }, callback);
486 }
487 /**
488 * Returns a list of indexes for a specific bucket.
489 *
490 * @param bucketName The name of the bucket to fetch indexes for.
491 * @param options Optional parameters for this operation.
492 * @param callback A node-style callback to be invoked after execution.
493 */
494 async getAllIndexes(bucketName, options, callback) {
495 if (options instanceof Function) {
496 callback = arguments[1];
497 options = undefined;
498 }
499 if (!options) {
500 options = {};
501 }
502 return this._manager.getAllIndexes(bucketName, {
503 collectionName: options.collectionName,
504 scopeName: options.scopeName,
505 timeout: options.timeout,
506 }, callback);
507 }
508 /**
509 * Starts building any indexes which were previously created with deferred=true.
510 *
511 * @param bucketName The name of the bucket to perform the build on.
512 * @param options Optional parameters for this operation.
513 * @param callback A node-style callback to be invoked after execution.
514 */
515 async buildDeferredIndexes(bucketName, options, callback) {
516 if (options instanceof Function) {
517 callback = arguments[1];
518 options = undefined;
519 }
520 if (!options) {
521 options = {};
522 }
523 return this._manager.buildDeferredIndexes(bucketName, {
524 collectionName: options.collectionName,
525 scopeName: options.scopeName,
526 timeout: options.timeout,
527 }, callback);
528 }
529 /**
530 * Waits for a number of indexes to finish creation and be ready to use.
531 *
532 * @param bucketName The name of the bucket to watch for indexes on.
533 * @param indexNames The names of the indexes to watch.
534 * @param timeout The maximum time to wait for the index, expressed in milliseconds.
535 * @param options Optional parameters for this operation.
536 * @param callback A node-style callback to be invoked after execution.
537 */
538 async watchIndexes(bucketName, indexNames, timeout, options, callback) {
539 if (options instanceof Function) {
540 callback = arguments[3];
541 options = undefined;
542 }
543 if (!options) {
544 options = {};
545 }
546 return this._manager.watchIndexes(bucketName, indexNames, timeout, {
547 collectionName: options.collectionName,
548 scopeName: options.scopeName,
549 watchPrimary: options.watchPrimary,
550 }, callback);
551 }
552}
553exports.QueryIndexManager = QueryIndexManager;