@mastra/clickhouse 1.2.3 → 1.3.0
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/CHANGELOG.md +34 -0
- package/dist/docs/SKILL.md +2 -2
- package/dist/docs/assets/SOURCE_MAP.json +1 -1
- package/dist/docs/references/reference-storage-composite.md +10 -10
- package/dist/index.cjs +201 -100
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +202 -101
- package/dist/index.js.map +1 -1
- package/dist/storage/db/index.d.ts +12 -0
- package/dist/storage/db/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts +2 -0
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/index.d.ts.map +1 -1
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# @mastra/clickhouse
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added `requestContext` column to the spans table. Request context data from tracing is now persisted alongside other span data. ([#14020](https://github.com/mastra-ai/mastra/pull/14020))
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. ([#14021](https://github.com/mastra-ai/mastra/pull/14021))
|
|
12
|
+
|
|
13
|
+
For example, calling `db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } })` will silently ignore `futureField` if it doesn't exist in the database table, rather than throwing. The same applies to `update` — unknown fields in the data payload are dropped before building the SQL statement.
|
|
14
|
+
|
|
15
|
+
- Fixed slow semantic recall in the libsql, Cloudflare D1, and ClickHouse storage adapters. Recall performance no longer degrades as threads grow larger. (Fixes #11702) ([#14022](https://github.com/mastra-ai/mastra/pull/14022))
|
|
16
|
+
|
|
17
|
+
- Updated dependencies [[`4f71b43`](https://github.com/mastra-ai/mastra/commit/4f71b436a4a6b8839842d8da47b57b84509af56c), [`a070277`](https://github.com/mastra-ai/mastra/commit/a07027766ce195ba74d0783116d894cbab25d44c), [`b628b91`](https://github.com/mastra-ai/mastra/commit/b628b9128b372c0f54214d902b07279f03443900), [`332c014`](https://github.com/mastra-ai/mastra/commit/332c014e076b81edf7fe45b58205882726415e90), [`6b63153`](https://github.com/mastra-ai/mastra/commit/6b63153878ea841c0f4ce632ba66bb33e57e9c1b), [`4246e34`](https://github.com/mastra-ai/mastra/commit/4246e34cec9c26636d0965942268e6d07c346671), [`b8837ee`](https://github.com/mastra-ai/mastra/commit/b8837ee77e2e84197609762bfabd8b3da326d30c), [`866cc2c`](https://github.com/mastra-ai/mastra/commit/866cc2cb1f0e3b314afab5194f69477fada745d1), [`5d950f7`](https://github.com/mastra-ai/mastra/commit/5d950f7bf426a215a1808f0abef7de5c8336ba1c), [`28c85b1`](https://github.com/mastra-ai/mastra/commit/28c85b184fc32b40f7f160483c982da6d388ecbd), [`e9a08fb`](https://github.com/mastra-ai/mastra/commit/e9a08fbef1ada7e50e961e2f54f55e8c10b4a45c), [`1d0a8a8`](https://github.com/mastra-ai/mastra/commit/1d0a8a8acf33203d5744fc429b090ad8598aa8ed), [`631ffd8`](https://github.com/mastra-ai/mastra/commit/631ffd82fed108648b448b28e6a90e38c5f53bf5), [`6bcbf8a`](https://github.com/mastra-ai/mastra/commit/6bcbf8a6774d5a53b21d61db8a45ce2593ca1616), [`aae2295`](https://github.com/mastra-ai/mastra/commit/aae2295838a2d329ad6640829e87934790ffe5b8), [`aa61f29`](https://github.com/mastra-ai/mastra/commit/aa61f29ff8095ce46a4ae16e46c4d8c79b2b685b), [`7ff3714`](https://github.com/mastra-ai/mastra/commit/7ff37148515439bb3be009a60e02c3e363299760), [`18c3a90`](https://github.com/mastra-ai/mastra/commit/18c3a90c9e48cf69500e308affeb8eba5860b2af), [`41d79a1`](https://github.com/mastra-ai/mastra/commit/41d79a14bd8cb6de1e2565fd0a04786bae2f211b), [`f35487b`](https://github.com/mastra-ai/mastra/commit/f35487bb2d46c636e22aa71d90025613ae38235a), [`6dc2192`](https://github.com/mastra-ai/mastra/commit/6dc21921aef0f0efab15cd0805fa3d18f277a76f), [`eeb3a3f`](https://github.com/mastra-ai/mastra/commit/eeb3a3f43aca10cf49479eed2a84b7d9ecea02ba), [`e673376`](https://github.com/mastra-ai/mastra/commit/e6733763ad1321aa7e5ae15096b9c2104f93b1f3), [`05f8d90`](https://github.com/mastra-ai/mastra/commit/05f8d9009290ce6aa03428b3add635268615db85), [`b2204c9`](https://github.com/mastra-ai/mastra/commit/b2204c98a42848bbfb6f0440f005dc2b6354f1cd), [`a1bf1e3`](https://github.com/mastra-ai/mastra/commit/a1bf1e385ed4c0ef6f11b56c5887442970d127f2), [`b6f647a`](https://github.com/mastra-ai/mastra/commit/b6f647ae2388e091f366581595feb957e37d5b40), [`0c57b8b`](https://github.com/mastra-ai/mastra/commit/0c57b8b0a69a97b5a4ae3f79be6c610f29f3cf7b), [`b081f27`](https://github.com/mastra-ai/mastra/commit/b081f272cf411716e1d6bd72ceac4bcee2657b19), [`4b8da97`](https://github.com/mastra-ai/mastra/commit/4b8da97a5ce306e97869df6c39535d9069e563db), [`0c09eac`](https://github.com/mastra-ai/mastra/commit/0c09eacb1926f64cfdc9ae5c6d63385cf8c9f72c), [`6b9b93d`](https://github.com/mastra-ai/mastra/commit/6b9b93d6f459d1ba6e36f163abf62a085ddb3d64), [`31b6067`](https://github.com/mastra-ai/mastra/commit/31b6067d0cc3ab10e1b29c36147f3b5266bc714a), [`797ac42`](https://github.com/mastra-ai/mastra/commit/797ac4276de231ad2d694d9aeca75980f6cd0419), [`0bc289e`](https://github.com/mastra-ai/mastra/commit/0bc289e2d476bf46c5b91c21969e8d0c6864691c), [`9b75a06`](https://github.com/mastra-ai/mastra/commit/9b75a06e53ebb0b950ba7c1e83a0142047185f46), [`4c3a1b1`](https://github.com/mastra-ai/mastra/commit/4c3a1b122ea083e003d71092f30f3b31680b01c0), [`256df35`](https://github.com/mastra-ai/mastra/commit/256df3571d62beb3ad4971faa432927cc140e603), [`85cc3b3`](https://github.com/mastra-ai/mastra/commit/85cc3b3b6f32ae4b083c26498f50d5b250ba944b), [`97ea28c`](https://github.com/mastra-ai/mastra/commit/97ea28c746e9e4147d56047bbb1c4a92417a3fec), [`d567299`](https://github.com/mastra-ai/mastra/commit/d567299cf81e02bd9d5221d4bc05967d6c224161), [`716ffe6`](https://github.com/mastra-ai/mastra/commit/716ffe68bed81f7c2690bc8581b9e140f7bf1c3d), [`8296332`](https://github.com/mastra-ai/mastra/commit/8296332de21c16e3dfc3d0b2d615720a6dc88f2f), [`4df2116`](https://github.com/mastra-ai/mastra/commit/4df211619dd922c047d396ca41cd7027c8c4c8e7), [`2219c1a`](https://github.com/mastra-ai/mastra/commit/2219c1acbd21da116da877f0036ffb985a9dd5a3), [`17c4145`](https://github.com/mastra-ai/mastra/commit/17c4145166099354545582335b5252bdfdfd908b)]:
|
|
18
|
+
- @mastra/core@1.11.0
|
|
19
|
+
|
|
20
|
+
## 1.3.0-alpha.0
|
|
21
|
+
|
|
22
|
+
### Minor Changes
|
|
23
|
+
|
|
24
|
+
- Added `requestContext` column to the spans table. Request context data from tracing is now persisted alongside other span data. ([#14020](https://github.com/mastra-ai/mastra/pull/14020))
|
|
25
|
+
|
|
26
|
+
### Patch Changes
|
|
27
|
+
|
|
28
|
+
- Added resilient column handling to insert and update operations. Unknown columns in records are now silently dropped instead of causing SQL errors, ensuring forward compatibility when newer domain packages add fields that haven't been migrated yet. ([#14021](https://github.com/mastra-ai/mastra/pull/14021))
|
|
29
|
+
|
|
30
|
+
For example, calling `db.insert({ tableName, record: { id: '1', title: 'Hello', futureField: 'value' } })` will silently ignore `futureField` if it doesn't exist in the database table, rather than throwing. The same applies to `update` — unknown fields in the data payload are dropped before building the SQL statement.
|
|
31
|
+
|
|
32
|
+
- Fixed slow semantic recall in the libsql, Cloudflare D1, and ClickHouse storage adapters. Recall performance no longer degrades as threads grow larger. (Fixes #11702) ([#14022](https://github.com/mastra-ai/mastra/pull/14022))
|
|
33
|
+
|
|
34
|
+
- Updated dependencies [[`4f71b43`](https://github.com/mastra-ai/mastra/commit/4f71b436a4a6b8839842d8da47b57b84509af56c), [`a070277`](https://github.com/mastra-ai/mastra/commit/a07027766ce195ba74d0783116d894cbab25d44c), [`b628b91`](https://github.com/mastra-ai/mastra/commit/b628b9128b372c0f54214d902b07279f03443900), [`332c014`](https://github.com/mastra-ai/mastra/commit/332c014e076b81edf7fe45b58205882726415e90), [`6b63153`](https://github.com/mastra-ai/mastra/commit/6b63153878ea841c0f4ce632ba66bb33e57e9c1b), [`4246e34`](https://github.com/mastra-ai/mastra/commit/4246e34cec9c26636d0965942268e6d07c346671), [`b8837ee`](https://github.com/mastra-ai/mastra/commit/b8837ee77e2e84197609762bfabd8b3da326d30c), [`5d950f7`](https://github.com/mastra-ai/mastra/commit/5d950f7bf426a215a1808f0abef7de5c8336ba1c), [`28c85b1`](https://github.com/mastra-ai/mastra/commit/28c85b184fc32b40f7f160483c982da6d388ecbd), [`e9a08fb`](https://github.com/mastra-ai/mastra/commit/e9a08fbef1ada7e50e961e2f54f55e8c10b4a45c), [`631ffd8`](https://github.com/mastra-ai/mastra/commit/631ffd82fed108648b448b28e6a90e38c5f53bf5), [`aae2295`](https://github.com/mastra-ai/mastra/commit/aae2295838a2d329ad6640829e87934790ffe5b8), [`aa61f29`](https://github.com/mastra-ai/mastra/commit/aa61f29ff8095ce46a4ae16e46c4d8c79b2b685b), [`7ff3714`](https://github.com/mastra-ai/mastra/commit/7ff37148515439bb3be009a60e02c3e363299760), [`41d79a1`](https://github.com/mastra-ai/mastra/commit/41d79a14bd8cb6de1e2565fd0a04786bae2f211b), [`e673376`](https://github.com/mastra-ai/mastra/commit/e6733763ad1321aa7e5ae15096b9c2104f93b1f3), [`b2204c9`](https://github.com/mastra-ai/mastra/commit/b2204c98a42848bbfb6f0440f005dc2b6354f1cd), [`a1bf1e3`](https://github.com/mastra-ai/mastra/commit/a1bf1e385ed4c0ef6f11b56c5887442970d127f2), [`b6f647a`](https://github.com/mastra-ai/mastra/commit/b6f647ae2388e091f366581595feb957e37d5b40), [`0c57b8b`](https://github.com/mastra-ai/mastra/commit/0c57b8b0a69a97b5a4ae3f79be6c610f29f3cf7b), [`b081f27`](https://github.com/mastra-ai/mastra/commit/b081f272cf411716e1d6bd72ceac4bcee2657b19), [`0c09eac`](https://github.com/mastra-ai/mastra/commit/0c09eacb1926f64cfdc9ae5c6d63385cf8c9f72c), [`6b9b93d`](https://github.com/mastra-ai/mastra/commit/6b9b93d6f459d1ba6e36f163abf62a085ddb3d64), [`31b6067`](https://github.com/mastra-ai/mastra/commit/31b6067d0cc3ab10e1b29c36147f3b5266bc714a), [`797ac42`](https://github.com/mastra-ai/mastra/commit/797ac4276de231ad2d694d9aeca75980f6cd0419), [`0bc289e`](https://github.com/mastra-ai/mastra/commit/0bc289e2d476bf46c5b91c21969e8d0c6864691c), [`9b75a06`](https://github.com/mastra-ai/mastra/commit/9b75a06e53ebb0b950ba7c1e83a0142047185f46), [`4c3a1b1`](https://github.com/mastra-ai/mastra/commit/4c3a1b122ea083e003d71092f30f3b31680b01c0), [`85cc3b3`](https://github.com/mastra-ai/mastra/commit/85cc3b3b6f32ae4b083c26498f50d5b250ba944b), [`97ea28c`](https://github.com/mastra-ai/mastra/commit/97ea28c746e9e4147d56047bbb1c4a92417a3fec), [`d567299`](https://github.com/mastra-ai/mastra/commit/d567299cf81e02bd9d5221d4bc05967d6c224161), [`716ffe6`](https://github.com/mastra-ai/mastra/commit/716ffe68bed81f7c2690bc8581b9e140f7bf1c3d), [`8296332`](https://github.com/mastra-ai/mastra/commit/8296332de21c16e3dfc3d0b2d615720a6dc88f2f), [`4df2116`](https://github.com/mastra-ai/mastra/commit/4df211619dd922c047d396ca41cd7027c8c4c8e7), [`2219c1a`](https://github.com/mastra-ai/mastra/commit/2219c1acbd21da116da877f0036ffb985a9dd5a3), [`17c4145`](https://github.com/mastra-ai/mastra/commit/17c4145166099354545582335b5252bdfdfd908b)]:
|
|
35
|
+
- @mastra/core@1.11.0-alpha.0
|
|
36
|
+
|
|
3
37
|
## 1.2.3
|
|
4
38
|
|
|
5
39
|
### Patch Changes
|
package/dist/docs/SKILL.md
CHANGED
|
@@ -3,7 +3,7 @@ name: mastra-clickhouse
|
|
|
3
3
|
description: Documentation for @mastra/clickhouse. Use when working with @mastra/clickhouse APIs, configuration, or implementation.
|
|
4
4
|
metadata:
|
|
5
5
|
package: "@mastra/clickhouse"
|
|
6
|
-
version: "1.
|
|
6
|
+
version: "1.3.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## When to use
|
|
@@ -16,7 +16,7 @@ Read the individual reference documents for detailed explanations and code examp
|
|
|
16
16
|
|
|
17
17
|
### Reference
|
|
18
18
|
|
|
19
|
-
- [Reference: Composite
|
|
19
|
+
- [Reference: Composite storage](references/reference-storage-composite.md) - Documentation for combining multiple storage backends in Mastra.
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
Read [assets/SOURCE_MAP.json](assets/SOURCE_MAP.json) for source code references.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Composite
|
|
1
|
+
# Composite storage
|
|
2
2
|
|
|
3
3
|
`MastraCompositeStore` can compose storage domains from different providers. Use it when you need different databases for different purposes. For example, use LibSQL for memory and PostgreSQL for workflows.
|
|
4
4
|
|
|
@@ -120,23 +120,23 @@ export const mastra = new Mastra({
|
|
|
120
120
|
|
|
121
121
|
## Options
|
|
122
122
|
|
|
123
|
-
**id
|
|
123
|
+
**id** (`string`): Unique identifier for this storage instance.
|
|
124
124
|
|
|
125
|
-
**default
|
|
125
|
+
**default** (`MastraCompositeStore`): Default storage adapter. Domains not explicitly specified in \`domains\` will use this storage's domains as fallbacks.
|
|
126
126
|
|
|
127
|
-
**domains
|
|
127
|
+
**domains** (`object`): Individual domain overrides. Each domain can come from a different storage adapter. These take precedence over the default storage.
|
|
128
128
|
|
|
129
|
-
**domains.memory
|
|
129
|
+
**domains.memory** (`MemoryStorage`): Storage for threads, messages, and resources.
|
|
130
130
|
|
|
131
|
-
**domains.workflows
|
|
131
|
+
**domains.workflows** (`WorkflowsStorage`): Storage for workflow snapshots.
|
|
132
132
|
|
|
133
|
-
**domains.scores
|
|
133
|
+
**domains.scores** (`ScoresStorage`): Storage for evaluation scores.
|
|
134
134
|
|
|
135
|
-
**domains.observability
|
|
135
|
+
**domains.observability** (`ObservabilityStorage`): Storage for traces and spans.
|
|
136
136
|
|
|
137
|
-
**domains.agents
|
|
137
|
+
**domains.agents** (`AgentsStorage`): Storage for stored agent configurations.
|
|
138
138
|
|
|
139
|
-
**disableInit
|
|
139
|
+
**disableInit** (`boolean`): When true, automatic initialization is disabled. You must call init() explicitly.
|
|
140
140
|
|
|
141
141
|
## Initialization
|
|
142
142
|
|
package/dist/index.cjs
CHANGED
|
@@ -105,6 +105,8 @@ function resolveClickhouseConfig(config) {
|
|
|
105
105
|
var ClickhouseDB = class extends base.MastraBase {
|
|
106
106
|
ttl;
|
|
107
107
|
client;
|
|
108
|
+
/** Cache of actual table columns: tableName -> Promise<Set<columnName>> (stores in-flight promise to coalesce concurrent calls) */
|
|
109
|
+
tableColumnsCache = /* @__PURE__ */ new Map();
|
|
108
110
|
constructor({ client, ttl }) {
|
|
109
111
|
super({
|
|
110
112
|
name: "CLICKHOUSE_DB"
|
|
@@ -112,6 +114,48 @@ var ClickhouseDB = class extends base.MastraBase {
|
|
|
112
114
|
this.ttl = ttl;
|
|
113
115
|
this.client = client;
|
|
114
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Gets the set of column names that actually exist in the database table.
|
|
119
|
+
* Results are cached; the cache is invalidated when alterTable() adds new columns.
|
|
120
|
+
*/
|
|
121
|
+
async getTableColumns(tableName) {
|
|
122
|
+
const cached = this.tableColumnsCache.get(tableName);
|
|
123
|
+
if (cached) return cached;
|
|
124
|
+
const promise = (async () => {
|
|
125
|
+
try {
|
|
126
|
+
const result = await this.client.query({
|
|
127
|
+
query: `DESCRIBE TABLE ${tableName}`,
|
|
128
|
+
format: "JSONEachRow"
|
|
129
|
+
});
|
|
130
|
+
const rows = await result.json();
|
|
131
|
+
const columns = new Set(rows.map((r) => r.name));
|
|
132
|
+
if (columns.size === 0) {
|
|
133
|
+
this.tableColumnsCache.delete(tableName);
|
|
134
|
+
}
|
|
135
|
+
return columns;
|
|
136
|
+
} catch {
|
|
137
|
+
this.tableColumnsCache.delete(tableName);
|
|
138
|
+
return /* @__PURE__ */ new Set();
|
|
139
|
+
}
|
|
140
|
+
})();
|
|
141
|
+
this.tableColumnsCache.set(tableName, promise);
|
|
142
|
+
return promise;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Filters a record to only include columns that exist in the actual database table.
|
|
146
|
+
* Unknown columns are silently dropped to ensure forward compatibility.
|
|
147
|
+
*/
|
|
148
|
+
async filterRecordToKnownColumns(tableName, record) {
|
|
149
|
+
const knownColumns = await this.getTableColumns(tableName);
|
|
150
|
+
if (knownColumns.size === 0) return record;
|
|
151
|
+
const filtered = {};
|
|
152
|
+
for (const [key, value] of Object.entries(record)) {
|
|
153
|
+
if (knownColumns.has(key)) {
|
|
154
|
+
filtered[key] = value;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return filtered;
|
|
158
|
+
}
|
|
115
159
|
async hasColumn(table, column) {
|
|
116
160
|
const result = await this.client.query({
|
|
117
161
|
query: `DESCRIBE TABLE ${table}`,
|
|
@@ -423,6 +467,8 @@ var ClickhouseDB = class extends base.MastraBase {
|
|
|
423
467
|
},
|
|
424
468
|
error$1
|
|
425
469
|
);
|
|
470
|
+
} finally {
|
|
471
|
+
this.tableColumnsCache.delete(tableName);
|
|
426
472
|
}
|
|
427
473
|
}
|
|
428
474
|
async alterTable({
|
|
@@ -462,6 +508,8 @@ var ClickhouseDB = class extends base.MastraBase {
|
|
|
462
508
|
},
|
|
463
509
|
error$1
|
|
464
510
|
);
|
|
511
|
+
} finally {
|
|
512
|
+
this.tableColumnsCache.delete(tableName);
|
|
465
513
|
}
|
|
466
514
|
}
|
|
467
515
|
async clearTable({ tableName }) {
|
|
@@ -489,25 +537,39 @@ var ClickhouseDB = class extends base.MastraBase {
|
|
|
489
537
|
}
|
|
490
538
|
}
|
|
491
539
|
async dropTable({ tableName }) {
|
|
492
|
-
|
|
493
|
-
query
|
|
494
|
-
|
|
540
|
+
try {
|
|
541
|
+
await this.client.query({
|
|
542
|
+
query: `DROP TABLE IF EXISTS ${tableName}`
|
|
543
|
+
});
|
|
544
|
+
} catch (error$1) {
|
|
545
|
+
throw new error.MastraError(
|
|
546
|
+
{
|
|
547
|
+
id: storage.createStorageErrorId("CLICKHOUSE", "DROP_TABLE", "FAILED"),
|
|
548
|
+
domain: error.ErrorDomain.STORAGE,
|
|
549
|
+
category: error.ErrorCategory.THIRD_PARTY,
|
|
550
|
+
details: { tableName }
|
|
551
|
+
},
|
|
552
|
+
error$1
|
|
553
|
+
);
|
|
554
|
+
} finally {
|
|
555
|
+
this.tableColumnsCache.delete(tableName);
|
|
556
|
+
}
|
|
495
557
|
}
|
|
496
558
|
async insert({ tableName, record }) {
|
|
497
|
-
const rawCreatedAt = record.createdAt || record.created_at || /* @__PURE__ */ new Date();
|
|
498
|
-
const rawUpdatedAt = record.updatedAt || /* @__PURE__ */ new Date();
|
|
499
|
-
const createdAt = rawCreatedAt instanceof Date ? rawCreatedAt.toISOString() : rawCreatedAt;
|
|
500
|
-
const updatedAt = rawUpdatedAt instanceof Date ? rawUpdatedAt.toISOString() : rawUpdatedAt;
|
|
501
559
|
try {
|
|
560
|
+
const filteredRecord = await this.filterRecordToKnownColumns(tableName, record);
|
|
561
|
+
if (Object.keys(filteredRecord).length === 0) return;
|
|
562
|
+
const rawCreatedAt = filteredRecord.createdAt || filteredRecord.created_at || /* @__PURE__ */ new Date();
|
|
563
|
+
const rawUpdatedAt = filteredRecord.updatedAt || /* @__PURE__ */ new Date();
|
|
564
|
+
if ("createdAt" in filteredRecord || (await this.getTableColumns(tableName)).has("createdAt")) {
|
|
565
|
+
filteredRecord.createdAt = rawCreatedAt instanceof Date ? rawCreatedAt.toISOString() : rawCreatedAt;
|
|
566
|
+
}
|
|
567
|
+
if ("updatedAt" in filteredRecord || (await this.getTableColumns(tableName)).has("updatedAt")) {
|
|
568
|
+
filteredRecord.updatedAt = rawUpdatedAt instanceof Date ? rawUpdatedAt.toISOString() : rawUpdatedAt;
|
|
569
|
+
}
|
|
502
570
|
await this.client.insert({
|
|
503
571
|
table: tableName,
|
|
504
|
-
values: [
|
|
505
|
-
{
|
|
506
|
-
...record,
|
|
507
|
-
createdAt,
|
|
508
|
-
updatedAt
|
|
509
|
-
}
|
|
510
|
-
],
|
|
572
|
+
values: [filteredRecord],
|
|
511
573
|
format: "JSONEachRow",
|
|
512
574
|
clickhouse_settings: {
|
|
513
575
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -529,7 +591,7 @@ var ClickhouseDB = class extends base.MastraBase {
|
|
|
529
591
|
}
|
|
530
592
|
}
|
|
531
593
|
async batchInsert({ tableName, records }) {
|
|
532
|
-
const
|
|
594
|
+
const processedRecords = records.map((record) => ({
|
|
533
595
|
...Object.fromEntries(
|
|
534
596
|
Object.entries(record).map(([key, value]) => [
|
|
535
597
|
key,
|
|
@@ -539,10 +601,15 @@ var ClickhouseDB = class extends base.MastraBase {
|
|
|
539
601
|
])
|
|
540
602
|
)
|
|
541
603
|
}));
|
|
604
|
+
const recordsToBeInserted = await Promise.all(
|
|
605
|
+
processedRecords.map((r) => this.filterRecordToKnownColumns(tableName, r))
|
|
606
|
+
);
|
|
607
|
+
const nonEmptyRecords = recordsToBeInserted.filter((r) => Object.keys(r).length > 0);
|
|
608
|
+
if (nonEmptyRecords.length === 0) return;
|
|
542
609
|
try {
|
|
543
610
|
await this.client.insert({
|
|
544
611
|
table: tableName,
|
|
545
|
-
values:
|
|
612
|
+
values: nonEmptyRecords,
|
|
546
613
|
format: "JSONEachRow",
|
|
547
614
|
clickhouse_settings: {
|
|
548
615
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -808,6 +875,20 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
808
875
|
}
|
|
809
876
|
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
810
877
|
dataQuery += ` ORDER BY "${field}" ${direction}`;
|
|
878
|
+
if (perPageForQuery === 0 && (!include || include.length === 0)) {
|
|
879
|
+
return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
|
|
880
|
+
}
|
|
881
|
+
if (perPageForQuery === 0 && include && include.length > 0) {
|
|
882
|
+
const includeResult = await this._getIncludedMessages({ include });
|
|
883
|
+
const list2 = new agent.MessageList().add(includeResult, "memory");
|
|
884
|
+
return {
|
|
885
|
+
messages: this._sortMessages(list2.get.all.db(), field, direction),
|
|
886
|
+
total: 0,
|
|
887
|
+
page,
|
|
888
|
+
perPage: perPageForResponse,
|
|
889
|
+
hasMore: false
|
|
890
|
+
};
|
|
891
|
+
}
|
|
811
892
|
if (perPageForResponse === false) ; else {
|
|
812
893
|
dataQuery += ` LIMIT {limit:Int64} OFFSET {offset:Int64}`;
|
|
813
894
|
dataParams.limit = perPageForQuery;
|
|
@@ -869,92 +950,17 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
869
950
|
};
|
|
870
951
|
}
|
|
871
952
|
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
872
|
-
let includeMessages = [];
|
|
873
953
|
if (include && include.length > 0) {
|
|
874
|
-
const
|
|
875
|
-
const
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
messageIds
|
|
879
|
-
});
|
|
880
|
-
for (const msg of includeLookup) {
|
|
881
|
-
if (msg.threadId) {
|
|
882
|
-
threadByMessageId.set(msg.id, msg.threadId);
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
const unionQueries = [];
|
|
887
|
-
const params = [];
|
|
888
|
-
let paramIdx = 1;
|
|
889
|
-
for (const inc of include) {
|
|
890
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
891
|
-
const searchThreadId = inc.threadId ?? threadByMessageId.get(id);
|
|
892
|
-
if (!searchThreadId) continue;
|
|
893
|
-
unionQueries.push(`
|
|
894
|
-
SELECT * FROM (
|
|
895
|
-
WITH numbered_messages AS (
|
|
896
|
-
SELECT
|
|
897
|
-
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
898
|
-
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
899
|
-
FROM "${storage.TABLE_MESSAGES}"
|
|
900
|
-
WHERE thread_id = {var_thread_id_${paramIdx}:String}
|
|
901
|
-
),
|
|
902
|
-
target_positions AS (
|
|
903
|
-
SELECT row_num as target_pos
|
|
904
|
-
FROM numbered_messages
|
|
905
|
-
WHERE id = {var_include_id_${paramIdx}:String}
|
|
906
|
-
)
|
|
907
|
-
SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId", m."resourceId"
|
|
908
|
-
FROM numbered_messages m
|
|
909
|
-
CROSS JOIN target_positions t
|
|
910
|
-
WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
|
|
911
|
-
) AS query_${paramIdx}
|
|
912
|
-
`);
|
|
913
|
-
params.push(
|
|
914
|
-
{ [`var_thread_id_${paramIdx}`]: searchThreadId },
|
|
915
|
-
{ [`var_include_id_${paramIdx}`]: id },
|
|
916
|
-
{ [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
|
|
917
|
-
{ [`var_withNextMessages_${paramIdx}`]: withNextMessages }
|
|
918
|
-
);
|
|
919
|
-
paramIdx++;
|
|
920
|
-
}
|
|
921
|
-
if (unionQueries.length > 0) {
|
|
922
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
923
|
-
const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
|
|
924
|
-
const includeResult = await this.client.query({
|
|
925
|
-
query: finalQuery,
|
|
926
|
-
query_params: mergedParams,
|
|
927
|
-
clickhouse_settings: {
|
|
928
|
-
date_time_input_format: "best_effort",
|
|
929
|
-
date_time_output_format: "iso",
|
|
930
|
-
use_client_time_zone: 1,
|
|
931
|
-
output_format_json_quote_64bit_integers: 0
|
|
932
|
-
}
|
|
933
|
-
});
|
|
934
|
-
const includeRows = await includeResult.json();
|
|
935
|
-
includeMessages = transformRows(includeRows.data);
|
|
936
|
-
for (const includeMsg of includeMessages) {
|
|
937
|
-
if (!messageIds.has(includeMsg.id)) {
|
|
938
|
-
paginatedMessages.push(includeMsg);
|
|
939
|
-
messageIds.add(includeMsg.id);
|
|
940
|
-
}
|
|
954
|
+
const includeMessages = await this._getIncludedMessages({ include });
|
|
955
|
+
for (const includeMsg of includeMessages) {
|
|
956
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
957
|
+
paginatedMessages.push(includeMsg);
|
|
958
|
+
messageIds.add(includeMsg.id);
|
|
941
959
|
}
|
|
942
960
|
}
|
|
943
961
|
}
|
|
944
962
|
const list = new agent.MessageList().add(paginatedMessages, "memory");
|
|
945
|
-
|
|
946
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
947
|
-
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
948
|
-
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
949
|
-
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
950
|
-
if (aValue === bValue) {
|
|
951
|
-
return a.id.localeCompare(b.id);
|
|
952
|
-
}
|
|
953
|
-
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
954
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
955
|
-
}
|
|
956
|
-
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
957
|
-
});
|
|
963
|
+
const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
|
|
958
964
|
const threadIdSet = new Set(threadIds);
|
|
959
965
|
const returnedThreadMessageIds = new Set(
|
|
960
966
|
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
@@ -992,6 +998,95 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
992
998
|
};
|
|
993
999
|
}
|
|
994
1000
|
}
|
|
1001
|
+
_sortMessages(messages, field, direction) {
|
|
1002
|
+
return messages.sort((a, b) => {
|
|
1003
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
1004
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
1005
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
1006
|
+
if (aValue === bValue) {
|
|
1007
|
+
return a.id.localeCompare(b.id);
|
|
1008
|
+
}
|
|
1009
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
1010
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1011
|
+
}
|
|
1012
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
async _getIncludedMessages({
|
|
1016
|
+
include
|
|
1017
|
+
}) {
|
|
1018
|
+
if (!include || include.length === 0) return [];
|
|
1019
|
+
const targetIds = include.map((inc) => inc.id).filter(Boolean);
|
|
1020
|
+
if (targetIds.length === 0) return [];
|
|
1021
|
+
const { messages: targetDocs } = await this.listMessagesById({ messageIds: targetIds });
|
|
1022
|
+
const targetMap = new Map(
|
|
1023
|
+
targetDocs.map((msg) => [msg.id, { threadId: msg.threadId, createdAt: msg.createdAt }])
|
|
1024
|
+
);
|
|
1025
|
+
const unionQueries = [];
|
|
1026
|
+
const params = {};
|
|
1027
|
+
let paramIdx = 1;
|
|
1028
|
+
for (const inc of include) {
|
|
1029
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1030
|
+
const target = targetMap.get(id);
|
|
1031
|
+
if (!target) continue;
|
|
1032
|
+
const threadParam = `var_thread_${paramIdx}`;
|
|
1033
|
+
const createdAtParam = `var_createdAt_${paramIdx}`;
|
|
1034
|
+
const limitParam = `var_limit_${paramIdx}`;
|
|
1035
|
+
unionQueries.push(`
|
|
1036
|
+
SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"
|
|
1037
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
1038
|
+
WHERE thread_id = {${threadParam}:String}
|
|
1039
|
+
AND createdAt <= parseDateTime64BestEffort({${createdAtParam}:String}, 3)
|
|
1040
|
+
ORDER BY createdAt DESC, id DESC
|
|
1041
|
+
LIMIT {${limitParam}:Int64}
|
|
1042
|
+
`);
|
|
1043
|
+
params[threadParam] = target.threadId;
|
|
1044
|
+
params[createdAtParam] = target.createdAt;
|
|
1045
|
+
params[limitParam] = withPreviousMessages + 1;
|
|
1046
|
+
paramIdx++;
|
|
1047
|
+
if (withNextMessages > 0) {
|
|
1048
|
+
const threadParam2 = `var_thread_${paramIdx}`;
|
|
1049
|
+
const createdAtParam2 = `var_createdAt_${paramIdx}`;
|
|
1050
|
+
const limitParam2 = `var_limit_${paramIdx}`;
|
|
1051
|
+
unionQueries.push(`
|
|
1052
|
+
SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"
|
|
1053
|
+
FROM "${storage.TABLE_MESSAGES}"
|
|
1054
|
+
WHERE thread_id = {${threadParam2}:String}
|
|
1055
|
+
AND createdAt > parseDateTime64BestEffort({${createdAtParam2}:String}, 3)
|
|
1056
|
+
ORDER BY createdAt ASC, id ASC
|
|
1057
|
+
LIMIT {${limitParam2}:Int64}
|
|
1058
|
+
`);
|
|
1059
|
+
params[threadParam2] = target.threadId;
|
|
1060
|
+
params[createdAtParam2] = target.createdAt;
|
|
1061
|
+
params[limitParam2] = withNextMessages;
|
|
1062
|
+
paramIdx++;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
if (unionQueries.length === 0) return [];
|
|
1066
|
+
let finalQuery;
|
|
1067
|
+
if (unionQueries.length === 1) {
|
|
1068
|
+
finalQuery = unionQueries[0];
|
|
1069
|
+
} else {
|
|
1070
|
+
finalQuery = `SELECT * FROM (${unionQueries.join(" UNION ALL ")}) ORDER BY "createdAt" ASC, id ASC`;
|
|
1071
|
+
}
|
|
1072
|
+
const includeResult = await this.client.query({
|
|
1073
|
+
query: finalQuery,
|
|
1074
|
+
query_params: params,
|
|
1075
|
+
clickhouse_settings: {
|
|
1076
|
+
date_time_input_format: "best_effort",
|
|
1077
|
+
date_time_output_format: "iso",
|
|
1078
|
+
use_client_time_zone: 1,
|
|
1079
|
+
output_format_json_quote_64bit_integers: 0
|
|
1080
|
+
}
|
|
1081
|
+
});
|
|
1082
|
+
const includeRows = await includeResult.json();
|
|
1083
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1084
|
+
return transformRows(includeRows.data).filter((row) => {
|
|
1085
|
+
if (seen.has(row.id)) return false;
|
|
1086
|
+
seen.add(row.id);
|
|
1087
|
+
return true;
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
995
1090
|
async saveMessages(args) {
|
|
996
1091
|
const { messages } = args;
|
|
997
1092
|
if (messages.length === 0) return { messages };
|
|
@@ -1912,6 +2007,11 @@ time for large tables. Please ensure you have a backup before proceeding.
|
|
|
1912
2007
|
});
|
|
1913
2008
|
}
|
|
1914
2009
|
await this.#db.createTable({ tableName: storage.TABLE_SPANS, schema: storage.SPAN_SCHEMA });
|
|
2010
|
+
await this.#db.alterTable({
|
|
2011
|
+
tableName: storage.TABLE_SPANS,
|
|
2012
|
+
schema: storage.SPAN_SCHEMA,
|
|
2013
|
+
ifNotExists: ["requestContext"]
|
|
2014
|
+
});
|
|
1915
2015
|
}
|
|
1916
2016
|
async dangerouslyClearAll() {
|
|
1917
2017
|
await this.#db.clearTable({ tableName: storage.TABLE_SPANS });
|
|
@@ -2184,7 +2284,8 @@ time for large tables. Please ensure you have a backup before proceeding.
|
|
|
2184
2284
|
}
|
|
2185
2285
|
async listTraces(args) {
|
|
2186
2286
|
const { filters, pagination, orderBy } = storage.listTracesArgsSchema.parse(args);
|
|
2187
|
-
const
|
|
2287
|
+
const page = pagination?.page ?? 0;
|
|
2288
|
+
const perPage = pagination?.perPage ?? 10;
|
|
2188
2289
|
try {
|
|
2189
2290
|
const conditions = [`(parentSpanId IS NULL OR parentSpanId = '')`];
|
|
2190
2291
|
const values = {};
|
|
@@ -2331,8 +2432,8 @@ time for large tables. Please ensure you have a backup before proceeding.
|
|
|
2331
2432
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2332
2433
|
const engine = TABLE_ENGINES[storage.TABLE_SPANS] ?? "MergeTree()";
|
|
2333
2434
|
const finalClause = engine.startsWith("ReplacingMergeTree") ? "FINAL" : "";
|
|
2334
|
-
const sortField = orderBy
|
|
2335
|
-
const sortDirection = orderBy
|
|
2435
|
+
const sortField = orderBy?.field ?? "startedAt";
|
|
2436
|
+
const sortDirection = orderBy?.direction ?? "DESC";
|
|
2336
2437
|
let orderClause;
|
|
2337
2438
|
if (sortField === "endedAt") {
|
|
2338
2439
|
const nullSortValue = sortDirection === "DESC" ? 0 : 1;
|