@mastra/couchbase 0.0.0-trigger-playground-ui-package-20250506151043 → 0.0.0-tsconfig-compile-20250703214351

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.
@@ -1,3 +1,4 @@
1
+ import { ErrorCategory, ErrorDomain, MastraError } from '@mastra/core/error';
1
2
  import { MastraVector } from '@mastra/core/vector';
2
3
  import type {
3
4
  QueryResult,
@@ -5,9 +6,13 @@ import type {
5
6
  CreateIndexParams,
6
7
  UpsertVectorParams,
7
8
  QueryVectorParams,
9
+ DescribeIndexParams,
10
+ DeleteIndexParams,
11
+ DeleteVectorParams,
12
+ UpdateVectorParams,
8
13
  } from '@mastra/core/vector';
9
14
  import type { Bucket, Cluster, Collection, Scope } from 'couchbase';
10
- import { connect, SearchRequest, VectorQuery, VectorSearch } from 'couchbase';
15
+ import { MutateInSpec, connect, SearchRequest, VectorQuery, VectorSearch } from 'couchbase';
11
16
 
12
17
  type MastraMetric = 'cosine' | 'euclidean' | 'dotproduct';
13
18
  type CouchbaseMetric = 'cosine' | 'l2_norm' | 'dot_product';
@@ -17,6 +22,15 @@ export const DISTANCE_MAPPING: Record<MastraMetric, CouchbaseMetric> = {
17
22
  dotproduct: 'dot_product',
18
23
  };
19
24
 
25
+ export type CouchbaseVectorParams = {
26
+ connectionString: string;
27
+ username: string;
28
+ password: string;
29
+ bucketName: string;
30
+ scopeName: string;
31
+ collectionName: string;
32
+ };
33
+
20
34
  export class CouchbaseVector extends MastraVector {
21
35
  private clusterPromise: Promise<Cluster>;
22
36
  private cluster: Cluster;
@@ -28,38 +42,50 @@ export class CouchbaseVector extends MastraVector {
28
42
  private scope: Scope;
29
43
  private vector_dimension: number;
30
44
 
31
- constructor(
32
- cnn_string: string,
33
- username: string,
34
- password: string,
35
- bucketName: string,
36
- scopeName: string,
37
- collectionName: string,
38
- ) {
45
+ constructor({ connectionString, username, password, bucketName, scopeName, collectionName }: CouchbaseVectorParams) {
39
46
  super();
40
47
 
41
- const baseClusterPromise = connect(cnn_string, {
42
- username,
43
- password,
44
- configProfile: 'wanDevelopment',
45
- });
46
-
47
- const telemetry = this.__getTelemetry();
48
- this.clusterPromise =
49
- telemetry?.traceClass(baseClusterPromise, {
50
- spanNamePrefix: 'couchbase-vector',
51
- attributes: {
52
- 'vector.type': 'couchbase',
48
+ try {
49
+ const baseClusterPromise = connect(connectionString, {
50
+ username,
51
+ password,
52
+ configProfile: 'wanDevelopment',
53
+ });
54
+
55
+ const telemetry = this.__getTelemetry();
56
+ this.clusterPromise =
57
+ telemetry?.traceClass(baseClusterPromise, {
58
+ spanNamePrefix: 'couchbase-vector',
59
+ attributes: {
60
+ 'vector.type': 'couchbase',
61
+ },
62
+ }) ?? baseClusterPromise;
63
+ this.cluster = null as unknown as Cluster;
64
+ this.bucketName = bucketName;
65
+ this.collectionName = collectionName;
66
+ this.scopeName = scopeName;
67
+ this.collection = null as unknown as Collection;
68
+ this.bucket = null as unknown as Bucket;
69
+ this.scope = null as unknown as Scope;
70
+ this.vector_dimension = null as unknown as number;
71
+ } catch (error) {
72
+ throw new MastraError(
73
+ {
74
+ id: 'COUCHBASE_VECTOR_INITIALIZE_FAILED',
75
+ domain: ErrorDomain.STORAGE,
76
+ category: ErrorCategory.THIRD_PARTY,
77
+ details: {
78
+ connectionString,
79
+ username,
80
+ password,
81
+ bucketName,
82
+ scopeName,
83
+ collectionName,
84
+ },
53
85
  },
54
- }) ?? baseClusterPromise;
55
- this.cluster = null as unknown as Cluster;
56
- this.bucketName = bucketName;
57
- this.collectionName = collectionName;
58
- this.scopeName = scopeName;
59
- this.collection = null as unknown as Collection;
60
- this.bucket = null as unknown as Bucket;
61
- this.scope = null as unknown as Scope;
62
- this.vector_dimension = null as unknown as number;
86
+ error,
87
+ );
88
+ }
63
89
  }
64
90
 
65
91
  async getCollection() {
@@ -76,201 +102,403 @@ export class CouchbaseVector extends MastraVector {
76
102
  return this.collection;
77
103
  }
78
104
 
79
- async createIndex(params: CreateIndexParams): Promise<void> {
80
- const { indexName, dimension, metric = 'dotproduct' as MastraMetric } = params;
81
- await this.getCollection();
105
+ async createIndex({ indexName, dimension, metric = 'dotproduct' as MastraMetric }: CreateIndexParams): Promise<void> {
106
+ try {
107
+ await this.getCollection();
82
108
 
83
- if (!Number.isInteger(dimension) || dimension <= 0) {
84
- throw new Error('Dimension must be a positive integer');
85
- }
109
+ if (!Number.isInteger(dimension) || dimension <= 0) {
110
+ throw new Error('Dimension must be a positive integer');
111
+ }
86
112
 
87
- await this.scope.searchIndexes().upsertIndex({
88
- name: indexName,
89
- sourceName: this.bucketName,
90
- type: 'fulltext-index',
91
- params: {
92
- doc_config: {
93
- docid_prefix_delim: '',
94
- docid_regexp: '',
95
- mode: 'scope.collection.type_field',
96
- type_field: 'type',
97
- },
98
- mapping: {
99
- default_analyzer: 'standard',
100
- default_datetime_parser: 'dateTimeOptional',
101
- default_field: '_all',
102
- default_mapping: {
103
- dynamic: true,
104
- enabled: false,
113
+ await this.scope.searchIndexes().upsertIndex({
114
+ name: indexName,
115
+ sourceName: this.bucketName,
116
+ type: 'fulltext-index',
117
+ params: {
118
+ doc_config: {
119
+ docid_prefix_delim: '',
120
+ docid_regexp: '',
121
+ mode: 'scope.collection.type_field',
122
+ type_field: 'type',
105
123
  },
106
- default_type: '_default',
107
- docvalues_dynamic: true, // [Doc](https://docs.couchbase.com/server/current/search/search-index-params.html#params) mentions this attribute is required for vector search to return the indexed field
108
- index_dynamic: true,
109
- store_dynamic: true, // [Doc](https://docs.couchbase.com/server/current/search/search-index-params.html#params) mentions this attribute is required for vector search to return the indexed field
110
- type_field: '_type',
111
- types: {
112
- [`${this.scopeName}.${this.collectionName}`]: {
124
+ mapping: {
125
+ default_analyzer: 'standard',
126
+ default_datetime_parser: 'dateTimeOptional',
127
+ default_field: '_all',
128
+ default_mapping: {
113
129
  dynamic: true,
114
- enabled: true,
115
- properties: {
116
- embedding: {
117
- enabled: true,
118
- fields: [
119
- {
120
- dims: dimension,
121
- index: true,
122
- name: 'embedding',
123
- similarity: DISTANCE_MAPPING[metric],
124
- type: 'vector',
125
- vector_index_optimized_for: 'recall',
126
- store: true, // CHANGED due to https://docs.couchbase.com/server/current/search/search-index-params.html#fields
127
- docvalues: true, // CHANGED due to https://docs.couchbase.com/server/current/search/search-index-params.html#fields
128
- include_term_vectors: true, // CHANGED due to https://docs.couchbase.com/server/current/search/search-index-params.html#fields
129
- },
130
- ],
131
- },
132
- content: {
133
- enabled: true,
134
- fields: [
135
- {
136
- index: true,
137
- name: 'content',
138
- store: true,
139
- type: 'text',
140
- },
141
- ],
130
+ enabled: false,
131
+ },
132
+ default_type: '_default',
133
+ docvalues_dynamic: true, // [Doc](https://docs.couchbase.com/server/current/search/search-index-params.html#params) mentions this attribute is required for vector search to return the indexed field
134
+ index_dynamic: true,
135
+ store_dynamic: true, // [Doc](https://docs.couchbase.com/server/current/search/search-index-params.html#params) mentions this attribute is required for vector search to return the indexed field
136
+ type_field: '_type',
137
+ types: {
138
+ [`${this.scopeName}.${this.collectionName}`]: {
139
+ dynamic: true,
140
+ enabled: true,
141
+ properties: {
142
+ embedding: {
143
+ enabled: true,
144
+ fields: [
145
+ {
146
+ dims: dimension,
147
+ index: true,
148
+ name: 'embedding',
149
+ similarity: DISTANCE_MAPPING[metric],
150
+ type: 'vector',
151
+ vector_index_optimized_for: 'recall',
152
+ store: true, // CHANGED due to https://docs.couchbase.com/server/current/search/search-index-params.html#fields
153
+ docvalues: true, // CHANGED due to https://docs.couchbase.com/server/current/search/search-index-params.html#fields
154
+ include_term_vectors: true, // CHANGED due to https://docs.couchbase.com/server/current/search/search-index-params.html#fields
155
+ },
156
+ ],
157
+ },
158
+ content: {
159
+ enabled: true,
160
+ fields: [
161
+ {
162
+ index: true,
163
+ name: 'content',
164
+ store: true,
165
+ type: 'text',
166
+ },
167
+ ],
168
+ },
142
169
  },
143
170
  },
144
171
  },
145
172
  },
173
+ store: {
174
+ indexType: 'scorch',
175
+ segmentVersion: 16,
176
+ },
146
177
  },
147
- store: {
148
- indexType: 'scorch',
149
- segmentVersion: 16,
178
+ sourceUuid: '',
179
+ sourceParams: {},
180
+ sourceType: 'gocbcore',
181
+ planParams: {
182
+ maxPartitionsPerPIndex: 64,
183
+ indexPartitions: 16,
184
+ numReplicas: 0,
150
185
  },
151
- },
152
- sourceUuid: '',
153
- sourceParams: {},
154
- sourceType: 'gocbcore',
155
- planParams: {
156
- maxPartitionsPerPIndex: 64,
157
- indexPartitions: 16,
158
- numReplicas: 0,
159
- },
160
- });
161
- this.vector_dimension = dimension;
186
+ });
187
+ this.vector_dimension = dimension;
188
+ } catch (error: any) {
189
+ // Check for 'already exists' error (Couchbase may throw a 400 or 409, or have a message)
190
+ const message = error?.message || error?.toString();
191
+ if (message && message.toLowerCase().includes('index exists')) {
192
+ // Fetch index info and check dimension
193
+ await this.validateExistingIndex(indexName, dimension, metric);
194
+ return;
195
+ }
196
+ throw new MastraError(
197
+ {
198
+ id: 'COUCHBASE_VECTOR_CREATE_INDEX_FAILED',
199
+ domain: ErrorDomain.STORAGE,
200
+ category: ErrorCategory.THIRD_PARTY,
201
+ details: {
202
+ indexName,
203
+ dimension,
204
+ metric,
205
+ },
206
+ },
207
+ error,
208
+ );
209
+ }
162
210
  }
163
211
 
164
- async upsert(params: UpsertVectorParams): Promise<string[]> {
165
- const { vectors, metadata, ids } = params;
166
- await this.getCollection();
212
+ async upsert({ vectors, metadata, ids }: UpsertVectorParams): Promise<string[]> {
213
+ try {
214
+ await this.getCollection();
167
215
 
168
- if (!vectors || vectors.length === 0) {
169
- throw new Error('No vectors provided');
170
- }
171
- if (this.vector_dimension) {
172
- for (const vector of vectors) {
173
- if (!vector || this.vector_dimension !== vector.length) {
174
- throw new Error('Vector dimension mismatch');
216
+ if (!vectors || vectors.length === 0) {
217
+ throw new Error('No vectors provided');
218
+ }
219
+ if (this.vector_dimension) {
220
+ for (const vector of vectors) {
221
+ if (!vector || this.vector_dimension !== vector.length) {
222
+ throw new Error('Vector dimension mismatch');
223
+ }
175
224
  }
176
225
  }
177
- }
178
226
 
179
- const pointIds = ids || vectors.map(() => crypto.randomUUID());
180
- const records = vectors.map((vector, i) => {
181
- const metadataObj = metadata?.[i] || {};
182
- const record: Record<string, any> = {
183
- embedding: vector,
184
- metadata: metadataObj,
185
- };
186
- // If metadata has a text field, save it as content
187
- if (metadataObj.text) {
188
- record.content = metadataObj.text;
227
+ const pointIds = ids || vectors.map(() => crypto.randomUUID());
228
+ const records = vectors.map((vector, i) => {
229
+ const metadataObj = metadata?.[i] || {};
230
+ const record: Record<string, any> = {
231
+ embedding: vector,
232
+ metadata: metadataObj,
233
+ };
234
+ // If metadata has a text field, save it as content
235
+ if (metadataObj.text) {
236
+ record.content = metadataObj.text;
237
+ }
238
+ return record;
239
+ });
240
+
241
+ const allPromises = [];
242
+ for (let i = 0; i < records.length; i++) {
243
+ allPromises.push(this.collection.upsert(pointIds[i]!, records[i]));
189
244
  }
190
- return record;
191
- });
245
+ await Promise.all(allPromises);
192
246
 
193
- const allPromises = [];
194
- for (let i = 0; i < records.length; i++) {
195
- allPromises.push(this.collection.upsert(pointIds[i]!, records[i]));
247
+ return pointIds;
248
+ } catch (error) {
249
+ throw new MastraError(
250
+ {
251
+ id: 'COUCHBASE_VECTOR_UPSERT_FAILED',
252
+ domain: ErrorDomain.STORAGE,
253
+ category: ErrorCategory.THIRD_PARTY,
254
+ },
255
+ error,
256
+ );
196
257
  }
197
- await Promise.all(allPromises);
198
-
199
- return pointIds;
200
258
  }
201
259
 
202
- async query(params: QueryVectorParams): Promise<QueryResult[]> {
203
- const { indexName, queryVector, topK = 10, includeVector = false } = params;
260
+ async query({ indexName, queryVector, topK = 10, includeVector = false }: QueryVectorParams): Promise<QueryResult[]> {
261
+ try {
262
+ await this.getCollection();
204
263
 
205
- await this.getCollection();
264
+ const index_stats = await this.describeIndex({ indexName });
265
+ if (queryVector.length !== index_stats.dimension) {
266
+ throw new Error(
267
+ `Query vector dimension mismatch. Expected ${index_stats.dimension}, got ${queryVector.length}`,
268
+ );
269
+ }
270
+
271
+ let request = SearchRequest.create(
272
+ VectorSearch.fromVectorQuery(VectorQuery.create('embedding', queryVector).numCandidates(topK)),
273
+ );
274
+ const results = await this.scope.search(indexName, request, {
275
+ fields: ['*'],
276
+ });
277
+
278
+ if (includeVector) {
279
+ throw new Error('Including vectors in search results is not yet supported by the Couchbase vector store');
280
+ }
281
+ const output = [];
282
+ for (const match of results.rows) {
283
+ const cleanedMetadata: Record<string, any> = {};
284
+ const fields = (match.fields as Record<string, any>) || {}; // Ensure fields is an object
285
+ for (const key in fields) {
286
+ if (Object.prototype.hasOwnProperty.call(fields, key)) {
287
+ const newKey = key.startsWith('metadata.') ? key.substring('metadata.'.length) : key;
288
+ cleanedMetadata[newKey] = fields[key];
289
+ }
290
+ }
291
+ output.push({
292
+ id: match.id as string,
293
+ score: (match.score as number) || 0,
294
+ metadata: cleanedMetadata, // Use the cleaned metadata object
295
+ });
296
+ }
297
+ return output;
298
+ } catch (error) {
299
+ throw new MastraError(
300
+ {
301
+ id: 'COUCHBASE_VECTOR_QUERY_FAILED',
302
+ domain: ErrorDomain.STORAGE,
303
+ category: ErrorCategory.THIRD_PARTY,
304
+ details: {
305
+ indexName,
306
+ topK,
307
+ },
308
+ },
309
+ error,
310
+ );
311
+ }
312
+ }
206
313
 
207
- const index_stats = await this.describeIndex(indexName);
208
- if (queryVector.length !== index_stats.dimension) {
209
- throw new Error(`Query vector dimension mismatch. Expected ${index_stats.dimension}, got ${queryVector.length}`);
314
+ async listIndexes(): Promise<string[]> {
315
+ try {
316
+ await this.getCollection();
317
+ const indexes = await this.scope.searchIndexes().getAllIndexes();
318
+ return indexes?.map(index => index.name) || [];
319
+ } catch (error) {
320
+ throw new MastraError(
321
+ {
322
+ id: 'COUCHBASE_VECTOR_LIST_INDEXES_FAILED',
323
+ domain: ErrorDomain.STORAGE,
324
+ category: ErrorCategory.THIRD_PARTY,
325
+ },
326
+ error,
327
+ );
210
328
  }
329
+ }
211
330
 
212
- let request = SearchRequest.create(
213
- VectorSearch.fromVectorQuery(VectorQuery.create('embedding', queryVector).numCandidates(topK)),
214
- );
215
- const results = await this.scope.search(indexName, request, {
216
- fields: ['*'],
217
- });
331
+ /**
332
+ * Retrieves statistics about a vector index.
333
+ *
334
+ * @param {string} indexName - The name of the index to describe
335
+ * @returns A promise that resolves to the index statistics including dimension, count and metric
336
+ */
337
+ async describeIndex({ indexName }: DescribeIndexParams): Promise<IndexStats> {
338
+ try {
339
+ await this.getCollection();
340
+ if (!(await this.listIndexes()).includes(indexName)) {
341
+ throw new Error(`Index ${indexName} does not exist`);
342
+ }
343
+ const index = await this.scope.searchIndexes().getIndex(indexName);
344
+ const dimensions =
345
+ index.params.mapping?.types?.[`${this.scopeName}.${this.collectionName}`]?.properties?.embedding?.fields?.[0]
346
+ ?.dims;
347
+ const count = -1; // Not added support yet for adding a count of documents covered by an index
348
+ const metric = index.params.mapping?.types?.[`${this.scopeName}.${this.collectionName}`]?.properties?.embedding
349
+ ?.fields?.[0]?.similarity as CouchbaseMetric;
350
+ return {
351
+ dimension: dimensions,
352
+ count: count,
353
+ metric: Object.keys(DISTANCE_MAPPING).find(
354
+ key => DISTANCE_MAPPING[key as MastraMetric] === metric,
355
+ ) as MastraMetric,
356
+ };
357
+ } catch (error) {
358
+ throw new MastraError(
359
+ {
360
+ id: 'COUCHBASE_VECTOR_DESCRIBE_INDEX_FAILED',
361
+ domain: ErrorDomain.STORAGE,
362
+ category: ErrorCategory.THIRD_PARTY,
363
+ details: {
364
+ indexName,
365
+ },
366
+ },
367
+ error,
368
+ );
369
+ }
370
+ }
218
371
 
219
- if (includeVector) {
220
- throw new Error('Including vectors in search results is not yet supported by the Couchbase vector store');
372
+ async deleteIndex({ indexName }: DeleteIndexParams): Promise<void> {
373
+ try {
374
+ await this.getCollection();
375
+ if (!(await this.listIndexes()).includes(indexName)) {
376
+ throw new Error(`Index ${indexName} does not exist`);
377
+ }
378
+ await this.scope.searchIndexes().dropIndex(indexName);
379
+ this.vector_dimension = null as unknown as number;
380
+ } catch (error) {
381
+ if (error instanceof MastraError) {
382
+ throw error;
383
+ }
384
+ throw new MastraError(
385
+ {
386
+ id: 'COUCHBASE_VECTOR_DELETE_INDEX_FAILED',
387
+ domain: ErrorDomain.STORAGE,
388
+ category: ErrorCategory.THIRD_PARTY,
389
+ details: {
390
+ indexName,
391
+ },
392
+ },
393
+ error,
394
+ );
221
395
  }
222
- const output = [];
223
- for (const match of results.rows) {
224
- const cleanedMetadata: Record<string, any> = {};
225
- const fields = (match.fields as Record<string, any>) || {}; // Ensure fields is an object
226
- for (const key in fields) {
227
- if (Object.prototype.hasOwnProperty.call(fields, key)) {
228
- const newKey = key.startsWith('metadata.') ? key.substring('metadata.'.length) : key;
229
- cleanedMetadata[newKey] = fields[key];
396
+ }
397
+
398
+ /**
399
+ * Updates a vector by its ID with the provided vector and/or metadata.
400
+ * @param indexName - The name of the index containing the vector.
401
+ * @param id - The ID of the vector to update.
402
+ * @param update - An object containing the vector and/or metadata to update.
403
+ * @param update.vector - An optional array of numbers representing the new vector.
404
+ * @param update.metadata - An optional record containing the new metadata.
405
+ * @returns A promise that resolves when the update is complete.
406
+ * @throws Will throw an error if no updates are provided or if the update operation fails.
407
+ */
408
+ async updateVector({ id, update }: UpdateVectorParams): Promise<void> {
409
+ try {
410
+ if (!update.vector && !update.metadata) {
411
+ throw new Error('No updates provided');
412
+ }
413
+ if (update.vector && this.vector_dimension && update.vector.length !== this.vector_dimension) {
414
+ throw new Error('Vector dimension mismatch');
415
+ }
416
+ const collection = await this.getCollection();
417
+
418
+ // Check if document exists
419
+ try {
420
+ await collection.get(id);
421
+ } catch (err: any) {
422
+ if (err.code === 13 || err.message?.includes('document not found')) {
423
+ throw new Error(`Vector with id ${id} does not exist`);
230
424
  }
425
+ throw err;
231
426
  }
232
- output.push({
233
- id: match.id as string,
234
- score: (match.score as number) || 0,
235
- metadata: cleanedMetadata, // Use the cleaned metadata object
236
- });
427
+
428
+ const specs: MutateInSpec[] = [];
429
+ if (update.vector) specs.push(MutateInSpec.replace('embedding', update.vector));
430
+ if (update.metadata) specs.push(MutateInSpec.replace('metadata', update.metadata));
431
+
432
+ await collection.mutateIn(id, specs);
433
+ } catch (error) {
434
+ throw new MastraError(
435
+ {
436
+ id: 'COUCHBASE_VECTOR_UPDATE_FAILED',
437
+ domain: ErrorDomain.STORAGE,
438
+ category: ErrorCategory.THIRD_PARTY,
439
+ details: {
440
+ id,
441
+ hasVectorUpdate: !!update.vector,
442
+ hasMetadataUpdate: !!update.metadata,
443
+ },
444
+ },
445
+ error,
446
+ );
237
447
  }
238
- return output;
239
448
  }
240
449
 
241
- async listIndexes(): Promise<string[]> {
242
- await this.getCollection();
243
- const indexes = await this.scope.searchIndexes().getAllIndexes();
244
- return indexes?.map(index => index.name) || [];
245
- }
450
+ /**
451
+ * Deletes a vector by its ID.
452
+ * @param indexName - The name of the index containing the vector.
453
+ * @param id - The ID of the vector to delete.
454
+ * @returns A promise that resolves when the deletion is complete.
455
+ * @throws Will throw an error if the deletion operation fails.
456
+ */
457
+ async deleteVector({ id }: DeleteVectorParams): Promise<void> {
458
+ try {
459
+ const collection = await this.getCollection();
460
+
461
+ // Check if document exists
462
+ try {
463
+ await collection.get(id);
464
+ } catch (err: any) {
465
+ if (err.code === 13 || err.message?.includes('document not found')) {
466
+ throw new Error(`Vector with id ${id} does not exist`);
467
+ }
468
+ throw err;
469
+ }
246
470
 
247
- async describeIndex(indexName: string): Promise<IndexStats> {
248
- await this.getCollection();
249
- if (!(await this.listIndexes()).includes(indexName)) {
250
- throw new Error(`Index ${indexName} does not exist`);
471
+ await collection.remove(id);
472
+ } catch (error) {
473
+ throw new MastraError(
474
+ {
475
+ id: 'COUCHBASE_VECTOR_DELETE_FAILED',
476
+ domain: ErrorDomain.STORAGE,
477
+ category: ErrorCategory.THIRD_PARTY,
478
+ details: {
479
+ id,
480
+ },
481
+ },
482
+ error,
483
+ );
251
484
  }
252
- const index = await this.scope.searchIndexes().getIndex(indexName);
253
- const dimensions =
254
- index.params.mapping?.types?.[`${this.scopeName}.${this.collectionName}`]?.properties?.embedding?.fields?.[0]
255
- ?.dims;
256
- const count = -1; // Not added support yet for adding a count of documents covered by an index
257
- const metric = index.params.mapping?.types?.[`${this.scopeName}.${this.collectionName}`]?.properties?.embedding
258
- ?.fields?.[0]?.similarity as CouchbaseMetric;
259
- return {
260
- dimension: dimensions,
261
- count: count,
262
- metric: Object.keys(DISTANCE_MAPPING).find(
263
- key => DISTANCE_MAPPING[key as MastraMetric] === metric,
264
- ) as MastraMetric,
265
- };
266
485
  }
267
486
 
268
- async deleteIndex(indexName: string): Promise<void> {
269
- await this.getCollection();
270
- if (!(await this.listIndexes()).includes(indexName)) {
271
- throw new Error(`Index ${indexName} does not exist`);
487
+ async disconnect() {
488
+ try {
489
+ if (!this.cluster) {
490
+ return;
491
+ }
492
+ await this.cluster.close();
493
+ } catch (error) {
494
+ throw new MastraError(
495
+ {
496
+ id: 'COUCHBASE_VECTOR_DISCONNECT_FAILED',
497
+ domain: ErrorDomain.STORAGE,
498
+ category: ErrorCategory.THIRD_PARTY,
499
+ },
500
+ error,
501
+ );
272
502
  }
273
- await this.scope.searchIndexes().dropIndex(indexName);
274
- this.vector_dimension = null as unknown as number;
275
503
  }
276
504
  }