@mastra/libsql 1.23.0 → 1.23.1-alpha.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/docs/SKILL.md +1 -1
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/docs-memory-message-history.md +21 -0
- package/dist/docs/references/reference-core-mastra-class.md +1 -1
- package/dist/docs/references/reference-memory-memory-class.md +2 -0
- package/dist/docs/references/reference-storage-retention.md +56 -4
- package/dist/index.cjs +30 -134
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +31 -135
- package/dist/index.js.map +1 -1
- package/dist/storage/factory-storage.d.ts.map +1 -1
- package/dist/storage/retention.d.ts +5 -56
- package/dist/storage/retention.d.ts.map +1 -1
- package/package.json +6 -6
package/dist/docs/SKILL.md
CHANGED
|
@@ -124,6 +124,27 @@ You can use this history in two ways:
|
|
|
124
124
|
|
|
125
125
|
> **Note:** `lastMessages` counts every stored message, including tool calls, tool results, and [signals](https://mastra.ai/docs/harness/signals) of any kind, so a single turn can add several messages to the count. The window also slides forward on every request: once a thread grows past the limit, the oldest message leaves context on each turn, which changes the start of the prompt and invalidates the provider prompt cache. For long-running conversations, use [Observational Memory](https://mastra.ai/docs/memory/observational-memory), which keeps the prompt prefix stable.
|
|
126
126
|
|
|
127
|
+
### Limit history by tokens
|
|
128
|
+
|
|
129
|
+
Message count is a poor proxy for context size: a tool result can be a few tokens or thousands. Use `messageHistory` to keep recent history within a token budget instead:
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
export const agent = new Agent({
|
|
133
|
+
id: 'test-agent',
|
|
134
|
+
memory: new Memory({
|
|
135
|
+
options: {
|
|
136
|
+
messageHistory: { maxTokens: 8_000, atMaxRemoveTokens: 2_000 },
|
|
137
|
+
},
|
|
138
|
+
}),
|
|
139
|
+
})
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Mastra counts the complete prompt against `maxTokens`, including remembered history, system instructions, context, and the current turn. When the prompt exceeds the budget, Mastra removes the oldest remembered messages until the prompt is at most `maxTokens - atMaxRemoveTokens`. `atMaxRemoveTokens` defaults to 25% of `maxTokens`. Removing history in chunks keeps the prompt prefix stable across several turns, which helps provider prompt caches stay warm.
|
|
143
|
+
|
|
144
|
+
System messages, context, the current turn's input, and the agent's responses are never trimmed. Linked tool calls and results are removed together. If protected content alone exceeds `maxTokens`, Mastra removes all remembered history but keeps the protected content.
|
|
145
|
+
|
|
146
|
+
Trimmed messages stay in storage. During agent runs, Mastra persists a per-thread boundary so they're excluded from later turns. Setting `messageHistory` without `lastMessages` disables the default 10-message cap. Set both to combine a count cap with a token budget. Set `maxTokens` to `0` to disable message history.
|
|
147
|
+
|
|
127
148
|
> **Tip:** When memory is enabled, [Studio](https://mastra.ai/docs/studio/overview) uses message history to display past conversations in the chat sidebar.
|
|
128
149
|
|
|
129
150
|
## Thread title generation
|
|
@@ -131,7 +131,7 @@ Visit the [Configuration reference](https://mastra.ai/reference/configuration) f
|
|
|
131
131
|
|
|
132
132
|
**recovery** (`MastraRecoveryConfig`): Boot-time recovery behavior for orphaned agent and workflow runs. See Crash recovery. (Default: `{ durableAgents: 'off' }`)
|
|
133
133
|
|
|
134
|
-
**recovery.durableAgents** (`'auto' | 'off'`): Set to 'auto' to automatically re-drive orphaned RUNNING durable agent runs on server boot. Recovery re-issues LLM calls and re-executes tool calls, so tools must be idempotent. See Crash recovery.
|
|
134
|
+
**recovery.durableAgents** (`'auto' | 'off'`): Set to 'auto' to automatically re-drive orphaned RUNNING durable agent runs on server boot. This also controls the default snapshot-persistence policy for durable agents: running checkpoints are only written when set to 'auto' (or when an agent sets a custom shouldPersistSnapshot that includes running). Recovery re-issues LLM calls and re-executes tool calls, so tools must be idempotent. See Crash recovery.
|
|
135
135
|
|
|
136
136
|
## Methods
|
|
137
137
|
|
|
@@ -41,6 +41,8 @@ export const agent = new Agent({
|
|
|
41
41
|
|
|
42
42
|
**options.lastMessages** (`number | false`): Number of most recent messages to include in context. Set to false to disable the message history feature entirely (messages are not loaded into context or saved). Use Number.MAX\_SAFE\_INTEGER to retrieve all messages with no limit. To load messages without saving new ones, use the readOnly option. The window slides forward on every request, so once a thread exceeds the limit, each turn invalidates the provider prompt cache. For long-running conversations, use Observational Memory instead.
|
|
43
43
|
|
|
44
|
+
**options.messageHistory** (`{ maxTokens: number; atMaxRemoveTokens?: number }`): Token budget for the complete prompt, including remembered history, system instructions, context, and the current turn. When the prompt exceeds maxTokens, the oldest remembered messages are dropped until the prompt is at most maxTokens - atMaxRemoveTokens (defaults to 25% of maxTokens). Protected content is never removed. Linked tool calls and results are removed together. During agent runs, trimmed history is excluded from later turns via a persisted per-thread boundary, but the messages themselves stay in storage. When set without an explicit lastMessages, the default 10-message cap is not applied. Set maxTokens to 0 to disable message history. Prefer this over lastMessages, since message count is a poor proxy for context size.
|
|
45
|
+
|
|
44
46
|
**options.readOnly** (`boolean`): When true, prevents memory from saving new messages and provides working memory as read-only context (without the updateWorkingMemory tool). Useful for read-only operations like previews, internal routing agents, or sub agents that should reference but not modify memory.
|
|
45
47
|
|
|
46
48
|
**options.semanticRecall** (`boolean | { topK: number; messageRange: number | { before: number; after: number }; scope?: 'thread' | 'resource' }`): Enable semantic search in message history. Can be a boolean or an object with configuration options. When enabled, requires both vector store and embedder to be configured. Default topK is 4, default messageRange is {before: 1, after: 1}.
|
|
@@ -6,11 +6,37 @@
|
|
|
6
6
|
|
|
7
7
|
Because storage grows without bound by default, Mastra provides an opt-in, age-based retention system. Declare per-table `maxAge` policies in the `retention` config, then call `storage.prune()` to delete rows older than their configured age. Unconfigured data is kept forever, so behavior doesn't change until you opt in.
|
|
8
8
|
|
|
9
|
-
`prune()` deletes rows.
|
|
9
|
+
`prune()` deletes rows in bounded batches. Runs are resumable and cancellable, so you can limit how much work each maintenance window performs. Pruning doesn't reclaim disk space by itself. Use the database-specific maintenance guidance below when you need to return freed space to the operating system.
|
|
10
10
|
|
|
11
11
|
Retention covers **growth tables** only: tables that accumulate rows unbounded as a side effect of normal operation (conversation history, telemetry, job and run records, schedule fire history, event feeds). User-authored artifacts and config (agents, skills, workspaces, prompt blocks, datasets, schedule definitions, channel installations, and so on) grow with user intent and are edited or deleted explicitly, so they're not valid retention keys.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Storage adapters use the shared core retention contract for `prune()`, or a database-native mechanism when that better matches the backend.
|
|
14
|
+
|
|
15
|
+
| Adapter | Mechanism | Retention support |
|
|
16
|
+
| -------------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
17
|
+
| libSQL | `prune()` | All supported growth domains |
|
|
18
|
+
| PostgreSQL | `prune()` | All supported growth domains. V-next observability drops expired partitions or chunks |
|
|
19
|
+
| MongoDB | `prune()` or native TTL | All supported growth domains. Native TTL indexes are also available |
|
|
20
|
+
| DuckDB | `prune()` | Observability spans, metrics, logs, scores, and feedback |
|
|
21
|
+
| MySQL | `prune()` | Observability spans |
|
|
22
|
+
| Microsoft SQL Server | `prune()` | Observability spans |
|
|
23
|
+
| Oracle Database | `prune()` | Observability spans and logs |
|
|
24
|
+
| Amazon Aurora DSQL | `prune()` | Observability spans |
|
|
25
|
+
| Google Cloud Spanner | `prune()` | Observability spans, plus metrics when metrics storage is enabled |
|
|
26
|
+
| ClickHouse | Native TTL | Observability spans, metrics, logs, scores, and feedback. When all five signals have finite retention, deletion-request records expire after the longest signal retention plus 30 days |
|
|
27
|
+
|
|
28
|
+
## Storage-specific maintenance
|
|
29
|
+
|
|
30
|
+
| Adapter | Maintenance guidance |
|
|
31
|
+
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
32
|
+
| SQLite and libSQL | Freed pages are reused by future writes, which stops the database file from growing. Reclaiming disk space requires database-level maintenance. |
|
|
33
|
+
| DuckDB | For file-backed stores, run `CHECKPOINT` after pruning to reclaim deleted rows in storage. DuckDB's `VACUUM` doesn't reclaim deleted rows. |
|
|
34
|
+
|
|
35
|
+
## Schedule pruning
|
|
36
|
+
|
|
37
|
+
Run `prune()` from a scheduler or maintenance worker, not from application startup or shutdown hooks. For deployments that share a database, prefer a single active scheduler or worker for pruning.
|
|
38
|
+
|
|
39
|
+
Prefer lower-traffic periods when pruning large tables. Use `maxBatches`, `maxRows`, and `pauseMs` to bound each run, and pass an `AbortSignal` when the maintenance process needs to stop promptly. These recommendations apply to adapters that expose `prune()`. ClickHouse applies its native time to live (TTL) policy within the database.
|
|
14
40
|
|
|
15
41
|
## Usage example
|
|
16
42
|
|
|
@@ -94,7 +120,8 @@ Each domain specifies its age-prunable tables and the timestamp column that anch
|
|
|
94
120
|
> - Experiments prune as whole units: an aged experiment's result rows are deleted together with it (results cascade with their parent), so a run is never left partially deleted. Retention doesn't have a separate `results` key.
|
|
95
121
|
> - For `schedules`, the growth table is the fire history (`schedule_triggers`, one row per fire): schedule definitions are config and aren't pruned.
|
|
96
122
|
> - On PostgreSQL, timestamp anchors use the timezone-aware mirror columns (for example `createdAtZ`, `completedAtZ`).
|
|
97
|
-
> -
|
|
123
|
+
> - DuckDB observability stores append-only events for all five signals. Its `spans` policy uses the event `timestamp` column rather than `startedAt`.
|
|
124
|
+
> - LibSQL and PostgreSQL support all domains above except `harness`, which PostgreSQL doesn't implement. MongoDB supports all except `threadState` and `harness`. DuckDB, MySQL, Microsoft SQL Server, Oracle Database, Amazon Aurora DSQL, and Google Cloud Spanner currently support retention only in their `observability` domains, with the signal coverage shown in the support matrix.
|
|
98
125
|
> - The v-next PostgreSQL observability domain stores signal events in day-partitioned tables (`spans`, `metrics`, `logs`, `scores`, `feedback`). For it, `prune()` drops whole day partitions (or TimescaleDB chunks) that are entirely older than the cutoff instead of deleting rows: effective level of detail is one day, and a partition is only dropped once its entire day is past `maxAge`. `PruneResult.deleted` reports the number of rows in the dropped partitions.
|
|
99
126
|
|
|
100
127
|
## Methods
|
|
@@ -109,7 +136,7 @@ Deletes rows older than their configured `maxAge` across every domain that has a
|
|
|
109
136
|
|
|
110
137
|
Pass `options.retention` to replace the configured policies for that call only: for example to skip a domain (keep chat history) or prune more aggressively than the standing config. The store's configured `retention` is unchanged.
|
|
111
138
|
|
|
112
|
-
|
|
139
|
+
Adapters that use anchor-column indexes create them lazily on the first `prune()` call for each table with a policy (never at `init()`) so deployments that don't configure retention pay no extra index write or disk overhead. The first prune of an existing large table pays a one-time index build. Subsequent prunes reuse the index. DuckDB uses its built-in zone maps instead of creating retention indexes.
|
|
113
140
|
|
|
114
141
|
```typescript
|
|
115
142
|
const results = await storage.prune({
|
|
@@ -177,6 +204,31 @@ async function retentionTick() {
|
|
|
177
204
|
|
|
178
205
|
You can also cancel a long-running prune with an `AbortSignal`: the loop stops between batches and returns partial results with `done: false`, so the next run resumes cleanly.
|
|
179
206
|
|
|
207
|
+
## ClickHouse native TTL
|
|
208
|
+
|
|
209
|
+
ClickHouse observability storage uses native table TTLs instead of `prune()`. Configure retention as days per signal. `init()` applies the TTLs to new and existing tables and skips `ALTER TABLE` statements when the configured TTL is already present.
|
|
210
|
+
|
|
211
|
+
For deployments that need to update TTL configuration without running the full initialization path, call `applyRetention()` on the v-next observability store:
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
import { ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'
|
|
215
|
+
|
|
216
|
+
const observability = new ObservabilityStorageClickhouseVNext({
|
|
217
|
+
client,
|
|
218
|
+
retention: {
|
|
219
|
+
tracing: 30,
|
|
220
|
+
logs: 7,
|
|
221
|
+
metrics: 14,
|
|
222
|
+
scores: 90,
|
|
223
|
+
feedback: 60,
|
|
224
|
+
},
|
|
225
|
+
})
|
|
226
|
+
|
|
227
|
+
await observability.applyRetention()
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
Deletion requests are retained long enough to keep enforcing erasure after signal rows expire. Mastra applies a TTL to `mastra_deletion_requests` only when tracing, logs, metrics, scores, and feedback all have finite retention. The deletion-request TTL is the longest of those periods plus 30 days. For example, if score retention is the longest period at 90 days, deletion requests expire after 120 days. When any signal is unbounded, deletion requests remain unbounded because trace deletion requests cover rows across all five signals.
|
|
231
|
+
|
|
180
232
|
## MongoDB TTL indexes (alternative to prune)
|
|
181
233
|
|
|
182
234
|
MongoDB offers native [TTL (Time-To-Live) indexes](https://www.mongodb.com/docs/manual/core/index-ttl/) that automatically delete expired documents without requiring manual `prune()` calls. This is a database-level feature that runs as a background thread.
|
package/dist/index.cjs
CHANGED
|
@@ -2873,13 +2873,6 @@ var AgentsLibSQL = class extends _mastra_core_storage.AgentsStorage {
|
|
|
2873
2873
|
};
|
|
2874
2874
|
//#endregion
|
|
2875
2875
|
//#region src/storage/retention.ts
|
|
2876
|
-
const DEFAULT_BATCH_SIZE = 1e3;
|
|
2877
|
-
/**
|
|
2878
|
-
* Lazily create the single-column anchor index a prune target relies on.
|
|
2879
|
-
* Called from the prune path (not init) so only deployments that actually
|
|
2880
|
-
* configure retention pay the index's write/disk overhead. Best-effort: a
|
|
2881
|
-
* failure is logged and pruning proceeds (correct, just slower).
|
|
2882
|
-
*/
|
|
2883
2876
|
async function ensureAnchorIndex(db, target, logger) {
|
|
2884
2877
|
if (!target.indexed) return;
|
|
2885
2878
|
try {
|
|
@@ -2892,134 +2885,32 @@ async function ensureAnchorIndex(db, target, logger) {
|
|
|
2892
2885
|
logger?.warn?.(`Failed to ensure retention index on ${target.table}(${target.column}):`, error);
|
|
2893
2886
|
}
|
|
2894
2887
|
}
|
|
2895
|
-
async function sleep(ms, signal) {
|
|
2896
|
-
if (ms <= 0 || signal?.aborted) return;
|
|
2897
|
-
await new Promise((resolve) => {
|
|
2898
|
-
const timer = setTimeout(() => {
|
|
2899
|
-
signal?.removeEventListener("abort", onAbort);
|
|
2900
|
-
resolve();
|
|
2901
|
-
}, ms);
|
|
2902
|
-
const onAbort = () => {
|
|
2903
|
-
clearTimeout(timer);
|
|
2904
|
-
resolve();
|
|
2905
|
-
};
|
|
2906
|
-
signal?.addEventListener("abort", onAbort, { once: true });
|
|
2907
|
-
});
|
|
2908
|
-
}
|
|
2909
|
-
/**
|
|
2910
|
-
* Runs the bounded, batched, cancellable delete loop for a set of tables in the
|
|
2911
|
-
* given order (callers pass children before parents for cascade-safe pruning),
|
|
2912
|
-
* and returns one {@link PruneResult} per table.
|
|
2913
|
-
*
|
|
2914
|
-
* The loop:
|
|
2915
|
-
* - deletes in chunks of `batchSize` (default 1000), each its own statement;
|
|
2916
|
-
* - stops a table's loop when a batch deletes fewer rows than requested (drained),
|
|
2917
|
-
* or when `maxBatches`/`maxRows` is hit, or the `signal` aborts — the latter
|
|
2918
|
-
* three leave `done: false` so the caller can resume;
|
|
2919
|
-
* - pauses `pauseMs` between batches when set, to avoid starving live traffic.
|
|
2920
|
-
*
|
|
2921
|
-
* `prune()` only deletes rows; it never reclaims disk. Freed pages are reused
|
|
2922
|
-
* by future writes so the file stops growing. Handing disk back to the OS is
|
|
2923
|
-
* left to the underlying database and the operator to manage.
|
|
2924
|
-
*/
|
|
2925
|
-
/** Convert a policy's `maxAge` into a cutoff bound matching the anchor's storage type. */
|
|
2926
2888
|
function cutoffFor(policy, anchorType, now = Date.now()) {
|
|
2927
|
-
const cutoffMs =
|
|
2889
|
+
const cutoffMs = (0, _mastra_core_storage.retentionCutoffMs)(policy, now);
|
|
2928
2890
|
return anchorType === "epoch-ms" ? cutoffMs : new Date(cutoffMs).toISOString();
|
|
2929
2891
|
}
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
if (options?.maxBatches !== void 0 && batches >= options.maxBatches) return {
|
|
2946
|
-
deleted,
|
|
2947
|
-
done: false
|
|
2948
|
-
};
|
|
2949
|
-
let limit = batchSize;
|
|
2950
|
-
if (options?.maxRows !== void 0) {
|
|
2951
|
-
const remaining = options.maxRows - deleted;
|
|
2952
|
-
if (remaining <= 0) return {
|
|
2953
|
-
deleted,
|
|
2954
|
-
done: false
|
|
2955
|
-
};
|
|
2956
|
-
limit = Math.min(limit, remaining);
|
|
2957
|
-
}
|
|
2958
|
-
const affected = await deleteBatch(limit);
|
|
2959
|
-
deleted += affected;
|
|
2960
|
-
batches += 1;
|
|
2961
|
-
if (affected < limit) return {
|
|
2962
|
-
deleted,
|
|
2963
|
-
done: true
|
|
2964
|
-
};
|
|
2965
|
-
if (options?.pauseMs) await sleep(options.pauseMs, options.signal);
|
|
2966
|
-
}
|
|
2967
|
-
}
|
|
2968
|
-
async function runPrune({ db, domain, targets, options, logger }) {
|
|
2969
|
-
const results = [];
|
|
2970
|
-
const now = Date.now();
|
|
2971
|
-
for (const target of targets) {
|
|
2972
|
-
if (options?.signal?.aborted) {
|
|
2973
|
-
results.push({
|
|
2974
|
-
domain,
|
|
2975
|
-
table: target.table,
|
|
2976
|
-
deleted: 0,
|
|
2977
|
-
done: false
|
|
2978
|
-
});
|
|
2979
|
-
continue;
|
|
2980
|
-
}
|
|
2981
|
-
await ensureAnchorIndex(db, target, logger);
|
|
2982
|
-
const cutoff = cutoffFor(target.policy, target.anchorType, now);
|
|
2983
|
-
const { deleted, done } = await runBatchedDelete({
|
|
2984
|
-
deleteBatch: (limit) => db.pruneBatch({
|
|
2985
|
-
tableName: target.table,
|
|
2986
|
-
column: target.column,
|
|
2987
|
-
cutoff,
|
|
2988
|
-
limit
|
|
2989
|
-
}),
|
|
2990
|
-
batchSize: target.policy.batchSize ?? DEFAULT_BATCH_SIZE,
|
|
2991
|
-
options
|
|
2992
|
-
});
|
|
2993
|
-
results.push({
|
|
2994
|
-
domain,
|
|
2995
|
-
table: target.table,
|
|
2996
|
-
deleted,
|
|
2997
|
-
done
|
|
2998
|
-
});
|
|
2999
|
-
}
|
|
3000
|
-
return results;
|
|
2892
|
+
const runBatchedDelete = _mastra_core_storage.runRetentionBatches;
|
|
2893
|
+
function runPrune({ db, domain, targets, options, logger }) {
|
|
2894
|
+
return (0, _mastra_core_storage.executeRetentionPrune)({
|
|
2895
|
+
domain,
|
|
2896
|
+
targets,
|
|
2897
|
+
options,
|
|
2898
|
+
beforeTarget: (target) => ensureAnchorIndex(db, target, logger),
|
|
2899
|
+
cutoffFor: (target, now) => cutoffFor(target.policy, target.anchorType ?? "timestamp", now),
|
|
2900
|
+
deleteBatch: (target, cutoff, limit) => db.pruneBatch({
|
|
2901
|
+
tableName: target.table,
|
|
2902
|
+
column: target.column,
|
|
2903
|
+
cutoff,
|
|
2904
|
+
limit
|
|
2905
|
+
})
|
|
2906
|
+
});
|
|
3001
2907
|
}
|
|
3002
|
-
/**
|
|
3003
|
-
* Resolve a domain's `{ tableKey: policy }` map plus its descriptor into an
|
|
3004
|
-
* ordered list of {@link PruneTarget}s. `order` lists table keys children-first
|
|
3005
|
-
* so cascade-dependent rows are removed before their parents. Table keys not in
|
|
3006
|
-
* `policies` are skipped (unset = keep forever).
|
|
3007
|
-
*/
|
|
3008
2908
|
function resolveTargets({ policies, descriptor, order }) {
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
targets.push({
|
|
3015
|
-
table: entry.table,
|
|
3016
|
-
column: entry.column,
|
|
3017
|
-
anchorType: entry.anchorType ?? "timestamp",
|
|
3018
|
-
indexed: entry.indexed ?? true,
|
|
3019
|
-
policy
|
|
3020
|
-
});
|
|
3021
|
-
}
|
|
3022
|
-
return targets;
|
|
2909
|
+
return (0, _mastra_core_storage.resolveRetentionTargets)({
|
|
2910
|
+
policies,
|
|
2911
|
+
descriptor,
|
|
2912
|
+
order
|
|
2913
|
+
});
|
|
3023
2914
|
}
|
|
3024
2915
|
//#endregion
|
|
3025
2916
|
//#region src/storage/domains/background-tasks/index.ts
|
|
@@ -14408,10 +14299,15 @@ var LibSQLFactoryStorageOps = class {
|
|
|
14408
14299
|
const filter = this.#buildWhere(schema, where);
|
|
14409
14300
|
const sql = `UPDATE "${schema.name}" SET ${columns.map((c) => `"${c}" = ?`).join(", ")} WHERE ${filter.sql}`;
|
|
14410
14301
|
const args = [...columns.map((column) => this.#serialize(this.#column(schema, column), set[column])), ...filter.args];
|
|
14411
|
-
|
|
14412
|
-
|
|
14413
|
-
|
|
14414
|
-
|
|
14302
|
+
try {
|
|
14303
|
+
return (await this.#client.execute({
|
|
14304
|
+
sql,
|
|
14305
|
+
args
|
|
14306
|
+
})).rowsAffected;
|
|
14307
|
+
} catch (error) {
|
|
14308
|
+
if (isUniqueViolation(error)) throw new _mastra_core_storage.UniqueViolationError(collection, { cause: error });
|
|
14309
|
+
throw error;
|
|
14310
|
+
}
|
|
14415
14311
|
}
|
|
14416
14312
|
async updateMany(collection, where, set) {
|
|
14417
14313
|
return this.#withWriteLock(() => this.#updateMany(collection, where, set));
|