@mastra/qdrant 0.2.13-alpha.0 → 0.2.13

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,23 +1,23 @@
1
1
 
2
- > @mastra/qdrant@0.2.13-alpha.0 build /home/runner/work/mastra/mastra/stores/qdrant
2
+ > @mastra/qdrant@0.2.13-alpha.1 build /home/runner/work/mastra/mastra/stores/qdrant
3
3
  > tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting
4
4
 
5
5
  CLI Building entry: src/index.ts
6
6
  CLI Using tsconfig: tsconfig.json
7
7
  CLI tsup v8.4.0
8
8
  TSC Build start
9
- TSC ⚡️ Build success in 6421ms
9
+ TSC ⚡️ Build success in 8886ms
10
10
  DTS Build start
11
11
  CLI Target: es2022
12
12
  Analysis will use the bundled TypeScript version 5.8.3
13
13
  Writing package typings: /home/runner/work/mastra/mastra/stores/qdrant/dist/_tsup-dts-rollup.d.ts
14
14
  Analysis will use the bundled TypeScript version 5.8.3
15
15
  Writing package typings: /home/runner/work/mastra/mastra/stores/qdrant/dist/_tsup-dts-rollup.d.cts
16
- DTS ⚡️ Build success in 8435ms
16
+ DTS ⚡️ Build success in 9642ms
17
17
  CLI Cleaning output folder
18
18
  ESM Build start
19
19
  CJS Build start
20
- CJS dist/index.cjs 16.64 KB
21
- CJS ⚡️ Build success in 655ms
22
- ESM dist/index.js 16.58 KB
23
- ESM ⚡️ Build success in 656ms
20
+ ESM dist/index.js 16.97 KB
21
+ ESM ⚡️ Build success in 811ms
22
+ CJS dist/index.cjs 17.03 KB
23
+ CJS ⚡️ Build success in 820ms
package/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # @mastra/qdrant
2
2
 
3
+ ## 0.2.13
4
+
5
+ ### Patch Changes
6
+
7
+ - 9cd1a46: [MASTRA-3338] update naming scheme for embedding index based on vector store rules and added duplicate index checks
8
+ - Updated dependencies [e450778]
9
+ - Updated dependencies [8902157]
10
+ - Updated dependencies [ca0dc88]
11
+ - Updated dependencies [526c570]
12
+ - Updated dependencies [d7a6a33]
13
+ - Updated dependencies [9cd1a46]
14
+ - Updated dependencies [b5d2de0]
15
+ - Updated dependencies [644f8ad]
16
+ - Updated dependencies [70dbf51]
17
+ - @mastra/core@0.9.3
18
+
19
+ ## 0.2.13-alpha.1
20
+
21
+ ### Patch Changes
22
+
23
+ - 9cd1a46: [MASTRA-3338] update naming scheme for embedding index based on vector store rules and added duplicate index checks
24
+ - Updated dependencies [e450778]
25
+ - Updated dependencies [8902157]
26
+ - Updated dependencies [ca0dc88]
27
+ - Updated dependencies [9cd1a46]
28
+ - Updated dependencies [70dbf51]
29
+ - @mastra/core@0.9.3-alpha.1
30
+
3
31
  ## 0.2.13-alpha.0
4
32
 
