spice-couchbase 2.0.53 → 2.0.54

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.js CHANGED
@@ -178,10 +178,10 @@ module.exports = class Database {
178
178
  }
179
179
 
180
180
  isCollectionAlreadyExistsError(error) {
181
- var _error$cause, _error$cause2, _error$context, _error$context2;
181
+ var _error$cause, _error$context, _error$context2, _error$cause2, _error$cause3;
182
182
 
183
183
  var message = (error === null || error === void 0 ? void 0 : error.message) || (error === null || error === void 0 ? void 0 : (_error$cause = error.cause) === null || _error$cause === void 0 ? void 0 : _error$cause.first_error_message) || (error === null || error === void 0 ? void 0 : (_error$context = error.context) === null || _error$context === void 0 ? void 0 : _error$context.first_error_message) || (error === null || error === void 0 ? void 0 : (_error$context2 = error.context) === null || _error$context2 === void 0 ? void 0 : _error$context2.http_response_body) || "";
184
- return error instanceof couchbase.CollectionExistsError || (error === null || error === void 0 ? void 0 : (_error$cause2 = error.cause) === null || _error$cause2 === void 0 ? void 0 : _error$cause2.first_error_code) === 12003 || (error === null || error === void 0 ? void 0 : (_error$cause2 = error.cause) === null || _error$cause2 === void 0 ? void 0 : _error$cause2.first_error_code) === 12027 || /collection .*already exists|already exists/i.test(message);
184
+ return error instanceof couchbase.CollectionExistsError || (error === null || error === void 0 ? void 0 : (_error$cause2 = error.cause) === null || _error$cause2 === void 0 ? void 0 : _error$cause2.first_error_code) === 12003 || (error === null || error === void 0 ? void 0 : (_error$cause3 = error.cause) === null || _error$cause3 === void 0 ? void 0 : _error$cause3.first_error_code) === 12027 || /collection .*already exists|already exists/i.test(message);
185
185
  }
186
186
 
