@mastra/pg 1.22.3-alpha.1 → 1.22.3-alpha.3
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/README.md +6 -484
- package/dist/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/index.cjs +61 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +61 -20
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/agents/index.d.ts +1 -0
- package/dist/storage/domains/agents/index.d.ts.map +1 -1
- package/dist/storage/domains/skills/index.d.ts +1 -0
- package/dist/storage/domains/skills/index.d.ts.map +1 -1
- package/dist/vector/index.d.ts.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -8,11 +8,6 @@ PostgreSQL implementation for Mastra, providing both vector similarity search (u
|
|
|
8
8
|
npm install @mastra/pg
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
## Prerequisites
|
|
12
|
-
|
|
13
|
-
- PostgreSQL server with pgvector extension installed (if using vector store)
|
|
14
|
-
- PostgreSQL 11 or higher
|
|
15
|
-
|
|
16
11
|
## Usage
|
|
17
12
|
|
|
18
13
|
### Vector Store
|
|
@@ -31,487 +26,14 @@ const vectorStore = new PgVector({
|
|
|
31
26
|
});
|
|
32
27
|
```
|
|
33
28
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
const vectorStore = new PgVector({
|
|
38
|
-
host: 'localhost',
|
|
39
|
-
port: 5432,
|
|
40
|
-
database: 'mydb',
|
|
41
|
-
user: 'postgres',
|
|
42
|
-
password: 'password',
|
|
43
|
-
});
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
> **Note:** PgVector also supports advanced configurations like Google Cloud SQL Connector via `pg.ClientConfig`.
|
|
47
|
-
|
|
48
|
-
#### Advanced Options
|
|
49
|
-
|
|
50
|
-
```typescript
|
|
51
|
-
const vectorStore = new PgVector({
|
|
52
|
-
connectionString: 'postgresql://user:pass@localhost:5432/db',
|
|
53
|
-
schemaName: 'custom_schema', // Use custom schema (default: public)
|
|
54
|
-
max: 30, // Max pool connections (default: 20)
|
|
55
|
-
idleTimeoutMillis: 60000, // Idle timeout (default: 30000)
|
|
56
|
-
pgPoolOptions: {
|
|
57
|
-
// Additional pg pool options
|
|
58
|
-
connectionTimeoutMillis: 5000,
|
|
59
|
-
allowExitOnIdle: true,
|
|
60
|
-
},
|
|
61
|
-
});
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
#### Usage Example
|
|
65
|
-
|
|
66
|
-
```typescript
|
|
67
|
-
// Create a new table with vector support
|
|
68
|
-
await vectorStore.createIndex({
|
|
69
|
-
indexName: 'my_vectors',
|
|
70
|
-
dimension: 1536,
|
|
71
|
-
metric: 'cosine',
|
|
72
|
-
// Optional: Configure index type and parameters
|
|
73
|
-
indexConfig: {
|
|
74
|
-
type: 'hnsw', // 'ivfflat' (default), 'hnsw', or 'flat'
|
|
75
|
-
hnsw: {
|
|
76
|
-
m: 16, // Number of connections per layer (default: 8)
|
|
77
|
-
efConstruction: 64 // Size of dynamic list (default: 32)
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
// Add vectors
|
|
83
|
-
const ids = await vectorStore.upsert({
|
|
84
|
-
indexName: 'my_vectors',
|
|
85
|
-
vectors: [[0.1, 0.2, ...], [0.3, 0.4, ...]],
|
|
86
|
-
metadata: [{ text: 'doc1' }, { text: 'doc2' }],
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
// Query vectors
|
|
90
|
-
const results = await vectorStore.query({
|
|
91
|
-
indexName: 'my_vectors',
|
|
92
|
-
queryVector: [0.1, 0.2, ...],
|
|
93
|
-
topK: 10, // topK
|
|
94
|
-
filter: { text: 'doc1' }, // filter
|
|
95
|
-
includeVector: false, // includeVector
|
|
96
|
-
minScore: 0.5, // minScore
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
// Clean up
|
|
100
|
-
await vectorStore.disconnect();
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Storage
|
|
104
|
-
|
|
105
|
-
```typescript
|
|
106
|
-
import { PostgresStore } from '@mastra/pg';
|
|
107
|
-
|
|
108
|
-
const store = new PostgresStore({
|
|
109
|
-
host: 'localhost',
|
|
110
|
-
port: 5432,
|
|
111
|
-
database: 'mastra',
|
|
112
|
-
user: 'postgres',
|
|
113
|
-
password: 'postgres',
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
// Create a thread
|
|
117
|
-
await store.saveThread({
|
|
118
|
-
thread: {
|
|
119
|
-
id: 'thread-123',
|
|
120
|
-
resourceId: 'resource-456',
|
|
121
|
-
title: 'My Thread',
|
|
122
|
-
metadata: { key: 'value' },
|
|
123
|
-
createdAt: new Date(),
|
|
124
|
-
},
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
// Add messages to thread
|
|
128
|
-
await store.saveMessages({
|
|
129
|
-
messages: [
|
|
130
|
-
{
|
|
131
|
-
id: 'msg-789',
|
|
132
|
-
threadId: 'thread-123',
|
|
133
|
-
role: 'user',
|
|
134
|
-
content: { content: 'Hello' },
|
|
135
|
-
resourceId: 'resource-456',
|
|
136
|
-
createdAt: new Date(),
|
|
137
|
-
},
|
|
138
|
-
],
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
// Query threads and messages
|
|
142
|
-
const savedThread = await store.getThreadById({ threadId: 'thread-123' });
|
|
143
|
-
const messages = await store.listMessages({ threadId: 'thread-123' });
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
## Configuration
|
|
147
|
-
|
|
148
|
-
### Connection Methods
|
|
149
|
-
|
|
150
|
-
Both `PgVector` and `PostgresStore` support multiple connection methods:
|
|
151
|
-
|
|
152
|
-
1. **Connection String**
|
|
153
|
-
|
|
154
|
-
```typescript
|
|
155
|
-
{
|
|
156
|
-
connectionString: 'postgresql://user:pass@localhost:5432/db';
|
|
157
|
-
}
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
2. **Host/Port/Database**
|
|
161
|
-
```typescript
|
|
162
|
-
{
|
|
163
|
-
host: 'localhost',
|
|
164
|
-
port: 5432,
|
|
165
|
-
database: 'mydb',
|
|
166
|
-
user: 'postgres',
|
|
167
|
-
password: 'password'
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
> **Advanced:** Also supports `pg.ClientConfig` for use cases like Google Cloud SQL Connector with IAM authentication.
|
|
172
|
-
|
|
173
|
-
### Optional Configuration
|
|
174
|
-
|
|
175
|
-
- `schemaName`: Custom PostgreSQL schema (default: `public`)
|
|
176
|
-
- `ssl`: Enable SSL or provide custom SSL options (`true` | `false` | `ConnectionOptions`)
|
|
177
|
-
- `max`: Maximum pool connections (default: `20`)
|
|
178
|
-
- `idleTimeoutMillis`: Idle connection timeout (default: `30000`)
|
|
179
|
-
- `pgPoolOptions`: Additional pg pool options (PgVector only)
|
|
180
|
-
|
|
181
|
-
### Default Connection Pool Settings
|
|
182
|
-
|
|
183
|
-
- Maximum connections: 20
|
|
184
|
-
- Idle timeout: 30 seconds
|
|
185
|
-
- Connection timeout: 2 seconds
|
|
186
|
-
|
|
187
|
-
## Features
|
|
188
|
-
|
|
189
|
-
### Vector Store Features
|
|
190
|
-
|
|
191
|
-
- Vector similarity search with cosine, euclidean, and dot product (inner) metrics
|
|
192
|
-
- Advanced metadata filtering with MongoDB-like query syntax
|
|
193
|
-
- Minimum score threshold for queries
|
|
194
|
-
- Automatic UUID generation for vectors
|
|
195
|
-
- Table management (create, list, describe, delete, truncate)
|
|
196
|
-
- Configurable vector index types:
|
|
197
|
-
- **IVFFlat** (default): Balanced speed/accuracy, auto-calculates optimal lists parameter
|
|
198
|
-
- **HNSW**: Fastest queries, higher memory usage, best for large datasets
|
|
199
|
-
- **Flat**: No index, 100% accuracy, best for small datasets (<1000 vectors)
|
|
200
|
-
|
|
201
|
-
### Storage Features
|
|
202
|
-
|
|
203
|
-
- Thread and message storage with JSON support
|
|
204
|
-
- Atomic transactions for data consistency
|
|
205
|
-
- Efficient batch operations
|
|
206
|
-
- Rich metadata support
|
|
207
|
-
- Timestamp tracking
|
|
208
|
-
- Cascading deletes
|
|
209
|
-
|
|
210
|
-
## Supported Filter Operators
|
|
211
|
-
|
|
212
|
-
The following filter operators are supported for metadata queries:
|
|
213
|
-
|
|
214
|
-
- Comparison: `$eq`, `$ne`, `$gt`, `$gte`, `$lt`, `$lte`
|
|
215
|
-
- Logical: `$and`, `$or`
|
|
216
|
-
- Array: `$in`, `$nin`
|
|
217
|
-
- Text: `$regex`, `$like`
|
|
218
|
-
|
|
219
|
-
Example filter:
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
{
|
|
223
|
-
$and: [{ age: { $gt: 25 } }, { tags: { $in: ['tag1', 'tag2'] } }];
|
|
224
|
-
}
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
## Vector Index Configuration
|
|
228
|
-
|
|
229
|
-
pgvector supports three index types, each with different performance characteristics:
|
|
230
|
-
|
|
231
|
-
### IVFFlat Index (Default)
|
|
232
|
-
|
|
233
|
-
IVFFlat groups vectors into clusters for efficient searching:
|
|
234
|
-
|
|
235
|
-
```typescript
|
|
236
|
-
await vectorStore.createIndex({
|
|
237
|
-
indexName: 'my_vectors',
|
|
238
|
-
dimension: 1536,
|
|
239
|
-
metric: 'cosine',
|
|
240
|
-
indexConfig: {
|
|
241
|
-
type: 'ivfflat',
|
|
242
|
-
ivf: {
|
|
243
|
-
lists: 1000, // Number of clusters (default: auto-calculated as sqrt(rows) * 2)
|
|
244
|
-
},
|
|
245
|
-
},
|
|
246
|
-
});
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
- **Best for:** Medium to large datasets (10K-1M vectors)
|
|
250
|
-
- **Build time:** Minutes for millions of vectors
|
|
251
|
-
- **Query speed:** Fast (tens of milliseconds)
|
|
252
|
-
- **Memory:** Moderate
|
|
253
|
-
- **Accuracy:** ~95-99%
|
|
254
|
-
|
|
255
|
-
### HNSW Index
|
|
256
|
-
|
|
257
|
-
HNSW builds a graph structure for extremely fast searches:
|
|
258
|
-
|
|
259
|
-
```typescript
|
|
260
|
-
await vectorStore.createIndex({
|
|
261
|
-
indexName: 'my_vectors',
|
|
262
|
-
dimension: 1536,
|
|
263
|
-
metric: 'dotproduct', // Recommended for normalized embeddings (OpenAI, etc.)
|
|
264
|
-
indexConfig: {
|
|
265
|
-
type: 'hnsw',
|
|
266
|
-
hnsw: {
|
|
267
|
-
m: 16, // Connections per layer (default: 8, range: 2-100)
|
|
268
|
-
efConstruction: 64, // Dynamic list size (default: 32, range: 4-1000)
|
|
269
|
-
},
|
|
270
|
-
},
|
|
271
|
-
});
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
- **Best for:** Large datasets (100K+ vectors) requiring fastest searches
|
|
275
|
-
- **Build time:** Can take hours for large datasets
|
|
276
|
-
- **Query speed:** Very fast (milliseconds even for millions)
|
|
277
|
-
- **Memory:** High (can be 2-3x vector size)
|
|
278
|
-
- **Accuracy:** ~99%
|
|
279
|
-
|
|
280
|
-
**Tuning HNSW:**
|
|
281
|
-
|
|
282
|
-
- Higher `m`: Better accuracy, more memory (16-32 for high accuracy)
|
|
283
|
-
- Higher `efConstruction`: Better index quality, slower builds (64-200 for quality)
|
|
284
|
-
|
|
285
|
-
### Flat Index (No Index)
|
|
286
|
-
|
|
287
|
-
Uses sequential scan for 100% accuracy:
|
|
288
|
-
|
|
289
|
-
```typescript
|
|
290
|
-
await vectorStore.createIndex({
|
|
291
|
-
indexName: 'my_vectors',
|
|
292
|
-
dimension: 1536,
|
|
293
|
-
metric: 'cosine',
|
|
294
|
-
indexConfig: {
|
|
295
|
-
type: 'flat',
|
|
296
|
-
},
|
|
297
|
-
});
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
- **Best for:** Small datasets (<1000 vectors) or when 100% accuracy is required
|
|
301
|
-
- **Build time:** None
|
|
302
|
-
- **Query speed:** Slow for large datasets (linear scan)
|
|
303
|
-
- **Memory:** Minimal (just vectors)
|
|
304
|
-
- **Accuracy:** 100%
|
|
305
|
-
|
|
306
|
-
### Distance Metrics
|
|
307
|
-
|
|
308
|
-
Choose the appropriate metric for your embeddings:
|
|
309
|
-
|
|
310
|
-
- **`cosine`** (default): Angular similarity, good for text embeddings
|
|
311
|
-
- **`euclidean`**: L2 distance, for unnormalized embeddings
|
|
312
|
-
- **`dotproduct`**: Dot product, optimal for normalized embeddings (OpenAI, Cohere)
|
|
313
|
-
|
|
314
|
-
### Index Recreation
|
|
315
|
-
|
|
316
|
-
The system automatically detects configuration changes and only rebuilds indexes when necessary, preventing the performance issues from unnecessary recreations.
|
|
317
|
-
|
|
318
|
-
**Important behaviors:**
|
|
319
|
-
|
|
320
|
-
- If no `indexConfig` is provided, existing indexes are preserved as-is
|
|
321
|
-
- If `indexConfig` is provided, indexes are only rebuilt if the configuration differs
|
|
322
|
-
- New indexes default to IVFFlat with cosine distance when no config is specified
|
|
323
|
-
|
|
324
|
-
## Vector Store Methods
|
|
325
|
-
|
|
326
|
-
- `createIndex({indexName, dimension, metric?, indexConfig?, buildIndex?})`: Create a new table with vector support
|
|
327
|
-
- `buildIndex({indexName, metric?, indexConfig?})`: Build or rebuild vector index
|
|
328
|
-
- `upsert({indexName, vectors, metadata?, ids?})`: Add or update vectors
|
|
329
|
-
- `query({indexName, queryVector, topK?, filter?, includeVector?, minScore?})`: Search for similar vectors
|
|
330
|
-
- `updateVector({ indexName, id?, filter?, update })`: Update a single vector by ID or metadata filter
|
|
331
|
-
- `deleteVector({ indexName, id })`: Delete a single vector by ID
|
|
332
|
-
- `deleteVectors({ indexName, ids?, filter? })`: Delete multiple vectors by IDs or metadata filter
|
|
333
|
-
- `listIndexes()`: List all vector-enabled tables
|
|
334
|
-
- `describeIndex(indexName)`: Get table statistics and index configuration
|
|
335
|
-
- `deleteIndex(indexName)`: Delete a table
|
|
336
|
-
- `truncateIndex(indexName)`: Remove all data from a table
|
|
337
|
-
- `disconnect()`: Close all database connections
|
|
338
|
-
|
|
339
|
-
## Storage Methods
|
|
340
|
-
|
|
341
|
-
### Thread Operations
|
|
342
|
-
|
|
343
|
-
- `saveThread({ thread })`: Create or update a thread
|
|
344
|
-
- `getThreadById({ threadId })`: Get a thread by ID
|
|
345
|
-
- `updateThread({ id, title, metadata })`: Update thread title and/or metadata
|
|
346
|
-
- `deleteThread({ threadId })`: Delete a thread and its messages
|
|
347
|
-
- `listThreadsByResourceId({ resourceId, offset, limit, orderBy? })`: List paginated threads for a resource
|
|
348
|
-
|
|
349
|
-
### Message Operations
|
|
350
|
-
|
|
351
|
-
- `saveMessages({ messages })`: Save multiple messages in a transaction
|
|
352
|
-
- `listMessages({ threadId, resourceId?, perPage?, page?, orderBy?, filter? })`: Get messages for a thread with pagination
|
|
353
|
-
- `listMessagesById({ messageIds })`: Get specific messages by their IDs
|
|
354
|
-
- `updateMessages({ messages })`: Update existing messages
|
|
355
|
-
- `deleteMessages(messageIds)`: Delete specific messages
|
|
356
|
-
|
|
357
|
-
### Resource Operations
|
|
358
|
-
|
|
359
|
-
- `getResourceById({ resourceId })`: Get a resource by ID
|
|
360
|
-
- `saveResource({ resource })`: Create or save a resource
|
|
361
|
-
- `updateResource({ resourceId, workingMemory })`: Update resource working memory
|
|
362
|
-
|
|
363
|
-
### Workflow Operations
|
|
364
|
-
|
|
365
|
-
- `persistWorkflowSnapshot({ workflowName, runId, snapshot })`: Save workflow state
|
|
366
|
-
- `loadWorkflowSnapshot({ workflowName, runId })`: Load workflow state
|
|
367
|
-
- `listWorkflowRuns({ workflowName, pagination })`: List workflow runs with pagination
|
|
368
|
-
- `getWorkflowRunById({ workflowName, runId })`: Get a specific workflow run
|
|
369
|
-
- `updateWorkflowState({ workflowName, runId, state })`: Update workflow state
|
|
370
|
-
- `updateWorkflowResults({ workflowName, runId, results })`: Update workflow results
|
|
371
|
-
|
|
372
|
-
### AI Observability Operations
|
|
373
|
-
|
|
374
|
-
- `createSpan(span)`: Create a single AI span
|
|
375
|
-
- `batchCreateSpans({ records })`: Create multiple AI spans
|
|
376
|
-
- `updateSpan({ traceId, spanId, updates })`: Update an AI span
|
|
377
|
-
- `batchUpdateSpans({ updates })`: Update multiple AI spans
|
|
378
|
-
- `getTrace(traceId)`: Get an trace by ID
|
|
379
|
-
- `getTracesPaginated({ ...filters, pagination })`: Get paginated traces with filtering
|
|
380
|
-
- `batchDeleteTraces({ traceIds })`: Delete multiple traces
|
|
29
|
+
## Documentation
|
|
381
30
|
|
|
382
|
-
|
|
31
|
+
- [@mastra/pg documentation](https://mastra.ai/reference/vectors/pg)
|
|
383
32
|
|
|
384
|
-
|
|
385
|
-
- `saveScore(score)`: Save an evaluation score
|
|
386
|
-
- `listScoresByScorerId({ scorerId, pagination })`: List scores by scorer with pagination
|
|
387
|
-
- `listScoresByRunId({ runId, pagination })`: List scores by run with pagination
|
|
388
|
-
- `listScoresByEntityId({ entityId, entityType, pagination })`: List scores by entity with pagination
|
|
389
|
-
- `listScoresBySpan({ traceId, spanId, pagination })`: List scores by span with pagination
|
|
33
|
+
## Changelog
|
|
390
34
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
The PostgreSQL store provides comprehensive index management capabilities to optimize query performance.
|
|
394
|
-
|
|
395
|
-
### Automatic Performance Indexes
|
|
396
|
-
|
|
397
|
-
PostgreSQL storage automatically creates composite indexes during initialization for common query patterns:
|
|
398
|
-
|
|
399
|
-
- `mastra_threads_resourceid_createdat_idx`: (resourceId, createdAt DESC)
|
|
400
|
-
- `mastra_messages_thread_id_createdat_idx`: (thread_id, createdAt DESC)
|
|
401
|
-
- `mastra_traces_name_starttime_idx`: (name, startTime DESC)
|
|
402
|
-
- `mastra_evals_agent_name_created_at_idx`: (agent_name, created_at DESC)
|
|
403
|
-
|
|
404
|
-
These indexes significantly improve performance for filtered queries with sorting.
|
|
405
|
-
|
|
406
|
-
### Creating Custom Indexes
|
|
407
|
-
|
|
408
|
-
Create additional indexes to optimize specific query patterns:
|
|
409
|
-
|
|
410
|
-
```typescript
|
|
411
|
-
// Basic index for common queries
|
|
412
|
-
await store.createIndex({
|
|
413
|
-
name: 'idx_threads_resource',
|
|
414
|
-
table: 'mastra_threads',
|
|
415
|
-
columns: ['resourceId'],
|
|
416
|
-
});
|
|
417
|
-
|
|
418
|
-
// Composite index with sort order for filtering + sorting
|
|
419
|
-
await store.createIndex({
|
|
420
|
-
name: 'idx_messages_composite',
|
|
421
|
-
table: 'mastra_messages',
|
|
422
|
-
columns: ['thread_id', 'createdAt DESC'],
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
// GIN index for JSONB columns (fast JSON queries)
|
|
426
|
-
await store.createIndex({
|
|
427
|
-
name: 'idx_traces_attributes',
|
|
428
|
-
table: 'mastra_traces',
|
|
429
|
-
columns: ['attributes'],
|
|
430
|
-
method: 'gin',
|
|
431
|
-
});
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
For more advanced use cases, you can also use:
|
|
435
|
-
|
|
436
|
-
- `unique: true` for unique constraints
|
|
437
|
-
- `where: 'condition'` for partial indexes
|
|
438
|
-
- `method: 'brin'` for time-series data
|
|
439
|
-
- `storage: { fillfactor: 90 }` for update-heavy tables
|
|
440
|
-
- `concurrent: true` for non-blocking creation (default)
|
|
441
|
-
|
|
442
|
-
### Managing Indexes
|
|
443
|
-
|
|
444
|
-
```typescript
|
|
445
|
-
// List all indexes
|
|
446
|
-
const allIndexes = await store.listIndexes();
|
|
447
|
-
|
|
448
|
-
// List indexes for specific table
|
|
449
|
-
const threadIndexes = await store.listIndexes('mastra_threads');
|
|
450
|
-
|
|
451
|
-
// Get detailed statistics for an index
|
|
452
|
-
const stats = await store.describeIndex('idx_threads_resource');
|
|
453
|
-
console.log(stats);
|
|
454
|
-
// {
|
|
455
|
-
// name: 'idx_threads_resource',
|
|
456
|
-
// table: 'mastra_threads',
|
|
457
|
-
// columns: ['resourceId', 'createdAt'],
|
|
458
|
-
// unique: false,
|
|
459
|
-
// size: '128 KB',
|
|
460
|
-
// definition: 'CREATE INDEX idx_threads_resource...',
|
|
461
|
-
// method: 'btree',
|
|
462
|
-
// scans: 1542, // Number of index scans
|
|
463
|
-
// tuples_read: 45230, // Tuples read via index
|
|
464
|
-
// tuples_fetched: 12050 // Tuples fetched via index
|
|
465
|
-
// }
|
|
466
|
-
|
|
467
|
-
// Drop an index
|
|
468
|
-
await store.dropIndex('idx_threads_status');
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
### Index Types and Use Cases
|
|
472
|
-
|
|
473
|
-
| Index Type | Best For | Storage | Speed |
|
|
474
|
-
| ------------------- | --------------------------------------- | ---------- | -------------------------- |
|
|
475
|
-
| **btree** (default) | Range queries, sorting, general purpose | Moderate | Fast |
|
|
476
|
-
| **hash** | Equality comparisons only | Small | Very fast for `=` |
|
|
477
|
-
| **gin** | JSONB, arrays, full-text search | Large | Fast for contains |
|
|
478
|
-
| **gist** | Geometric data, full-text search | Moderate | Fast for nearest-neighbor |
|
|
479
|
-
| **spgist** | Non-balanced data, text patterns | Small | Fast for specific patterns |
|
|
480
|
-
| **brin** | Large tables with natural ordering | Very small | Fast for ranges |
|
|
481
|
-
|
|
482
|
-
### Index Options
|
|
483
|
-
|
|
484
|
-
- `name` (required): Index name
|
|
485
|
-
- `table` (required): Table name
|
|
486
|
-
- `columns` (required): Array of column names (can include DESC/ASC)
|
|
487
|
-
- `unique`: Create unique index (default: false)
|
|
488
|
-
- `concurrent`: Non-blocking index creation (default: true)
|
|
489
|
-
- `where`: Partial index condition
|
|
490
|
-
- `method`: Index type ('btree' | 'hash' | 'gin' | 'gist' | 'spgist' | 'brin')
|
|
491
|
-
- `opclass`: Operator class for GIN/GIST indexes
|
|
492
|
-
- `storage`: Storage parameters (e.g., { fillfactor: 90 })
|
|
493
|
-
- `tablespace`: Tablespace name for index placement
|
|
494
|
-
|
|
495
|
-
### Monitoring Index Performance
|
|
496
|
-
|
|
497
|
-
```typescript
|
|
498
|
-
// Check index usage statistics
|
|
499
|
-
const stats = await store.describeIndex('idx_threads_resource');
|
|
500
|
-
|
|
501
|
-
// Identify unused indexes
|
|
502
|
-
if (stats.scans === 0) {
|
|
503
|
-
console.log(`Index ${stats.name} is unused - consider removing`);
|
|
504
|
-
await store.dropIndex(stats.name);
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
// Monitor index efficiency
|
|
508
|
-
const efficiency = stats.tuples_fetched / stats.tuples_read;
|
|
509
|
-
if (efficiency < 0.5) {
|
|
510
|
-
console.log(`Index ${stats.name} has low efficiency: ${efficiency}`);
|
|
511
|
-
}
|
|
512
|
-
```
|
|
35
|
+
See the [package changelog](https://github.com/mastra-ai/mastra/blob/main/stores/pg/CHANGELOG.md) for version history and release notes.
|
|
513
36
|
|
|
514
|
-
##
|
|
37
|
+
## Support
|
|
515
38
|
|
|
516
|
-
|
|
517
|
-
- [PostgreSQL Documentation](https://www.postgresql.org/docs/)
|
|
39
|
+
We have an [open community Discord](https://discord.gg/mastra-ai). Come and say hello and let us know if you have any questions or need any help getting things running.
|
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -818,19 +818,18 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
818
818
|
}
|
|
819
819
|
async ensureNamespaceSchema(indexName, client) {
|
|
820
820
|
const { tableName, parsedIndexName } = this.getTableName(indexName);
|
|
821
|
-
const schemaName = this.schema ? (0, _mastra_core_utils.parseSqlIdentifier)(this.schema, "schema name") : "public";
|
|
822
821
|
if ((await client.query(`SELECT 1
|
|
823
|
-
FROM
|
|
824
|
-
WHERE
|
|
822
|
+
FROM pg_attribute
|
|
823
|
+
WHERE attrelid = to_regclass($1)
|
|
824
|
+
AND attname = 'vector_id'
|
|
825
|
+
AND attnum > 0
|
|
826
|
+
AND NOT attisdropped`, [tableName])).rowCount === 0) return;
|
|
825
827
|
await client.query(`ALTER TABLE ${tableName} ADD COLUMN IF NOT EXISTS namespace VARCHAR(255) NOT NULL DEFAULT '${DEFAULT_NAMESPACE}'`);
|
|
826
828
|
const legacyConstraints = await client.query(`SELECT c.conname
|
|
827
829
|
FROM pg_constraint c
|
|
828
|
-
|
|
829
|
-
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
830
|
-
WHERE n.nspname = $1
|
|
831
|
-
AND t.relname = $2
|
|
830
|
+
WHERE c.conrelid = to_regclass($1)
|
|
832
831
|
AND c.contype = 'u'
|
|
833
|
-
AND pg_get_constraintdef(c.oid) = 'UNIQUE (vector_id)'`, [
|
|
832
|
+
AND pg_get_constraintdef(c.oid) = 'UNIQUE (vector_id)'`, [tableName]);
|
|
834
833
|
for (const { conname } of legacyConstraints.rows) {
|
|
835
834
|
const parsedConstraintName = (0, _mastra_core_utils.parseSqlIdentifier)(conname, "constraint name");
|
|
836
835
|
await client.query(`ALTER TABLE ${tableName} DROP CONSTRAINT "${parsedConstraintName}"`);
|
|
@@ -1468,7 +1467,9 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1468
1467
|
return (await client.query(`
|
|
1469
1468
|
SELECT DISTINCT t.table_name
|
|
1470
1469
|
FROM information_schema.tables t
|
|
1471
|
-
WHERE t.table_schema =
|
|
1470
|
+
WHERE t.table_schema = ANY(
|
|
1471
|
+
CASE WHEN $1::text IS NULL THEN current_schemas(false) ELSE ARRAY[$1::text] END
|
|
1472
|
+
)
|
|
1472
1473
|
AND EXISTS (
|
|
1473
1474
|
SELECT 1
|
|
1474
1475
|
FROM information_schema.columns c
|
|
@@ -1493,7 +1494,7 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1493
1494
|
AND c.column_name = 'metadata'
|
|
1494
1495
|
AND c.data_type = 'jsonb'
|
|
1495
1496
|
);
|
|
1496
|
-
`, [this.schema
|
|
1497
|
+
`, [this.schema ?? null])).rows.map((row) => row.table_name);
|
|
1497
1498
|
} catch (e) {
|
|
1498
1499
|
const mastraError = new _mastra_core_error.MastraError({
|
|
1499
1500
|
id: (0, _mastra_core_storage.createVectorErrorId)("PG", "LIST_INDEXES", "FAILED"),
|
|
@@ -1528,15 +1529,18 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1528
1529
|
async describeIndexMetadata({ indexName }) {
|
|
1529
1530
|
const client = await this.pool.connect();
|
|
1530
1531
|
try {
|
|
1531
|
-
const { tableName } = this.getTableName(indexName);
|
|
1532
|
+
const { tableName, parsedIndexName } = this.getTableName(indexName);
|
|
1532
1533
|
const tableExists = await client.query(`
|
|
1533
|
-
SELECT udt_name
|
|
1534
|
-
FROM
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
AND
|
|
1534
|
+
SELECT t.typname AS udt_name
|
|
1535
|
+
FROM pg_attribute a
|
|
1536
|
+
JOIN pg_type t ON t.oid = a.atttypid
|
|
1537
|
+
WHERE a.attrelid = to_regclass($1)
|
|
1538
|
+
AND a.attname = 'embedding'
|
|
1539
|
+
AND a.attnum > 0
|
|
1540
|
+
AND NOT a.attisdropped
|
|
1541
|
+
AND t.typname IN ('vector', 'halfvec', 'bit', 'sparsevec')
|
|
1538
1542
|
LIMIT 1;
|
|
1539
|
-
`, [
|
|
1543
|
+
`, [tableName]);
|
|
1540
1544
|
if (tableExists.rows.length === 0) throw new Error(`Vector table ${tableName} does not exist`);
|
|
1541
1545
|
const udtName = tableExists.rows[0].udt_name;
|
|
1542
1546
|
const vectorType = udtName === "halfvec" ? "halfvec" : udtName === "bit" ? "bit" : udtName === "sparsevec" ? "sparsevec" : "vector";
|
|
@@ -1555,12 +1559,11 @@ var PgVector = class extends _mastra_core_vector.MastraVector {
|
|
|
1555
1559
|
JOIN pg_class c ON i.indexrelid = c.oid
|
|
1556
1560
|
JOIN pg_am am ON c.relam = am.oid
|
|
1557
1561
|
JOIN pg_opclass opclass ON i.indclass[0] = opclass.oid
|
|
1558
|
-
JOIN pg_namespace n ON c.relnamespace = n.oid
|
|
1559
1562
|
WHERE c.relname = $1
|
|
1560
|
-
AND
|
|
1563
|
+
AND i.indrelid = to_regclass($2);
|
|
1561
1564
|
`;
|
|
1562
1565
|
const dimResult = await client.query(dimensionQuery, [tableName]);
|
|
1563
|
-
const { index_method, index_def, operator_class } = (await client.query(indexQuery, [`${
|
|
1566
|
+
const { index_method, index_def, operator_class } = (await client.query(indexQuery, [`${parsedIndexName}_vector_idx`, tableName])).rows[0] || {
|
|
1564
1567
|
index_method: "flat",
|
|
1565
1568
|
index_def: "",
|
|
1566
1569
|
operator_class: "cosine"
|
|
@@ -4498,6 +4501,25 @@ var AgentsPG = class AgentsPG extends _mastra_core_storage.AgentsStorage {
|
|
|
4498
4501
|
}, error);
|
|
4499
4502
|
}
|
|
4500
4503
|
}
|
|
4504
|
+
async getVersions(ids) {
|
|
4505
|
+
if (ids.length === 0) return [];
|
|
4506
|
+
try {
|
|
4507
|
+
const tableName = getTableName$5({
|
|
4508
|
+
indexName: _mastra_core_storage.TABLE_AGENT_VERSIONS,
|
|
4509
|
+
schemaName: getSchemaName$5(this.#schema)
|
|
4510
|
+
});
|
|
4511
|
+
const placeholders = ids.map((_, i) => `$${i + 1}`).join(", ");
|
|
4512
|
+
return (await this.#db.client.manyOrNone(`SELECT * FROM ${tableName} WHERE id IN (${placeholders})`, ids)).map((row) => this.parseVersionRow(row));
|
|
4513
|
+
} catch (error) {
|
|
4514
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
4515
|
+
throw new _mastra_core_error.MastraError({
|
|
4516
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "GET_VERSIONS", "FAILED"),
|
|
4517
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
4518
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
4519
|
+
details: { count: ids.length }
|
|
4520
|
+
}, error);
|
|
4521
|
+
}
|
|
4522
|
+
}
|
|
4501
4523
|
async getVersionByNumber(agentId, versionNumber) {
|
|
4502
4524
|
try {
|
|
4503
4525
|
const tableName = getTableName$5({
|
|
@@ -20122,6 +20144,25 @@ var SkillsPG = class SkillsPG extends _mastra_core_storage.SkillsStorage {
|
|
|
20122
20144
|
}, error);
|
|
20123
20145
|
}
|
|
20124
20146
|
}
|
|
20147
|
+
async getVersions(ids) {
|
|
20148
|
+
if (ids.length === 0) return [];
|
|
20149
|
+
try {
|
|
20150
|
+
const tableName = getTableName$5({
|
|
20151
|
+
indexName: _mastra_core_storage.TABLE_SKILL_VERSIONS,
|
|
20152
|
+
schemaName: getSchemaName$5(this.#schema)
|
|
20153
|
+
});
|
|
20154
|
+
const placeholders = ids.map((_, i) => `$${i + 1}`).join(", ");
|
|
20155
|
+
return (await this.#db.client.manyOrNone(`SELECT * FROM ${tableName} WHERE id IN (${placeholders})`, ids)).map((row) => this.parseVersionRow(row));
|
|
20156
|
+
} catch (error) {
|
|
20157
|
+
if (error instanceof _mastra_core_error.MastraError) throw error;
|
|
20158
|
+
throw new _mastra_core_error.MastraError({
|
|
20159
|
+
id: (0, _mastra_core_storage.createStorageErrorId)("PG", "GET_SKILL_VERSIONS", "FAILED"),
|
|
20160
|
+
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
20161
|
+
category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
|
|
20162
|
+
details: { count: ids.length }
|
|
20163
|
+
}, error);
|
|
20164
|
+
}
|
|
20165
|
+
}
|
|
20125
20166
|
async getVersionByNumber(skillId, versionNumber) {
|
|
20126
20167
|
try {
|
|
20127
20168
|
const tableName = getTableName$5({
|