@mastra/couchbase 1.1.0 → 1.1.1

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