@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/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createClient } from '@clickhouse/client';
|
|
2
2
|
import { MastraError, ErrorCategory, ErrorDomain } from '@mastra/core/error';
|
|
3
|
-
import { TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SKILLS, TABLE_WORKSPACE_VERSIONS, TABLE_WORKSPACES, TABLE_MCP_SERVER_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_CLIENTS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SCORER_DEFINITIONS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_PROMPT_BLOCKS, TABLE_EXPERIMENT_RESULTS, TABLE_EXPERIMENTS, TABLE_DATASET_VERSIONS, TABLE_DATASET_ITEMS, TABLE_DATASETS, TABLE_AGENT_VERSIONS, TABLE_SPANS, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_TRACES, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, MemoryStorage, TABLE_SCHEMAS, createStorageErrorId, normalizePerPage, calculatePagination, ObservabilityStorage, SPAN_SCHEMA, listTracesArgsSchema, toTraceSpans, ScoresStorage, transformScoreRow, SCORERS_SCHEMA, WorkflowsStorage, MastraCompositeStore,
|
|
3
|
+
import { TABLE_SKILL_BLOBS, TABLE_SKILL_VERSIONS, TABLE_SKILLS, TABLE_WORKSPACE_VERSIONS, TABLE_WORKSPACES, TABLE_MCP_SERVER_VERSIONS, TABLE_MCP_SERVERS, TABLE_MCP_CLIENT_VERSIONS, TABLE_MCP_CLIENTS, TABLE_SCORER_DEFINITION_VERSIONS, TABLE_SCORER_DEFINITIONS, TABLE_PROMPT_BLOCK_VERSIONS, TABLE_PROMPT_BLOCKS, TABLE_EXPERIMENT_RESULTS, TABLE_EXPERIMENTS, TABLE_DATASET_VERSIONS, TABLE_DATASET_ITEMS, TABLE_DATASETS, TABLE_AGENT_VERSIONS, TABLE_SPANS, TABLE_RESOURCES, TABLE_SCORERS, TABLE_THREADS, TABLE_TRACES, TABLE_WORKFLOW_SNAPSHOT, TABLE_MESSAGES, MemoryStorage, TABLE_SCHEMAS, createStorageErrorId, normalizePerPage, calculatePagination, ObservabilityStorage, SPAN_SCHEMA, listTracesArgsSchema, toTraceSpans, ScoresStorage, transformScoreRow, SCORERS_SCHEMA, WorkflowsStorage, MastraCompositeStore, getSqlType, getDefaultValue, safelyParseJSON, TraceStatus } from '@mastra/core/storage';
|
|
4
4
|
import { MessageList } from '@mastra/core/agent';
|
|
5
5
|
import { MastraBase } from '@mastra/core/base';
|
|
6
6
|
import { saveScorePayloadSchema } from '@mastra/core/evals';
|
|
@@ -103,6 +103,8 @@ function resolveClickhouseConfig(config) {
|
|
|
103
103
|
var ClickhouseDB = class extends MastraBase {
|
|
104
104
|
ttl;
|
|
105
105
|
client;
|
|
106
|
+
/** Cache of actual table columns: tableName -> Promise<Set<columnName>> (stores in-flight promise to coalesce concurrent calls) */
|
|
107
|
+
tableColumnsCache = /* @__PURE__ */ new Map();
|
|
106
108
|
constructor({ client, ttl }) {
|
|
107
109
|
super({
|
|
108
110
|
name: "CLICKHOUSE_DB"
|
|
@@ -110,6 +112,48 @@ var ClickhouseDB = class extends MastraBase {
|
|
|
110
112
|
this.ttl = ttl;
|
|
111
113
|
this.client = client;
|
|
112
114
|
}
|
|
115
|
+
/**
|
|
116
|
+
* Gets the set of column names that actually exist in the database table.
|
|
117
|
+
* Results are cached; the cache is invalidated when alterTable() adds new columns.
|
|
118
|
+
*/
|
|
119
|
+
async getTableColumns(tableName) {
|
|
120
|
+
const cached = this.tableColumnsCache.get(tableName);
|
|
121
|
+
if (cached) return cached;
|
|
122
|
+
const promise = (async () => {
|
|
123
|
+
try {
|
|
124
|
+
const result = await this.client.query({
|
|
125
|
+
query: `DESCRIBE TABLE ${tableName}`,
|
|
126
|
+
format: "JSONEachRow"
|
|
127
|
+
});
|
|
128
|
+
const rows = await result.json();
|
|
129
|
+
const columns = new Set(rows.map((r) => r.name));
|
|
130
|
+
if (columns.size === 0) {
|
|
131
|
+
this.tableColumnsCache.delete(tableName);
|
|
132
|
+
}
|
|
133
|
+
return columns;
|
|
134
|
+
} catch {
|
|
135
|
+
this.tableColumnsCache.delete(tableName);
|
|
136
|
+
return /* @__PURE__ */ new Set();
|
|
137
|
+
}
|
|
138
|
+
})();
|
|
139
|
+
this.tableColumnsCache.set(tableName, promise);
|
|
140
|
+
return promise;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Filters a record to only include columns that exist in the actual database table.
|
|
144
|
+
* Unknown columns are silently dropped to ensure forward compatibility.
|
|
145
|
+
*/
|
|
146
|
+
async filterRecordToKnownColumns(tableName, record) {
|
|
147
|
+
const knownColumns = await this.getTableColumns(tableName);
|
|
148
|
+
if (knownColumns.size === 0) return record;
|
|
149
|
+
const filtered = {};
|
|
150
|
+
for (const [key, value] of Object.entries(record)) {
|
|
151
|
+
if (knownColumns.has(key)) {
|
|
152
|
+
filtered[key] = value;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return filtered;
|
|
156
|
+
}
|
|
113
157
|
async hasColumn(table, column) {
|
|
114
158
|
const result = await this.client.query({
|
|
115
159
|
query: `DESCRIBE TABLE ${table}`,
|
|
@@ -421,6 +465,8 @@ var ClickhouseDB = class extends MastraBase {
|
|
|
421
465
|
},
|
|
422
466
|
error
|
|
423
467
|
);
|
|
468
|
+
} finally {
|
|
469
|
+
this.tableColumnsCache.delete(tableName);
|
|
424
470
|
}
|
|
425
471
|
}
|
|
426
472
|
async alterTable({
|
|
@@ -460,6 +506,8 @@ var ClickhouseDB = class extends MastraBase {
|
|
|
460
506
|
},
|
|
461
507
|
error
|
|
462
508
|
);
|
|
509
|
+
} finally {
|
|
510
|
+
this.tableColumnsCache.delete(tableName);
|
|
463
511
|
}
|
|
464
512
|
}
|
|
465
513
|
async clearTable({ tableName }) {
|
|
@@ -487,25 +535,39 @@ var ClickhouseDB = class extends MastraBase {
|
|
|
487
535
|
}
|
|
488
536
|
}
|
|
489
537
|
async dropTable({ tableName }) {
|
|
490
|
-
|
|
491
|
-
query
|
|
492
|
-
|
|
538
|
+
try {
|
|
539
|
+
await this.client.query({
|
|
540
|
+
query: `DROP TABLE IF EXISTS ${tableName}`
|
|
541
|
+
});
|
|
542
|
+
} catch (error) {
|
|
543
|
+
throw new MastraError(
|
|
544
|
+
{
|
|
545
|
+
id: createStorageErrorId("CLICKHOUSE", "DROP_TABLE", "FAILED"),
|
|
546
|
+
domain: ErrorDomain.STORAGE,
|
|
547
|
+
category: ErrorCategory.THIRD_PARTY,
|
|
548
|
+
details: { tableName }
|
|
549
|
+
},
|
|
550
|
+
error
|
|
551
|
+
);
|
|
552
|
+
} finally {
|
|
553
|
+
this.tableColumnsCache.delete(tableName);
|
|
554
|
+
}
|
|
493
555
|
}
|
|
494
556
|
async insert({ tableName, record }) {
|
|
495
|
-
const rawCreatedAt = record.createdAt || record.created_at || /* @__PURE__ */ new Date();
|
|
496
|
-
const rawUpdatedAt = record.updatedAt || /* @__PURE__ */ new Date();
|
|
497
|
-
const createdAt = rawCreatedAt instanceof Date ? rawCreatedAt.toISOString() : rawCreatedAt;
|
|
498
|
-
const updatedAt = rawUpdatedAt instanceof Date ? rawUpdatedAt.toISOString() : rawUpdatedAt;
|
|
499
557
|
try {
|
|
558
|
+
const filteredRecord = await this.filterRecordToKnownColumns(tableName, record);
|
|
559
|
+
if (Object.keys(filteredRecord).length === 0) return;
|
|
560
|
+
const rawCreatedAt = filteredRecord.createdAt || filteredRecord.created_at || /* @__PURE__ */ new Date();
|
|
561
|
+
const rawUpdatedAt = filteredRecord.updatedAt || /* @__PURE__ */ new Date();
|
|
562
|
+
if ("createdAt" in filteredRecord || (await this.getTableColumns(tableName)).has("createdAt")) {
|
|
563
|
+
filteredRecord.createdAt = rawCreatedAt instanceof Date ? rawCreatedAt.toISOString() : rawCreatedAt;
|
|
564
|
+
}
|
|
565
|
+
if ("updatedAt" in filteredRecord || (await this.getTableColumns(tableName)).has("updatedAt")) {
|
|
566
|
+
filteredRecord.updatedAt = rawUpdatedAt instanceof Date ? rawUpdatedAt.toISOString() : rawUpdatedAt;
|
|
567
|
+
}
|
|
500
568
|
await this.client.insert({
|
|
501
569
|
table: tableName,
|
|
502
|
-
values: [
|
|
503
|
-
{
|
|
504
|
-
...record,
|
|
505
|
-
createdAt,
|
|
506
|
-
updatedAt
|
|
507
|
-
}
|
|
508
|
-
],
|
|
570
|
+
values: [filteredRecord],
|
|
509
571
|
format: "JSONEachRow",
|
|
510
572
|
clickhouse_settings: {
|
|
511
573
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -527,7 +589,7 @@ var ClickhouseDB = class extends MastraBase {
|
|
|
527
589
|
}
|
|
528
590
|
}
|
|
529
591
|
async batchInsert({ tableName, records }) {
|
|
530
|
-
const
|
|
592
|
+
const processedRecords = records.map((record) => ({
|
|
531
593
|
...Object.fromEntries(
|
|
532
594
|
Object.entries(record).map(([key, value]) => [
|
|
533
595
|
key,
|
|
@@ -537,10 +599,15 @@ var ClickhouseDB = class extends MastraBase {
|
|
|
537
599
|
])
|
|
538
600
|
)
|
|
539
601
|
}));
|
|
602
|
+
const recordsToBeInserted = await Promise.all(
|
|
603
|
+
processedRecords.map((r) => this.filterRecordToKnownColumns(tableName, r))
|
|
604
|
+
);
|
|
605
|
+
const nonEmptyRecords = recordsToBeInserted.filter((r) => Object.keys(r).length > 0);
|
|
606
|
+
if (nonEmptyRecords.length === 0) return;
|
|
540
607
|
try {
|
|
541
608
|
await this.client.insert({
|
|
542
609
|
table: tableName,
|
|
543
|
-
values:
|
|
610
|
+
values: nonEmptyRecords,
|
|
544
611
|
format: "JSONEachRow",
|
|
545
612
|
clickhouse_settings: {
|
|
546
613
|
// Allows to insert serialized JS Dates (such as '2023-12-06T10:54:48.000Z')
|
|
@@ -806,6 +873,20 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
|
|
|
806
873
|
}
|
|
807
874
|
const { field, direction } = this.parseOrderBy(orderBy, "ASC");
|
|
808
875
|
dataQuery += ` ORDER BY "${field}" ${direction}`;
|
|
876
|
+
if (perPageForQuery === 0 && (!include || include.length === 0)) {
|
|
877
|
+
return { messages: [], total: 0, page, perPage: perPageForResponse, hasMore: false };
|
|
878
|
+
}
|
|
879
|
+
if (perPageForQuery === 0 && include && include.length > 0) {
|
|
880
|
+
const includeResult = await this._getIncludedMessages({ include });
|
|
881
|
+
const list2 = new MessageList().add(includeResult, "memory");
|
|
882
|
+
return {
|
|
883
|
+
messages: this._sortMessages(list2.get.all.db(), field, direction),
|
|
884
|
+
total: 0,
|
|
885
|
+
page,
|
|
886
|
+
perPage: perPageForResponse,
|
|
887
|
+
hasMore: false
|
|
888
|
+
};
|
|
889
|
+
}
|
|
809
890
|
if (perPageForResponse === false) ; else {
|
|
810
891
|
dataQuery += ` LIMIT {limit:Int64} OFFSET {offset:Int64}`;
|
|
811
892
|
dataParams.limit = perPageForQuery;
|
|
@@ -867,92 +948,17 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
|
|
|
867
948
|
};
|
|
868
949
|
}
|
|
869
950
|
const messageIds = new Set(paginatedMessages.map((m) => m.id));
|
|
870
|
-
let includeMessages = [];
|
|
871
951
|
if (include && include.length > 0) {
|
|
872
|
-
const
|
|
873
|
-
const
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
messageIds
|
|
877
|
-
});
|
|
878
|
-
for (const msg of includeLookup) {
|
|
879
|
-
if (msg.threadId) {
|
|
880
|
-
threadByMessageId.set(msg.id, msg.threadId);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
}
|
|
884
|
-
const unionQueries = [];
|
|
885
|
-
const params = [];
|
|
886
|
-
let paramIdx = 1;
|
|
887
|
-
for (const inc of include) {
|
|
888
|
-
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
889
|
-
const searchThreadId = inc.threadId ?? threadByMessageId.get(id);
|
|
890
|
-
if (!searchThreadId) continue;
|
|
891
|
-
unionQueries.push(`
|
|
892
|
-
SELECT * FROM (
|
|
893
|
-
WITH numbered_messages AS (
|
|
894
|
-
SELECT
|
|
895
|
-
id, content, role, type, "createdAt", thread_id, "resourceId",
|
|
896
|
-
ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
|
|
897
|
-
FROM "${TABLE_MESSAGES}"
|
|
898
|
-
WHERE thread_id = {var_thread_id_${paramIdx}:String}
|
|
899
|
-
),
|
|
900
|
-
target_positions AS (
|
|
901
|
-
SELECT row_num as target_pos
|
|
902
|
-
FROM numbered_messages
|
|
903
|
-
WHERE id = {var_include_id_${paramIdx}:String}
|
|
904
|
-
)
|
|
905
|
-
SELECT DISTINCT m.id, m.content, m.role, m.type, m."createdAt", m.thread_id AS "threadId", m."resourceId"
|
|
906
|
-
FROM numbered_messages m
|
|
907
|
-
CROSS JOIN target_positions t
|
|
908
|
-
WHERE m.row_num BETWEEN (t.target_pos - {var_withPreviousMessages_${paramIdx}:Int64}) AND (t.target_pos + {var_withNextMessages_${paramIdx}:Int64})
|
|
909
|
-
) AS query_${paramIdx}
|
|
910
|
-
`);
|
|
911
|
-
params.push(
|
|
912
|
-
{ [`var_thread_id_${paramIdx}`]: searchThreadId },
|
|
913
|
-
{ [`var_include_id_${paramIdx}`]: id },
|
|
914
|
-
{ [`var_withPreviousMessages_${paramIdx}`]: withPreviousMessages },
|
|
915
|
-
{ [`var_withNextMessages_${paramIdx}`]: withNextMessages }
|
|
916
|
-
);
|
|
917
|
-
paramIdx++;
|
|
918
|
-
}
|
|
919
|
-
if (unionQueries.length > 0) {
|
|
920
|
-
const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
|
|
921
|
-
const mergedParams = params.reduce((acc, paramObj) => ({ ...acc, ...paramObj }), {});
|
|
922
|
-
const includeResult = await this.client.query({
|
|
923
|
-
query: finalQuery,
|
|
924
|
-
query_params: mergedParams,
|
|
925
|
-
clickhouse_settings: {
|
|
926
|
-
date_time_input_format: "best_effort",
|
|
927
|
-
date_time_output_format: "iso",
|
|
928
|
-
use_client_time_zone: 1,
|
|
929
|
-
output_format_json_quote_64bit_integers: 0
|
|
930
|
-
}
|
|
931
|
-
});
|
|
932
|
-
const includeRows = await includeResult.json();
|
|
933
|
-
includeMessages = transformRows(includeRows.data);
|
|
934
|
-
for (const includeMsg of includeMessages) {
|
|
935
|
-
if (!messageIds.has(includeMsg.id)) {
|
|
936
|
-
paginatedMessages.push(includeMsg);
|
|
937
|
-
messageIds.add(includeMsg.id);
|
|
938
|
-
}
|
|
952
|
+
const includeMessages = await this._getIncludedMessages({ include });
|
|
953
|
+
for (const includeMsg of includeMessages) {
|
|
954
|
+
if (!messageIds.has(includeMsg.id)) {
|
|
955
|
+
paginatedMessages.push(includeMsg);
|
|
956
|
+
messageIds.add(includeMsg.id);
|
|
939
957
|
}
|
|
940
958
|
}
|
|
941
959
|
}
|
|
942
960
|
const list = new MessageList().add(paginatedMessages, "memory");
|
|
943
|
-
|
|
944
|
-
finalMessages = finalMessages.sort((a, b) => {
|
|
945
|
-
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
946
|
-
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
947
|
-
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
948
|
-
if (aValue === bValue) {
|
|
949
|
-
return a.id.localeCompare(b.id);
|
|
950
|
-
}
|
|
951
|
-
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
952
|
-
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
953
|
-
}
|
|
954
|
-
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
955
|
-
});
|
|
961
|
+
const finalMessages = this._sortMessages(list.get.all.db(), field, direction);
|
|
956
962
|
const threadIdSet = new Set(threadIds);
|
|
957
963
|
const returnedThreadMessageIds = new Set(
|
|
958
964
|
finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
|
|
@@ -990,6 +996,95 @@ var MemoryStorageClickhouse = class extends MemoryStorage {
|
|
|
990
996
|
};
|
|
991
997
|
}
|
|
992
998
|
}
|
|
999
|
+
_sortMessages(messages, field, direction) {
|
|
1000
|
+
return messages.sort((a, b) => {
|
|
1001
|
+
const isDateField = field === "createdAt" || field === "updatedAt";
|
|
1002
|
+
const aValue = isDateField ? new Date(a[field]).getTime() : a[field];
|
|
1003
|
+
const bValue = isDateField ? new Date(b[field]).getTime() : b[field];
|
|
1004
|
+
if (aValue === bValue) {
|
|
1005
|
+
return a.id.localeCompare(b.id);
|
|
1006
|
+
}
|
|
1007
|
+
if (typeof aValue === "number" && typeof bValue === "number") {
|
|
1008
|
+
return direction === "ASC" ? aValue - bValue : bValue - aValue;
|
|
1009
|
+
}
|
|
1010
|
+
return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
async _getIncludedMessages({
|
|
1014
|
+
include
|
|
1015
|
+
}) {
|
|
1016
|
+
if (!include || include.length === 0) return [];
|
|
1017
|
+
const targetIds = include.map((inc) => inc.id).filter(Boolean);
|
|
1018
|
+
if (targetIds.length === 0) return [];
|
|
1019
|
+
const { messages: targetDocs } = await this.listMessagesById({ messageIds: targetIds });
|
|
1020
|
+
const targetMap = new Map(
|
|
1021
|
+
targetDocs.map((msg) => [msg.id, { threadId: msg.threadId, createdAt: msg.createdAt }])
|
|
1022
|
+
);
|
|
1023
|
+
const unionQueries = [];
|
|
1024
|
+
const params = {};
|
|
1025
|
+
let paramIdx = 1;
|
|
1026
|
+
for (const inc of include) {
|
|
1027
|
+
const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
|
|
1028
|
+
const target = targetMap.get(id);
|
|
1029
|
+
if (!target) continue;
|
|
1030
|
+
const threadParam = `var_thread_${paramIdx}`;
|
|
1031
|
+
const createdAtParam = `var_createdAt_${paramIdx}`;
|
|
1032
|
+
const limitParam = `var_limit_${paramIdx}`;
|
|
1033
|
+
unionQueries.push(`
|
|
1034
|
+
SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"
|
|
1035
|
+
FROM "${TABLE_MESSAGES}"
|
|
1036
|
+
WHERE thread_id = {${threadParam}:String}
|
|
1037
|
+
AND createdAt <= parseDateTime64BestEffort({${createdAtParam}:String}, 3)
|
|
1038
|
+
ORDER BY createdAt DESC, id DESC
|
|
1039
|
+
LIMIT {${limitParam}:Int64}
|
|
1040
|
+
`);
|
|
1041
|
+
params[threadParam] = target.threadId;
|
|
1042
|
+
params[createdAtParam] = target.createdAt;
|
|
1043
|
+
params[limitParam] = withPreviousMessages + 1;
|
|
1044
|
+
paramIdx++;
|
|
1045
|
+
if (withNextMessages > 0) {
|
|
1046
|
+
const threadParam2 = `var_thread_${paramIdx}`;
|
|
1047
|
+
const createdAtParam2 = `var_createdAt_${paramIdx}`;
|
|
1048
|
+
const limitParam2 = `var_limit_${paramIdx}`;
|
|
1049
|
+
unionQueries.push(`
|
|
1050
|
+
SELECT id, content, role, type, "createdAt", thread_id AS "threadId", "resourceId"
|
|
1051
|
+
FROM "${TABLE_MESSAGES}"
|
|
1052
|
+
WHERE thread_id = {${threadParam2}:String}
|
|
1053
|
+
AND createdAt > parseDateTime64BestEffort({${createdAtParam2}:String}, 3)
|
|
1054
|
+
ORDER BY createdAt ASC, id ASC
|
|
1055
|
+
LIMIT {${limitParam2}:Int64}
|
|
1056
|
+
`);
|
|
1057
|
+
params[threadParam2] = target.threadId;
|
|
1058
|
+
params[createdAtParam2] = target.createdAt;
|
|
1059
|
+
params[limitParam2] = withNextMessages;
|
|
1060
|
+
paramIdx++;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (unionQueries.length === 0) return [];
|
|
1064
|
+
let finalQuery;
|
|
1065
|
+
if (unionQueries.length === 1) {
|
|
1066
|
+
finalQuery = unionQueries[0];
|
|
1067
|
+
} else {
|
|
1068
|
+
finalQuery = `SELECT * FROM (${unionQueries.join(" UNION ALL ")}) ORDER BY "createdAt" ASC, id ASC`;
|
|
1069
|
+
}
|
|
1070
|
+
const includeResult = await this.client.query({
|
|
1071
|
+
query: finalQuery,
|
|
1072
|
+
query_params: params,
|
|
1073
|
+
clickhouse_settings: {
|
|
1074
|
+
date_time_input_format: "best_effort",
|
|
1075
|
+
date_time_output_format: "iso",
|
|
1076
|
+
use_client_time_zone: 1,
|
|
1077
|
+
output_format_json_quote_64bit_integers: 0
|
|
1078
|
+
}
|
|
1079
|
+
});
|
|
1080
|
+
const includeRows = await includeResult.json();
|
|
1081
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1082
|
+
return transformRows(includeRows.data).filter((row) => {
|
|
1083
|
+
if (seen.has(row.id)) return false;
|
|
1084
|
+
seen.add(row.id);
|
|
1085
|
+
return true;
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
993
1088
|
async saveMessages(args) {
|
|
994
1089
|
const { messages } = args;
|
|
995
1090
|
if (messages.length === 0) return { messages };
|
|
@@ -1910,6 +2005,11 @@ time for large tables. Please ensure you have a backup before proceeding.
|
|
|
1910
2005
|
});
|
|
1911
2006
|
}
|
|
1912
2007
|
await this.#db.createTable({ tableName: TABLE_SPANS, schema: SPAN_SCHEMA });
|
|
2008
|
+
await this.#db.alterTable({
|
|
2009
|
+
tableName: TABLE_SPANS,
|
|
2010
|
+
schema: SPAN_SCHEMA,
|
|
2011
|
+
ifNotExists: ["requestContext"]
|
|
2012
|
+
});
|
|
1913
2013
|
}
|
|
1914
2014
|
async dangerouslyClearAll() {
|
|
1915
2015
|
await this.#db.clearTable({ tableName: TABLE_SPANS });
|
|
@@ -2182,7 +2282,8 @@ time for large tables. Please ensure you have a backup before proceeding.
|
|
|
2182
2282
|
}
|
|
2183
2283
|
async listTraces(args) {
|
|
2184
2284
|
const { filters, pagination, orderBy } = listTracesArgsSchema.parse(args);
|
|
2185
|
-
const
|
|
2285
|
+
const page = pagination?.page ?? 0;
|
|
2286
|
+
const perPage = pagination?.perPage ?? 10;
|
|
2186
2287
|
try {
|
|
2187
2288
|
const conditions = [`(parentSpanId IS NULL OR parentSpanId = '')`];
|
|
2188
2289
|
const values = {};
|
|
@@ -2329,8 +2430,8 @@ time for large tables. Please ensure you have a backup before proceeding.
|
|
|
2329
2430
|
const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
2330
2431
|
const engine = TABLE_ENGINES[TABLE_SPANS] ?? "MergeTree()";
|
|
2331
2432
|
const finalClause = engine.startsWith("ReplacingMergeTree") ? "FINAL" : "";
|
|
2332
|
-
const sortField = orderBy
|
|
2333
|
-
const sortDirection = orderBy
|
|
2433
|
+
const sortField = orderBy?.field ?? "startedAt";
|
|
2434
|
+
const sortDirection = orderBy?.direction ?? "DESC";
|
|
2334
2435
|
let orderClause;
|
|
2335
2436
|
if (sortField === "endedAt") {
|
|
2336
2437
|
const nullSortValue = sortDirection === "DESC" ? 0 : 1;
|