@mastra/clickhouse 1.20.0 → 1.20.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/index.cjs +72 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +72 -17
- package/dist/index.js.map +1 -1
- package/dist/storage/domains/observability/v-next/ddl.d.ts +1 -0
- package/dist/storage/domains/observability/v-next/ddl.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/index.d.ts +15 -0
- package/dist/storage/domains/observability/v-next/index.d.ts.map +1 -1
- package/dist/storage/domains/observability/v-next/scores.d.ts.map +1 -1
- package/package.json +5 -5
package/dist/docs/SKILL.md
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -3223,7 +3223,8 @@ CREATE TABLE IF NOT EXISTS ${TABLE_SCORE_EVENTS_DELTA} (
|
|
|
3223
3223
|
ingestedAt ${DELTA_INGESTED_AT_TYPE},
|
|
3224
3224
|
traceId Nullable(String),
|
|
3225
3225
|
timestamp DateTime64(3, 'UTC'),
|
|
3226
|
-
scoreId String
|
|
3226
|
+
scoreId String,
|
|
3227
|
+
INDEX idx_scoreId scoreId TYPE bloom_filter(0.01) GRANULARITY 1
|
|
3227
3228
|
)
|
|
3228
3229
|
ENGINE = MergeTree
|
|
3229
3230
|
PARTITION BY toDate(ingestedAt)
|
|
@@ -3232,12 +3233,8 @@ TTL ingestedAt + toIntervalDay(2)
|
|
|
3232
3233
|
SETTINGS allow_nullable_key = 1
|
|
3233
3234
|
`;
|
|
3234
3235
|
}
|
|
3235
|
-
function
|
|
3236
|
-
return `
|
|
3237
|
-
CREATE MATERIALIZED VIEW IF NOT EXISTS ${MV_SCORE_EVENTS_DELTA}
|
|
3238
|
-
TO ${TABLE_SCORE_EVENTS_DELTA}
|
|
3239
|
-
AS
|
|
3240
|
-
SELECT
|
|
3236
|
+
function buildScoreEventsDeltaMvQuery(strategy) {
|
|
3237
|
+
return `SELECT
|
|
3241
3238
|
${buildDeltaCursorExpr(strategy, "mastra_score_events_delta_cursor", "scoreId")} AS cursorId,
|
|
3242
3239
|
ingestedAt,
|
|
3243
3240
|
traceId,
|
|
@@ -3250,7 +3247,19 @@ FROM (
|
|
|
3250
3247
|
timestamp,
|
|
3251
3248
|
scoreId
|
|
3252
3249
|
FROM ${TABLE_SCORE_EVENTS}
|
|
3253
|
-
|
|
3250
|
+
WHERE scoreId NOT IN (
|
|
3251
|
+
SELECT scoreId FROM ${TABLE_SCORE_EVENTS_DELTA}
|
|
3252
|
+
WHERE scoreId IN (SELECT scoreId FROM ${TABLE_SCORE_EVENTS})
|
|
3253
|
+
)
|
|
3254
|
+
LIMIT 1 BY scoreId
|
|
3255
|
+
)`;
|
|
3256
|
+
}
|
|
3257
|
+
function buildScoreEventsDeltaMvDDL(strategy) {
|
|
3258
|
+
return `
|
|
3259
|
+
CREATE MATERIALIZED VIEW IF NOT EXISTS ${MV_SCORE_EVENTS_DELTA}
|
|
3260
|
+
TO ${TABLE_SCORE_EVENTS_DELTA}
|
|
3261
|
+
AS
|
|
3262
|
+
${buildScoreEventsDeltaMvQuery(strategy)}
|
|
3254
3263
|
`;
|
|
3255
3264
|
}
|
|
3256
3265
|
const FEEDBACK_EVENTS_DDL = `
|
|
@@ -3559,6 +3568,7 @@ const ALL_MIGRATIONS = [
|
|
|
3559
3568
|
addColumn(TABLE_SCORE_EVENTS, "parentEntityVersionId", "Nullable(String)"),
|
|
3560
3569
|
addColumn(TABLE_SCORE_EVENTS, "rootEntityVersionId", "Nullable(String)"),
|
|
3561
3570
|
addBloomIndex(TABLE_SCORE_EVENTS, "idx_scoreId", "scoreId", 1),
|
|
3571
|
+
addBloomIndex(TABLE_SCORE_EVENTS_DELTA, "idx_scoreId", "scoreId", 1),
|
|
3562
3572
|
addColumn(TABLE_FEEDBACK_EVENTS, "writeVersion", "UInt64 DEFAULT 0"),
|
|
3563
3573
|
addColumn(TABLE_FEEDBACK_EVENTS, "entityVersionId", "Nullable(String)"),
|
|
3564
3574
|
addColumn(TABLE_FEEDBACK_EVENTS, "reviewStatus", "LowCardinality(String) DEFAULT 'needs-review'"),
|
|
@@ -6308,6 +6318,17 @@ async function listScores(client, args, strategy) {
|
|
|
6308
6318
|
...deltaCursorEnabled ? { deltaCursor: currentDeltaCursor } : {}
|
|
6309
6319
|
};
|
|
6310
6320
|
}
|
|
6321
|
+
/**
|
|
6322
|
+
* Delta reads join the delta stream to the current-state table by scoreId, so
|
|
6323
|
+
* a poll or replay always returns the latest write of a score (a rewrite may
|
|
6324
|
+
* change traceId or timestamp, which the delta row does not track).
|
|
6325
|
+
*
|
|
6326
|
+
* A score's first delta row is its only cursor: rows after `afterCursor` are
|
|
6327
|
+
* dropped when the same scoreId already has a row at or before it, and
|
|
6328
|
+
* `LIMIT 1 BY` keeps the lowest cursor within the page. Duplicate delta rows
|
|
6329
|
+
* (a concurrent-insert race past the MV check) therefore never surface, in
|
|
6330
|
+
* this poll or a later one.
|
|
6331
|
+
*/
|
|
6311
6332
|
async function queryScoresAfterCursor(client, whereClause, params, limit, cursorId) {
|
|
6312
6333
|
return await queryJson(client, `
|
|
6313
6334
|
SELECT
|
|
@@ -6317,12 +6338,16 @@ async function queryScoresAfterCursor(client, whereClause, params, limit, cursor
|
|
|
6317
6338
|
s.scoreId AS scoreId,
|
|
6318
6339
|
toString(d.cursorId) AS cursorId
|
|
6319
6340
|
FROM ${TABLE_SCORE_EVENTS_DELTA} d
|
|
6320
|
-
INNER JOIN ${
|
|
6321
|
-
ON
|
|
6322
|
-
|
|
6323
|
-
|
|
6324
|
-
|
|
6341
|
+
INNER JOIN ${TABLE_SCORE_EVENTS_CURRENT} s FINAL
|
|
6342
|
+
ON s.scoreId = d.scoreId
|
|
6343
|
+
${whereClause ? `${whereClause} AND` : "WHERE"} d.cursorId > {afterCursor:UInt64}
|
|
6344
|
+
AND d.scoreId NOT IN (
|
|
6345
|
+
SELECT scoreId FROM ${TABLE_SCORE_EVENTS_DELTA}
|
|
6346
|
+
WHERE cursorId <= {afterCursor:UInt64}
|
|
6347
|
+
AND scoreId IN (SELECT scoreId FROM ${TABLE_SCORE_EVENTS_DELTA} WHERE cursorId > {afterCursor:UInt64})
|
|
6348
|
+
)
|
|
6325
6349
|
ORDER BY d.cursorId ASC
|
|
6350
|
+
LIMIT 1 BY s.scoreId
|
|
6326
6351
|
LIMIT {fetchLimit:UInt32}
|
|
6327
6352
|
`, {
|
|
6328
6353
|
...params,
|
|
@@ -6334,10 +6359,8 @@ async function getDeltaCursor$2(client, whereClause, params) {
|
|
|
6334
6359
|
const cursorId = (await queryJson(client, `
|
|
6335
6360
|
SELECT toString(max(d.cursorId)) AS cursorId
|
|
6336
6361
|
FROM mastra_score_events_delta d
|
|
6337
|
-
INNER JOIN
|
|
6338
|
-
ON
|
|
6339
|
-
AND s.timestamp = d.timestamp
|
|
6340
|
-
AND s.scoreId = d.scoreId
|
|
6362
|
+
INNER JOIN mastra_score_events_current s FINAL
|
|
6363
|
+
ON s.scoreId = d.scoreId
|
|
6341
6364
|
${whereClause}
|
|
6342
6365
|
`, params))[0]?.cursorId ?? null;
|
|
6343
6366
|
if (cursorId) return cursorId;
|
|
@@ -8307,6 +8330,37 @@ async function queryNamesByTable(client, query, tables) {
|
|
|
8307
8330
|
}
|
|
8308
8331
|
return out;
|
|
8309
8332
|
}
|
|
8333
|
+
/**
|
|
8334
|
+
* Upgrades a score delta MV created before per-scoreId deduplication with
|
|
8335
|
+
* `ALTER TABLE ... MODIFY QUERY`. The view is changed in place, so there is no
|
|
8336
|
+
* window without a view in which score writes would miss their delta row (a
|
|
8337
|
+
* drop-and-recreate would leave such writes out of delta polling for good).
|
|
8338
|
+
*
|
|
8339
|
+
* With a cluster configured the definition is read from every replica via
|
|
8340
|
+
* `clusterAllReplicas`, since each host stores its own copy of the view; a
|
|
8341
|
+
* single legacy copy is enough to alter `ON CLUSTER`.
|
|
8342
|
+
*
|
|
8343
|
+
* Introspection failures are logged and skipped, like the other schema checks
|
|
8344
|
+
* in init(): the existing view keeps working and the next boot retries.
|
|
8345
|
+
*/
|
|
8346
|
+
async function reconcileScoreDeltaMv(client, replication, strategy, logger) {
|
|
8347
|
+
const cluster = replication?.cluster?.trim();
|
|
8348
|
+
let createQueries;
|
|
8349
|
+
try {
|
|
8350
|
+
createQueries = (await (await client.query({
|
|
8351
|
+
query: cluster ? `SELECT create_table_query FROM clusterAllReplicas({cluster:String}, system.tables) WHERE database = currentDatabase() AND name = {name:String}` : `SELECT create_table_query FROM system.tables WHERE database = currentDatabase() AND name = {name:String}`,
|
|
8352
|
+
query_params: cluster ? {
|
|
8353
|
+
cluster,
|
|
8354
|
+
name: MV_SCORE_EVENTS_DELTA
|
|
8355
|
+
} : { name: MV_SCORE_EVENTS_DELTA },
|
|
8356
|
+
format: "JSONEachRow"
|
|
8357
|
+
})).json()).map((row) => row.create_table_query ?? "");
|
|
8358
|
+
} catch (error) {
|
|
8359
|
+
logger?.warn?.(`Could not verify the ${MV_SCORE_EVENTS_DELTA} definition; leaving the existing view in place: ${error instanceof Error ? error.message : String(error)}`);
|
|
8360
|
+
return;
|
|
8361
|
+
}
|
|
8362
|
+
if (createQueries.some((createQuery) => createQuery.length > 0 && !/NOT IN/i.test(createQuery))) await client.command({ query: addOnClusterToDDL(`ALTER TABLE ${MV_SCORE_EVENTS_DELTA} MODIFY QUERY ${buildScoreEventsDeltaMvQuery(strategy)}`, replication) });
|
|
8363
|
+
}
|
|
8310
8364
|
async function detectDeltaCursorStrategy(client, override, existingStrategy) {
|
|
8311
8365
|
if (override) return override;
|
|
8312
8366
|
if (existingStrategy && existingStrategy !== "mixed") return existingStrategy;
|
|
@@ -8416,6 +8470,7 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
|
|
|
8416
8470
|
for (const migration of pendingMigrations) await this.#client.command({ query: addOnClusterToDDL(migration.sql, this.#replication) });
|
|
8417
8471
|
const coreMvDdl = this.#deltaCursorStrategy === null ? BASE_MV_DDL : buildAllMvDDL(this.#deltaCursorStrategy);
|
|
8418
8472
|
for (const ddl of coreMvDdl) await this.#client.command({ query: applyReplicationToDDL(ddl, this.#replication) });
|
|
8473
|
+
if (this.#deltaCursorStrategy !== null) await reconcileScoreDeltaMv(this.#client, this.#replication, this.#deltaCursorStrategy, this.logger);
|
|
8419
8474
|
await backfillCurrentScores(this.#client);
|
|
8420
8475
|
if (this.#retention) await this.applyRetention();
|
|
8421
8476
|
if (this.#deltaCursorStrategy === "serial") for (const counterName of DELTA_CURSOR_COUNTER_NAMES) await this.#client.query({
|