@mastra/clickhouse 1.0.0-beta.1 → 1.0.0-beta.2
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 +25 -0
- package/dist/index.cjs +73 -55
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +74 -56
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/scores/index.d.ts +4 -0
- package/dist/storage/domains/scores/index.d.ts.map +1 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @mastra/clickhouse
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- feat(storage): support querying messages from multiple threads ([#10663](https://github.com/mastra-ai/mastra/pull/10663))
|
|
8
|
+
- Fixed TypeScript errors where `threadId: string | string[]` was being passed to places expecting `Scalar` type
|
|
9
|
+
- Added proper multi-thread support for `listMessages` across all adapters when `threadId` is an array
|
|
10
|
+
- Updated `_getIncludedMessages` to look up message threadId by ID (since message IDs are globally unique)
|
|
11
|
+
- **upstash**: Added `msg-idx:{messageId}` index for O(1) message lookups (backwards compatible with fallback to scan for old messages, with automatic backfill)
|
|
12
|
+
|
|
13
|
+
- fix: ensure score responses match saved payloads for Mastra Stores. ([#10557](https://github.com/mastra-ai/mastra/pull/10557))
|
|
14
|
+
|
|
15
|
+
- Unify transformScoreRow functions across storage adapters ([#10648](https://github.com/mastra-ai/mastra/pull/10648))
|
|
16
|
+
|
|
17
|
+
Added a unified `transformScoreRow` function in `@mastra/core/storage` that provides schema-driven row transformation for score data. This eliminates code duplication across 10 storage adapters while maintaining store-specific behavior through configurable options:
|
|
18
|
+
- `preferredTimestampFields`: Preferred source fields for timestamps (PostgreSQL, Cloudflare D1)
|
|
19
|
+
- `convertTimestamps`: Convert timestamp strings to Date objects (MSSQL, MongoDB, ClickHouse)
|
|
20
|
+
- `nullValuePattern`: Skip values matching pattern (ClickHouse's `'_null_'`)
|
|
21
|
+
- `fieldMappings`: Map source column names to schema fields (LibSQL's `additionalLLMContext`)
|
|
22
|
+
|
|
23
|
+
Each store adapter now uses the unified function with appropriate options, reducing ~200 lines of duplicate transformation logic while ensuring consistent behavior across all storage backends.
|
|
24
|
+
|
|
25
|
+
- Updated dependencies [[`ac0d2f4`](https://github.com/mastra-ai/mastra/commit/ac0d2f4ff8831f72c1c66c2be809706d17f65789), [`1a0d3fc`](https://github.com/mastra-ai/mastra/commit/1a0d3fc811482c9c376cdf79ee615c23bae9b2d6), [`85a628b`](https://github.com/mastra-ai/mastra/commit/85a628b1224a8f64cd82ea7f033774bf22df7a7e), [`c237233`](https://github.com/mastra-ai/mastra/commit/c23723399ccedf7f5744b3f40997b79246bfbe64), [`15f9e21`](https://github.com/mastra-ai/mastra/commit/15f9e216177201ea6e3f6d0bfb063fcc0953444f), [`ff94dea`](https://github.com/mastra-ai/mastra/commit/ff94dea935f4e34545c63bcb6c29804732698809), [`5b2ff46`](https://github.com/mastra-ai/mastra/commit/5b2ff4651df70c146523a7fca773f8eb0a2272f8), [`db41688`](https://github.com/mastra-ai/mastra/commit/db4168806d007417e2e60b4f68656dca4e5f40c9), [`5ca599d`](https://github.com/mastra-ai/mastra/commit/5ca599d0bb59a1595f19f58473fcd67cc71cef58), [`bff1145`](https://github.com/mastra-ai/mastra/commit/bff114556b3cbadad9b2768488708f8ad0e91475), [`5c8ca24`](https://github.com/mastra-ai/mastra/commit/5c8ca247094e0cc2cdbd7137822fb47241f86e77), [`e191844`](https://github.com/mastra-ai/mastra/commit/e1918444ca3f80e82feef1dad506cd4ec6e2875f), [`22553f1`](https://github.com/mastra-ai/mastra/commit/22553f11c63ee5e966a9c034a349822249584691), [`7237163`](https://github.com/mastra-ai/mastra/commit/72371635dbf96a87df4b073cc48fc655afbdce3d), [`2500740`](https://github.com/mastra-ai/mastra/commit/2500740ea23da067d6e50ec71c625ab3ce275e64), [`873ecbb`](https://github.com/mastra-ai/mastra/commit/873ecbb517586aa17d2f1e99283755b3ebb2863f), [`4f9bbe5`](https://github.com/mastra-ai/mastra/commit/4f9bbe5968f42c86f4930b8193de3c3c17e5bd36), [`02e51fe`](https://github.com/mastra-ai/mastra/commit/02e51feddb3d4155cfbcc42624fd0d0970d032c0), [`8f3fa3a`](https://github.com/mastra-ai/mastra/commit/8f3fa3a652bb77da092f913ec51ae46e3a7e27dc), [`cd29ad2`](https://github.com/mastra-ai/mastra/commit/cd29ad23a255534e8191f249593849ed29160886), [`bdf4d8c`](https://github.com/mastra-ai/mastra/commit/bdf4d8cdc656d8a2c21d81834bfa3bfa70f56c16), [`854e3da`](https://github.com/mastra-ai/mastra/commit/854e3dad5daac17a91a20986399d3a51f54bf68b), [`ce18d38`](https://github.com/mastra-ai/mastra/commit/ce18d38678c65870350d123955014a8432075fd9), [`cccf9c8`](https://github.com/mastra-ai/mastra/commit/cccf9c8b2d2dfc1a5e63919395b83d78c89682a0), [`61a5705`](https://github.com/mastra-ai/mastra/commit/61a570551278b6743e64243b3ce7d73de915ca8a), [`db70a48`](https://github.com/mastra-ai/mastra/commit/db70a48aeeeeb8e5f92007e8ede52c364ce15287), [`f0fdc14`](https://github.com/mastra-ai/mastra/commit/f0fdc14ee233d619266b3d2bbdeea7d25cfc6d13), [`db18bc9`](https://github.com/mastra-ai/mastra/commit/db18bc9c3825e2c1a0ad9a183cc9935f6691bfa1), [`9b37b56`](https://github.com/mastra-ai/mastra/commit/9b37b565e1f2a76c24f728945cc740c2b09be9da), [`41a23c3`](https://github.com/mastra-ai/mastra/commit/41a23c32f9877d71810f37e24930515df2ff7a0f), [`5d171ad`](https://github.com/mastra-ai/mastra/commit/5d171ad9ef340387276b77c2bb3e83e83332d729), [`f03ae60`](https://github.com/mastra-ai/mastra/commit/f03ae60500fe350c9d828621006cdafe1975fdd8), [`d1e74a0`](https://github.com/mastra-ai/mastra/commit/d1e74a0a293866dece31022047f5dbab65a304d0), [`39e7869`](https://github.com/mastra-ai/mastra/commit/39e7869bc7d0ee391077ce291474d8a84eedccff), [`5761926`](https://github.com/mastra-ai/mastra/commit/57619260c4a2cdd598763abbacd90de594c6bc76), [`c900fdd`](https://github.com/mastra-ai/mastra/commit/c900fdd504c41348efdffb205cfe80d48c38fa33), [`604a79f`](https://github.com/mastra-ai/mastra/commit/604a79fecf276e26a54a3fe01bb94e65315d2e0e), [`887f0b4`](https://github.com/mastra-ai/mastra/commit/887f0b4746cdbd7cb7d6b17ac9f82aeb58037ea5), [`2562143`](https://github.com/mastra-ai/mastra/commit/256214336b4faa78646c9c1776612393790d8784), [`ef11a61`](https://github.com/mastra-ai/mastra/commit/ef11a61920fa0ed08a5b7ceedd192875af119749)]:
|
|
26
|
+
- @mastra/core@1.0.0-beta.6
|
|
27
|
+
|
|
3
28
|
## 1.0.0-beta.1
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -127,6 +127,8 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
127
127
|
}
|
|
128
128
|
async listMessages(args) {
|
|
129
129
|
const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
|
|
130
|
+
const rawThreadIds = Array.isArray(threadId) ? threadId : [threadId];
|
|
131
|
+
const threadIds = rawThreadIds.filter((id) => id !== void 0 && id !== null).map((id) => (typeof id === "string" ? id : String(id)).trim()).filter((id) => id.length > 0);
|
|
130
132
|
if (page < 0) {
|
|
131
133
|
throw new error.MastraError(
|
|
132
134
|
{
|
|
@@ -138,20 +140,21 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
138
140
|
new Error("page must be >= 0")
|
|
139
141
|
);
|
|
140
142
|
}
|
|
141
|
-
if (
|
|
143
|
+
if (threadIds.length === 0) {
|
|
142
144
|
throw new error.MastraError(
|
|
143
145
|
{
|
|
144
146
|
id: "STORAGE_CLICKHOUSE_LIST_MESSAGES_INVALID_THREAD_ID",
|
|
145
147
|
domain: error.ErrorDomain.STORAGE,
|
|
146
148
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
147
|
-
details: { threadId }
|
|
149
|
+
details: { threadId: Array.isArray(threadId) ? JSON.stringify(threadId) : String(threadId) }
|
|
148
150
|
},
|
|
149
|
-
new Error("threadId must be a non-empty string")
|
|
151
|
+
new Error("threadId must be a non-empty string or array of non-empty strings")
|
|
150
152
|
);
|
|
151
153
|
}
|
|
152
154
|
const perPageForQuery = storage.normalizePerPage(perPageInput, 40);
|
|
153
155
|
const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPageForQuery);
|
|
154
156
|
try {
|
|
157
|
+
const threadCondition = threadIds.length === 1 ? `thread_id = {threadId0:String}` : `thread_id IN (${threadIds.map((_, i) => `{threadId${i}:String}`).join(", ")})`;
|
|
155
158
|
let dataQuery = `
|
|
156
159
|
SELECT
|
|
157
160
|
id,
|
|
@@ -162,9 +165,12 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
162
165
|
thread_id AS "threadId",
|
|
163
166
|
resourceId
|
|
164
167
|
FROM ${storage.TABLE_MESSAGES}
|
|
165
|
-
WHERE
|
|
168
|
+
WHERE ${threadCondition}
|
|
166
169
|
`;
|
|
167
|
-
const dataParams = {
|
|
170
|
+
const dataParams = {};
|
|
171
|
+
threadIds.forEach((tid, i) => {
|
|
172
|
+
dataParams[`threadId${i}`] = tid;
|
|
173
|
+
});
|
|
168
174
|
if (resourceId) {
|
|
169
175
|
dataQuery += ` AND resourceId = {resourceId:String}`;
|
|
170
176
|
dataParams.resourceId = resourceId;
|
|
@@ -199,8 +205,11 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
199
205
|
const rows = await result.json();
|
|
200
206
|
const paginatedMessages = transformRows(rows.data);
|
|
201
207
|
const paginatedCount = paginatedMessages.length;
|
|
202
|
-
let countQuery = `SELECT count() as total FROM ${storage.TABLE_MESSAGES} WHERE
|
|
203
|
-
const countParams = {
|
|
208
|
+
let countQuery = `SELECT count() as total FROM ${storage.TABLE_MESSAGES} WHERE ${threadCondition}`;
|
|
209
|
+
const countParams = {};
|
|
210
|
+
threadIds.forEach((tid, i) => {
|
|
211
|
+
countParams[`threadId${i}`] = tid;
|
|
212
|
+
});
|
|
204
213
|
if (resourceId) {
|
|
205
214
|
countQuery += ` AND resourceId = {resourceId:String}`;
|
|
206
215
|
countParams.resourceId = resourceId;
|
|
@@ -239,12 +248,25 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
239
248
|
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
240
249
|
let includeMessages = [];
|
|
241
250
|
if (include && include.length > 0) {
|
|
251
|
+
const includesNeedingThread = include.filter((inc) => !inc.threadId);
|
|
252
|
+
const threadByMessageId = /* @__PURE__ */ new Map();
|
|
253
|
+
if (includesNeedingThread.length > 0) {
|
|
254
|
+
const { messages: includeLookup } = await this.listMessagesById({
|
|
255
|
+
messageIds: includesNeedingThread.map((inc) => inc.id)
|
|
256
|
+
});
|
|
257
|
+
for (const msg of includeLookup) {
|
|
258
|
+
if (msg.threadId) {
|
|
259
|
+
threadByMessageId.set(msg.id, msg.threadId);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
242
263
|
const unionQueries = [];
|
|
243
264
|
const params = [];
|
|
244
265
|
let paramIdx = 1;
|
|
245
266
|
for (const inc of include) {
|
|
246
267
|
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
247
|
-
const
|
|
268
|
+
const searchThreadId = inc.threadId ?? threadByMessageId.get(id);
|
|
269
|
+
if (!searchThreadId) continue;
|
|
248
270
|
unionQueries.push(`
|
|
249
271
|
SELECT * FROM (
|
|
250
272
|
WITH numbered_messages AS (
|
|
@@ -266,31 +288,33 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
266
288
|
) AS query_${paramIdx}
|
|
267
289
|
`);
|
|
268
290
|
params.push(
|
|
269
|
-
{ [`var_thread_id_${paramIdx}`]:
|
|
291
|
+
{ [`var_thread_id_${paramIdx}`]: searchThreadId },
|
|
270
292
|
{ [`var_include_id_${paramIdx}`]: id },
|
|
271
293
|
{ [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
|
|
272
294
|
{ [`var_withNextMessages_${paramIdx}`]: withNextMessages }
|
|
273
295
|
);
|
|
274
296
|
paramIdx++;
|
|
275
297
|
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
query
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
298
|
+
if (unionQueries.length > 0) {
|
|
299
|
+
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
300
|
+
const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
|
|
301
|
+
const includeResult = await this.client.query({
|
|
302
|
+
query: finalQuery,
|
|
303
|
+
query_params: mergedParams,
|
|
304
|
+
clickhouse_settings: {
|
|
305
|
+
date_time_input_format: "best_effort",
|
|
306
|
+
date_time_output_format: "iso",
|
|
307
|
+
use_client_time_zone: 1,
|
|
308
|
+
output_format_json_quote_64bit_integers: 0
|
|
309
|
+
}
|
|
310
|
+
});
|
|
311
|
+
const includeRows = await includeResult.json();
|
|
312
|
+
includeMessages = transformRows(includeRows.data);
|
|
313
|
+
for (const includeMsg of includeMessages) {
|
|
314
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
315
|
+
paginatedMessages.push(includeMsg);
|
|
316
|
+
messageIds.add(includeMsg.id);
|
|
317
|
+
}
|
|
294
318
|
}
|
|
295
319
|
}
|
|
296
320
|
}
|
|
@@ -308,7 +332,10 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
308
332
|
}
|
|
309
333
|
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
310
334
|
});
|
|
311
|
-
const
|
|
335
|
+
const threadIdSet = new Set(threadIds);
|
|
336
|
+
const returnedThreadMessageIds = new Set(
|
|
337
|
+
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
338
|
+
);
|
|
312
339
|
const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
|
|
313
340
|
const hasMore = perPageForResponse === false ? false : allThreadMessagesReturned ? false : offset + paginatedCount < total;
|
|
314
341
|
return {
|
|
@@ -325,7 +352,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
|
|
|
325
352
|
domain: error.ErrorDomain.STORAGE,
|
|
326
353
|
category: error.ErrorCategory.THIRD_PARTY,
|
|
327
354
|
details: {
|
|
328
|
-
threadId,
|
|
355
|
+
threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
|
|
329
356
|
resourceId: resourceId ?? ""
|
|
330
357
|
}
|
|
331
358
|
},
|
|
@@ -1451,30 +1478,15 @@ var ScoresStorageClickhouse = class extends storage.ScoresStorage {
|
|
|
1451
1478
|
this.client = client;
|
|
1452
1479
|
this.operations = operations;
|
|
1453
1480
|
}
|
|
1481
|
+
/**
|
|
1482
|
+
* ClickHouse-specific score row transformation.
|
|
1483
|
+
* Converts timestamps to Date objects and filters out '_null_' values.
|
|
1484
|
+
*/
|
|
1454
1485
|
transformScoreRow(row) {
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
const input = storage.safelyParseJSON(row.input);
|
|
1460
|
-
const output = storage.safelyParseJSON(row.output);
|
|
1461
|
-
const additionalContext = storage.safelyParseJSON(row.additionalContext);
|
|
1462
|
-
const requestContext = storage.safelyParseJSON(row.requestContext);
|
|
1463
|
-
const entity = storage.safelyParseJSON(row.entity);
|
|
1464
|
-
return {
|
|
1465
|
-
...row,
|
|
1466
|
-
scorer,
|
|
1467
|
-
preprocessStepResult,
|
|
1468
|
-
analyzeStepResult,
|
|
1469
|
-
metadata,
|
|
1470
|
-
input,
|
|
1471
|
-
output,
|
|
1472
|
-
additionalContext,
|
|
1473
|
-
requestContext,
|
|
1474
|
-
entity,
|
|
1475
|
-
createdAt: new Date(row.createdAt),
|
|
1476
|
-
updatedAt: new Date(row.updatedAt)
|
|
1477
|
-
};
|
|
1486
|
+
return storage.transformScoreRow(row, {
|
|
1487
|
+
convertTimestamps: true,
|
|
1488
|
+
nullValuePattern: "_null_"
|
|
1489
|
+
});
|
|
1478
1490
|
}
|
|
1479
1491
|
async getScoreById({ id }) {
|
|
1480
1492
|
try {
|
|
@@ -1523,9 +1535,15 @@ var ScoresStorageClickhouse = class extends storage.ScoresStorage {
|
|
|
1523
1535
|
);
|
|
1524
1536
|
}
|
|
1525
1537
|
try {
|
|
1526
|
-
const record = {
|
|
1527
|
-
|
|
1528
|
-
|
|
1538
|
+
const record = {};
|
|
1539
|
+
for (const key of Object.keys(storage.SCORERS_SCHEMA)) {
|
|
1540
|
+
const value = parsedScore[key];
|
|
1541
|
+
if (key === "createdAt" || key === "updatedAt") {
|
|
1542
|
+
record[key] = (/* @__PURE__ */ new Date()).toISOString();
|
|
1543
|
+
continue;
|
|
1544
|
+
}
|
|
1545
|
+
record[key] = value === void 0 || value === null ? "_null_" : value;
|
|
1546
|
+
}
|
|
1529
1547
|
await this.client.insert({
|
|
1530
1548
|
table: storage.TABLE_SCORERS,
|
|
1531
1549
|
values: [record],
|