187
187
  upsertCollection() {
@@ -283,9 +283,9 @@ module.exports = class Database {
283
283
  var response = yield _this7.query("CREATE PRIMARY INDEX ON ".concat(_this7.collectionPath(scope_name, col_name)));
284
284
  return response;
285
285
  } catch (e) {
286
- var _e$cause3, _e$cause4;
286
+ var _e$cause, _e$cause2;
287
287
 
288
- if (e instanceof couchbase.IndexExistsError || (e === null || e === void 0 ? void 0 : (_e$cause3 = e.cause) === null || _e$cause3 === void 0 ? void 0 : _e$cause3.first_error_code) === 4300 || /index .*already exists|index_exists/i.test((e === null || e === void 0 ? void 0 : e.message) || (e === null || e === void 0 ? void 0 : (_e$cause4 = e.cause) === null || _e$cause4 === void 0 ? void 0 : _e$cause4.first_error_message) || "")) {
288
+ if (e instanceof couchbase.IndexExistsError || (e === null || e === void 0 ? void 0 : (_e$cause = e.cause) === null || _e$cause === void 0 ? void 0 : _e$cause.first_error_code) === 4300 || /index .*already exists|index_exists/i.test((e === null || e === void 0 ? void 0 : e.message) || (e === null || e === void 0 ? void 0 : (_e$cause2 = e.cause) === null || _e$cause2 === void 0 ? void 0 : _e$cause2.first_error_message) || "")) {
289
289
  return;
290
290
  }
291
291
 
@@ -870,7 +870,7 @@ module.exports = class Database {
870
870
 
871
871
  var durationInMilliseconds = (endTime - startTime) / BigInt(1000000); // optimize if response time is greater than 1 second
872
872
 
873
- if (durationInMilliseconds > 2000) {
873
+ if (durationInMilliseconds > 1000) {
874
874
  _this20.optimize(query, exec_scope);
875
875
  }
876
876
 
@@ -878,4 +878,4 @@ module.exports = class Database {
878
878
  })();
879
879
  }
880
880
 
881
- };
881
+ };
package/build/utility.js CHANGED
@@ -284,8 +284,21 @@ function splitSelectClause(clause) {
284
284
 
285
285
  return parts;
286
286
  }
287
+
288
+ function hasQualifiedWildcardProjection(query) {
289
+ var selectMatch = query.match(/\bSELECT\b([\s\S]+?)\bFROM\b/i);
290
+
291
+ if (!selectMatch) {
292
+ return false;
293
+ }
294
+
295
+ return splitSelectClause(selectMatch[1].trim()).some(part => {
296
+ var trimmedPart = part.trim();
297
+ return /^\(\s*`?\w+`?\s*\)\s*\.\s*\*$/.test(trimmedPart) || /^`?\w+`?\s*\.\s*\*$/.test(trimmedPart);
298
+ });
299
+ }
287
300
  /**
288
- * Builds a covering index CREATE statement from a query
301
+ * Builds a covering or fallback non-covering index CREATE statement from a query
289
302
  * @param {string} query - The N1QL query to analyze
290
303
  * @param {Object} options - Configuration options
291
304
  * @param {string} options.bucket - The bucket name
@@ -298,19 +311,19 @@ function splitSelectClause(clause) {
298
311
  function buildCoveringIndex(query, options) {
299
312
  var {
300
313
  bucket,
301
- scope,
302
- collection
314
+ scope = "_default",
315
+ collection = "_default"
303
316
  } = options;
304
317
 
305
- if (!bucket || !scope || !collection) {
318
+ if (!bucket) {
306
319
  return null;
307
320
  } // Extract fields from SELECT clause
308
321
 
309
322
 
310
323
  var selectFields = extractSelectFields(query);
324
+ var isNonCoveringFallback = selectFields === null && hasQualifiedWildcardProjection(query);
311
325
 
312
- if (selectFields === null) {
313
- // SELECT * query - cannot create covering index
326
+ if (selectFields === null && !isNonCoveringFallback) {
314
327
  return null;
315
328
  } // Extract fields from WHERE clause
316
329
 
@@ -349,7 +362,7 @@ function buildCoveringIndex(query, options) {
349
362
  return true;
350
363
  }); // Filter SELECT fields (remove duplicates from WHERE, GROUP BY, and ORDER BY, remove deleted)
351
364
 
352
- var selectFieldsFiltered = selectFields.filter(f => {
365
+ var selectFieldsFiltered = (selectFields || []).filter(f => {
353
366
  var lower = f.toLowerCase();
354
367
 
355
368
  if (addedFields.has(lower) || lower === "deleted") {
@@ -373,9 +386,10 @@ function buildCoveringIndex(query, options) {
373
386
 
374
387
  var indexFieldsKey = allFields.map(field => formatIndexKey(field, orderDirectionMap)).sort().join(",");
375
388
  var orderFieldsKey = orderByIndexFields.map(field => formatIndexKey(field.name, orderDirectionMap)).join(",");
376
- var indexKey = "".concat(bucket, "|").concat(scope, "|").concat(collection, "|fields:").concat(indexFieldsKey, "|order:").concat(orderFieldsKey);
389
+ var indexMode = isNonCoveringFallback ? "noncovered" : "covered";
390
+ var indexKey = "".concat(bucket, "|").concat(scope, "|").concat(collection, "|mode:").concat(indexMode, "|fields:").concat(indexFieldsKey, "|order:").concat(orderFieldsKey);
377
391
  var hash = generateHash(indexKey);
378
- var indexName = "adv_covered_".concat(hash); // Build the CREATE INDEX statement
392
+ var indexName = "adv_".concat(indexMode, "_").concat(hash); // Build the CREATE INDEX statement
379
393
 
380
394
  var indexStatement = "CREATE INDEX `".concat(indexName, "` ON `default`:`").concat(bucket, "`.`").concat(scope, "`.`").concat(collection, "`(").concat(fieldList, ")");
381
395
  return indexStatement;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spice-couchbase",
3
- "version": "2.0.53",
3
+ "version": "2.0.54",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "scripts": {
package/src/index.js CHANGED
@@ -249,9 +249,7 @@ module.exports = class Database {
249
249
  spice.db.collections.add(connection_name);
250
250
  return response;
251
251
  } catch (e) {
252
- if (
253
- this.isCollectionAlreadyExistsError(e)
254
- ) {
252
+ if (this.isCollectionAlreadyExistsError(e)) {
255
253
  spice.db.collections.add(connection_name);
256
254
  return;
257
255
  }
@@ -795,7 +793,7 @@ module.exports = class Database {
795
793
  // Calculate duration in microseconds
796
794
  let durationInMilliseconds = (endTime - startTime) / BigInt(1000000);
797
795
  // optimize if response time is greater than 1 second
798
- if (durationInMilliseconds > 2000) {
796
+ if (durationInMilliseconds > 1000) {
799
797
  this.optimize(query, exec_scope);
800
798
  }
801
799
  return response;
package/src/utility.js CHANGED
@@ -293,8 +293,23 @@ function splitSelectClause(clause) {
293
293
  return parts;
294
294
  }
295
295
 
296
+ function hasQualifiedWildcardProjection(query) {
297
+ const selectMatch = query.match(/\bSELECT\b(.+?)\bFROM\b/is);
298
+ if (!selectMatch) {
299
+ return false;
300
+ }
301
+
302
+ return splitSelectClause(selectMatch[1].trim()).some((part) => {
303
+ const trimmedPart = part.trim();
304
+ return (
305
+ /^\(\s*`?\w+`?\s*\)\s*\.\s*\*$/.test(trimmedPart) ||
306
+ /^`?\w+`?\s*\.\s*\*$/.test(trimmedPart)
307
+ );
308
+ });
309
+ }
310
+
296
311
  /**
297
- * Builds a covering index CREATE statement from a query
312
+ * Builds a covering or fallback non-covering index CREATE statement from a query
298
313
  * @param {string} query - The N1QL query to analyze
299
314
  * @param {Object} options - Configuration options
300
315
  * @param {string} options.bucket - The bucket name
@@ -303,16 +318,17 @@ function splitSelectClause(clause) {
303
318
  * @returns {string|null} - The CREATE INDEX statement, or null if cannot build
304
319
  */
305
320
  function buildCoveringIndex(query, options) {
306
- const { bucket, scope, collection } = options;
321
+ const { bucket, scope = "_default", collection = "_default" } = options;
307
322
 
308
- if (!bucket || !scope || !collection) {
323
+ if (!bucket) {
309
324
  return null;
310
325
  }
311
326
 
312
327
  // Extract fields from SELECT clause
313
328
  const selectFields = extractSelectFields(query);
314
- if (selectFields === null) {
315
- // SELECT * query - cannot create covering index
329
+ const isNonCoveringFallback =
330
+ selectFields === null && hasQualifiedWildcardProjection(query);
331
+ if (selectFields === null && !isNonCoveringFallback) {
316
332
  return null;
317
333
  }
318
334
 
@@ -356,7 +372,7 @@ function buildCoveringIndex(query, options) {
356
372
  });
357
373
 
358
374
  // Filter SELECT fields (remove duplicates from WHERE, GROUP BY, and ORDER BY, remove deleted)
359
- const selectFieldsFiltered = selectFields.filter((f) => {
375
+ const selectFieldsFiltered = (selectFields || []).filter((f) => {
360
376
  const lower = f.toLowerCase();
361
377
  if (addedFields.has(lower) || lower === "deleted") {
362
378
  return false;
@@ -393,9 +409,10 @@ function buildCoveringIndex(query, options) {
393
409
  const orderFieldsKey = orderByIndexFields
394
410
  .map((field) => formatIndexKey(field.name, orderDirectionMap))
395
411
  .join(",");
396
- const indexKey = `${bucket}|${scope}|${collection}|fields:${indexFieldsKey}|order:${orderFieldsKey}`;
412
+ const indexMode = isNonCoveringFallback ? "noncovered" : "covered";
413
+ const indexKey = `${bucket}|${scope}|${collection}|mode:${indexMode}|fields:${indexFieldsKey}|order:${orderFieldsKey}`;
397
414
  const hash = generateHash(indexKey);
398
- const indexName = `adv_covered_${hash}`;
415
+ const indexName = `adv_${indexMode}_${hash}`;
399
416
 
400
417
  // Build the CREATE INDEX statement
401
418
  const indexStatement = `CREATE INDEX \`${indexName}\` ON \`default\`:\`${bucket}\`.\`${scope}\`.\`${collection}\`(${fieldList})`;