5
33
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -279,14 +279,23 @@ var QdrantVector = class extends vector.MastraVector {
279
279
  if (!Number.isInteger(dimension) || dimension <= 0) {
280
280
  throw new Error("Dimension must be a positive integer");
281
281
  }
282
- await this.client.createCollection(indexName, {
283
- vectors: {
284
- // @ts-expect-error
285
- size: dimension,
286
- // @ts-expect-error
287
- distance: DISTANCE_MAPPING[metric]
282
+ if (!DISTANCE_MAPPING[metric]) {
283
+ throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
284
+ }
285
+ try {
286
+ await this.client.createCollection(indexName, {
287
+ vectors: {
288
+ size: dimension,
289
+ distance: DISTANCE_MAPPING[metric]
290
+ }
291
+ });
292
+ } catch (error) {
293
+ const message = error?.message || error?.toString();
294
+ if (error?.status === 409 || typeof message === "string" && message.toLowerCase().includes("exists")) {
295
+ await this.validateExistingIndex(indexName, dimension, metric);
296
+ return;
288
297
  }
289
- });
298
+ }
290
299
  }
291
300
  transformFilter(filter) {
292
301
  const translator = new QdrantFilterTranslator();
package/dist/index.js CHANGED
@@ -277,14 +277,23 @@ var QdrantVector = class extends MastraVector {
277
277
  if (!Number.isInteger(dimension) || dimension <= 0) {
278
278
  throw new Error("Dimension must be a positive integer");
279
279
  }
280
- await this.client.createCollection(indexName, {
281
- vectors: {
282
- // @ts-expect-error
283
- size: dimension,
284
- // @ts-expect-error
285
- distance: DISTANCE_MAPPING[metric]
280
+ if (!DISTANCE_MAPPING[metric]) {
281
+ throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
282
+ }
283
+ try {
284
+ await this.client.createCollection(indexName, {
285
+ vectors: {
286
+ size: dimension,
287
+ distance: DISTANCE_MAPPING[metric]
288
+ }
289
+ });
290
+ } catch (error) {
291
+ const message = error?.message || error?.toString();
292
+ if (error?.status === 409 || typeof message === "string" && message.toLowerCase().includes("exists")) {
293
+ await this.validateExistingIndex(indexName, dimension, metric);
294
+ return;
286
295
  }
287
- });
296
+ }
288
297
  }
289
298
  transformFilter(filter) {
290
299
  const translator = new QdrantFilterTranslator();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mastra/qdrant",
3
- "version": "0.2.13-alpha.0",
3
+ "version": "0.2.13",
4
4
  "description": "Qdrant vector store provider for Mastra",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -21,7 +21,7 @@
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
23
  "@qdrant/js-client-rest": "^1.13.0",
24
- "@mastra/core": "^0.9.3-alpha.0"
24
+ "@mastra/core": "^0.9.3"
25
25
  },
26
26
  "devDependencies": {
27
27
  "@microsoft/api-extractor": "^7.52.5",
@@ -30,7 +30,7 @@
30
30
  "tsup": "^8.4.0",
31
31
  "typescript": "^5.8.2",
32
32
  "vitest": "^3.1.2",
33
- "@internal/lint": "0.0.3"
33
+ "@internal/lint": "0.0.4"
34
34
  },
35
35
  "scripts": {
36
36
  "build": "tsup src/index.ts --format esm,cjs --experimental-dts --clean --treeshake=smallest --splitting",
@@ -184,8 +184,8 @@ describe('QdrantVector', () => {
184
184
  // expect(results[0]?.vector).toEqual(newVector);
185
185
  });
186
186
 
187
- it('should throw exception when no updates are given', () => {
188
- expect(qdrant.updateIndexById(testCollectionName, 'id', {})).rejects.toThrow('No updates provided');
187
+ it('should throw exception when no updates are given', async () => {
188
+ await expect(qdrant.updateIndexById(testCollectionName, 'id', {})).rejects.toThrow('No updates provided');
189
189
  });
190
190
 
191
191
  it('should throw error for non-existent index', async () => {
@@ -755,6 +755,15 @@ describe('QdrantVector', () => {
755
755
  });
756
756
  });
757
757
  describe('Error Handling', () => {
758
+ const testIndexName = 'test_index_error';
759
+ beforeAll(async () => {
760
+ await qdrant.createIndex({ indexName: testIndexName, dimension: 3 });
761
+ });
762
+
763
+ afterAll(async () => {
764
+ await qdrant.deleteIndex(testIndexName);
765
+ });
766
+
758
767
  it('should handle non-existent index query gracefully', async () => {
759
768
  const nonExistentIndex = 'non-existent-index';
760
769
  await expect(qdrant.query({ indexName: nonExistentIndex, queryVector: [1, 0, 0] })).rejects.toThrow();
@@ -764,6 +773,65 @@ describe('QdrantVector', () => {
764
773
  const wrongDimVector = [[1, 0]]; // 2D vector for 3D index
765
774
  await expect(qdrant.upsert({ indexName: testCollectionName, vectors: wrongDimVector })).rejects.toThrow();
766
775
  }, 50000);
776
+
777
+ it('should handle mismatched metadata and vectors length', async () => {
778
+ const vectors = [[1, 2, 3]];
779
+ const metadata = [{}, {}];
780
+ await expect(qdrant.upsert({ indexName: testCollectionName, vectors, metadata })).rejects.toThrow();
781
+ });
782
+
783
+ it('should handle duplicate index creation gracefully', async () => {
784
+ const duplicateIndexName = `duplicate_test`;
785
+ const dimension = 768;
786
+ const infoSpy = vi.spyOn(qdrant['logger'], 'info');
787
+ const warnSpy = vi.spyOn(qdrant['logger'], 'warn');
788
+ try {
789
+ // Create index first time
790
+ await qdrant.createIndex({
791
+ indexName: duplicateIndexName,
792
+ dimension,
793
+ metric: 'cosine',
794
+ });
795
+
796
+ // Try to create with same dimensions - should not throw
797
+ await expect(
798
+ qdrant.createIndex({
799
+ indexName: duplicateIndexName,
800
+ dimension,
801
+ metric: 'cosine',
802
+ }),
803
+ ).resolves.not.toThrow();
804
+
805
+ expect(infoSpy).toHaveBeenCalledWith(expect.stringContaining('already exists with'));
806
+
807
+ // Try to create with same dimensions and different metric - should not throw
808
+ await expect(
809
+ qdrant.createIndex({
810
+ indexName: duplicateIndexName,
811
+ dimension,
812
+ metric: 'euclidean',
813
+ }),
814
+ ).resolves.not.toThrow();
815
+
816
+ expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('Attempted to create index with metric'));
817
+
818
+ // Try to create with different dimensions - should throw
819
+ await expect(
820
+ qdrant.createIndex({
821
+ indexName: duplicateIndexName,
822
+ dimension: dimension + 1,
823
+ metric: 'cosine',
824
+ }),
825
+ ).rejects.toThrow(
826
+ `Index "${duplicateIndexName}" already exists with ${dimension} dimensions, but ${dimension + 1} dimensions were requested`,
827
+ );
828
+ } finally {
829
+ infoSpy.mockRestore();
830
+ warnSpy.mockRestore();
831
+ // Cleanup
832
+ await qdrant.deleteIndex(duplicateIndexName);
833
+ }
834
+ });
767
835
  });
768
836
 
769
837
  describe('Empty/Undefined Filters', () => {
@@ -75,14 +75,25 @@ export class QdrantVector extends MastraVector {
75
75
  if (!Number.isInteger(dimension) || dimension <= 0) {
76
76
  throw new Error('Dimension must be a positive integer');
77
77
  }
78
- await this.client.createCollection(indexName, {
79
- vectors: {
80
- // @ts-expect-error
81
- size: dimension,
82
- // @ts-expect-error
83
- distance: DISTANCE_MAPPING[metric],
84
- },
85
- });
78
+ if (!DISTANCE_MAPPING[metric]) {
79
+ throw new Error(`Invalid metric: "${metric}". Must be one of: cosine, euclidean, dotproduct`);
80
+ }
81
+ try {
82
+ await this.client.createCollection(indexName, {
83
+ vectors: {
84
+ size: dimension,
85
+ distance: DISTANCE_MAPPING[metric],
86
+ },
87
+ });
88
+ } catch (error: any) {
89
+ const message = error?.message || error?.toString();
90
+ // Qdrant typically returns 409 for existing collection
91
+ if (error?.status === 409 || (typeof message === 'string' && message.toLowerCase().includes('exists'))) {
92
+ // Fetch collection info and check dimension
93
+ await this.validateExistingIndex(indexName, dimension, metric);
94
+ return;
95
+ }
96
+ }
86
97
  }
87
98
 
88
99
  transformFilter(filter?: VectorFilter) {