@mastra/clickhouse 1.18.0-alpha.1 → 1.18.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.
@@ -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.18.0-alpha.1"
6
+ version: "1.18.0"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.18.0-alpha.1",
2
+ "version": "1.18.0",
3
3
  "package": "@mastra/clickhouse",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -3206,6 +3206,7 @@ CREATE TABLE IF NOT EXISTS ${TABLE_FEEDBACK_EVENTS} (
3206
3206
 
3207
3207
  -- IDs
3208
3208
  feedbackId String,
3209
+ writeVersion UInt64 DEFAULT 0,
3209
3210
  traceId Nullable(String),
3210
3211
  spanId Nullable(String),
3211
3212
  experimentId Nullable(String),
@@ -3493,6 +3494,7 @@ const ALL_MIGRATIONS = [
3493
3494
  addColumn(TABLE_SCORE_EVENTS, "entityVersionId", "Nullable(String)"),
3494
3495
  addColumn(TABLE_SCORE_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3495
3496
  addColumn(TABLE_SCORE_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3497
+ addColumn(TABLE_FEEDBACK_EVENTS, "writeVersion", "UInt64 DEFAULT 0"),
3496
3498
  addColumn(TABLE_FEEDBACK_EVENTS, "entityVersionId", "Nullable(String)"),
3497
3499
  addColumn(TABLE_FEEDBACK_EVENTS, "reviewStatus", "LowCardinality(String) DEFAULT 'needs-review'"),
3498
3500
  addColumn(TABLE_FEEDBACK_EVENTS, "parentEntityVersionId", "Nullable(String)"),
@@ -4656,6 +4658,26 @@ async function queryJson$2(client, query, params) {
4656
4658
  clickhouse_settings: CH_SETTINGS
4657
4659
  })).json();
4658
4660
  }
4661
+ async function feedbackRowsWithWriteVersions(client, feedbacks) {
4662
+ const identifiedFeedback = feedbacks.map((feedback) => ({
4663
+ ...feedback,
4664
+ feedbackId: feedback.feedbackId ?? ""
4665
+ }));
4666
+ const feedbackIds = [...new Set(identifiedFeedback.map((feedback) => feedback.feedbackId))];
4667
+ const existingVersions = await queryJson$2(client, `SELECT feedbackId, toString(max(writeVersion)) AS writeVersion
4668
+ FROM ${TABLE_FEEDBACK_EVENTS}
4669
+ WHERE feedbackId IN ({feedbackIds:Array(String)})
4670
+ GROUP BY feedbackId`, { feedbackIds });
4671
+ const versions = new Map(existingVersions.map((row) => [row.feedbackId, BigInt(row.writeVersion)]));
4672
+ return identifiedFeedback.map((feedback) => {
4673
+ const writeVersion = (versions.get(feedback.feedbackId) ?? 0n) + 1n;
4674
+ versions.set(feedback.feedbackId, writeVersion);
4675
+ return {
4676
+ ...feedbackRecordToRow(feedback),
4677
+ writeVersion: writeVersion.toString()
4678
+ };
4679
+ });
4680
+ }
4659
4681
  async function createFeedback(client, args) {
4660
4682
  await batchCreateFeedback(client, { feedbacks: [args.feedback] });
4661
4683
  }
@@ -4663,7 +4685,7 @@ async function batchCreateFeedback(client, args) {
4663
4685
  if (args.feedbacks.length === 0) return;
4664
4686
  await client.insert({
4665
4687
  table: TABLE_FEEDBACK_EVENTS,
4666
- values: args.feedbacks.map(feedbackRecordToRow),
4688
+ values: await feedbackRowsWithWriteVersions(client, args.feedbacks),
4667
4689
  format: "JSONEachRow",
4668
4690
  clickhouse_settings: CH_INSERT_SETTINGS
4669
4691
  });
@@ -4736,19 +4758,17 @@ async function hasFeedbackDeletionRequest(client, feedbackId, organizationId, re
4736
4758
  }
4737
4759
  async function updateFeedbackReviewStatus(client, args, replication) {
4738
4760
  const { feedbackId, reviewStatus } = parseUpdateFeedbackReviewStatusArgs(args);
4739
- const existingRow = (await queryJson$2(client, `SELECT * FROM ${TABLE_FEEDBACK_EVENTS} FINAL WHERE feedbackId = {feedbackId:String} LIMIT 1`, { feedbackId }))[0];
4761
+ const existingRow = (await queryJson$2(client, `SELECT * FROM ${TABLE_FEEDBACK_EVENTS} FINAL
4762
+ WHERE feedbackId = {feedbackId:String}
4763
+ ORDER BY writeVersion DESC, timestamp DESC
4764
+ LIMIT 1`, { feedbackId }))[0];
4740
4765
  if (!existingRow) throw feedbackNotFoundError(feedbackId);
4741
4766
  if (await hasFeedbackDeletionRequest(client, feedbackId, existingRow.organizationId, existingRow.resourceId)) throw feedbackNotFoundError(feedbackId);
4742
4767
  const updated = rowToFeedbackRecord({
4743
4768
  ...existingRow,
4744
4769
  reviewStatus
4745
4770
  });
4746
- await client.insert({
4747
- table: TABLE_FEEDBACK_EVENTS,
4748
- values: [feedbackRecordToRow(updated)],
4749
- format: "JSONEachRow",
4750
- clickhouse_settings: CH_INSERT_SETTINGS
4751
- });
4771
+ await batchCreateFeedback(client, { feedbacks: [updated] });
4752
4772
  if (await hasFeedbackDeletionRequest(client, feedbackId, existingRow.organizationId, existingRow.resourceId)) {
4753
4773
  await deleteFeedback(client, {
4754
4774
  feedbackIds: [feedbackId],
@@ -6460,6 +6480,44 @@ const SCORE_FIELDS = {
6460
6480
  parameterType: "String"
6461
6481
  }
6462
6482
  };
6483
+ const FEEDBACK_FIELDS = {
6484
+ feedbackType: {
6485
+ sql: "s.feedbackType",
6486
+ parameterType: "String"
6487
+ },
6488
+ feedbackSource: {
6489
+ sql: "s.feedbackSource",
6490
+ parameterType: "String"
6491
+ },
6492
+ feedbackUserId: {
6493
+ sql: "s.feedbackUserId",
6494
+ parameterType: "String"
6495
+ },
6496
+ sourceId: {
6497
+ sql: "s.sourceId",
6498
+ parameterType: "String"
6499
+ },
6500
+ entityVersionId: {
6501
+ sql: "s.entityVersionId",
6502
+ parameterType: "String"
6503
+ },
6504
+ parentEntityVersionId: {
6505
+ sql: "s.parentEntityVersionId",
6506
+ parameterType: "String"
6507
+ },
6508
+ rootEntityVersionId: {
6509
+ sql: "s.rootEntityVersionId",
6510
+ parameterType: "String"
6511
+ },
6512
+ timestamp: {
6513
+ sql: "s.timestamp",
6514
+ parameterType: "DateTime64(3, 'UTC')"
6515
+ },
6516
+ comment: {
6517
+ sql: "s.comment",
6518
+ parameterType: "String"
6519
+ }
6520
+ };
6463
6521
  const TRACE_SELECT = `
6464
6522
  r.traceId AS traceId,
6465
6523
  r.spanId AS rootSpanId,
@@ -6520,6 +6578,22 @@ function compileScalarPredicate(predicate, registry, parameters, allowMetadata =
6520
6578
  if (operator === void 0) throw new Error(`Unsupported trusted trace-query operator: ${predicate.operator}`);
6521
6579
  return `ifNull(${field.sql} ${operator} ${parameter}, ${predicate.operator === "ne" ? "1" : "0"})`;
6522
6580
  }
6581
+ function compileFeedbackScalarPredicate(predicate, parameters) {
6582
+ if (predicate.type === "boolean") return predicate.args.map((arg) => `(${compileFeedbackScalarPredicate(arg, parameters)})`).join(predicate.operator === "and" ? " AND " : " OR ");
6583
+ if (predicate.type === "not") return `NOT (${compileFeedbackScalarPredicate(predicate.arg, parameters)})`;
6584
+ if (predicate.field !== "value") return compileScalarPredicate(predicate, FEEDBACK_FIELDS, parameters);
6585
+ if (predicate.type === "presence") {
6586
+ const present = `(isNotNull(s.valueString) OR isNotNull(s.valueNumber))`;
6587
+ return predicate.operator === "exists" ? present : `NOT ${present}`;
6588
+ }
6589
+ return compileScalarPredicate(predicate, typeof (predicate.type === "membership" ? predicate.values[0] : predicate.value) === "number" ? { value: {
6590
+ sql: "s.valueNumber",
6591
+ parameterType: "Float64"
6592
+ } } : { value: {
6593
+ sql: "s.valueString",
6594
+ parameterType: "String"
6595
+ } }, parameters);
6596
+ }
6523
6597
  function collectRelationCollections(predicate, collections = /* @__PURE__ */ new Set()) {
6524
6598
  if (!predicate) return collections;
6525
6599
  if (predicate.type === "relation") collections.add(predicate.collection);
@@ -6529,11 +6603,11 @@ function collectRelationCollections(predicate, collections = /* @__PURE__ */ new
6529
6603
  }
6530
6604
  function compilePredicate(predicate, parameters) {
6531
6605
  if (predicate.type === "relation") {
6532
- const registry = predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS;
6533
6606
  const existence = `EXISTS (
6534
- SELECT 1 FROM ${predicate.collection === "spans" ? "current_spans" : "current_scores"} s
6535
- WHERE s.traceId = r.traceId
6536
- AND (${compileScalarPredicate(predicate.predicate, registry, parameters)})
6607
+ SELECT 1 FROM ${predicate.collection === "spans" ? "current_spans" : predicate.collection === "scores" ? "current_scores" : "current_feedback"} s
6608
+ WHERE isNotNull(s.traceId)
6609
+ AND s.traceId = r.traceId
6610
+ AND (${predicate.collection === "feedback" ? compileFeedbackScalarPredicate(predicate.predicate, parameters) : compileScalarPredicate(predicate.predicate, predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS, parameters)})
6537
6611
  )`;
6538
6612
  return predicate.quantifier === "some" ? existence : `NOT ${existence}`;
6539
6613
  }
@@ -6602,6 +6676,29 @@ function compileClickHouseTraceQuery(plan) {
6602
6676
  AND traceId IN (SELECT traceId FROM root_scope)
6603
6677
  ORDER BY scoreId, timestamp DESC
6604
6678
  LIMIT 1 BY scoreId
6679
+ )`);
6680
+ if (relationCollections.has("feedback")) ctes.push(`current_feedback AS (
6681
+ SELECT
6682
+ traceId,
6683
+ feedbackType,
6684
+ feedbackSource,
6685
+ feedbackUserId,
6686
+ sourceId,
6687
+ valueString,
6688
+ valueNumber,
6689
+ comment,
6690
+ timestamp,
6691
+ entityVersionId,
6692
+ parentEntityVersionId,
6693
+ rootEntityVersionId
6694
+ FROM (
6695
+ SELECT *
6696
+ FROM ${TABLE_FEEDBACK_EVENTS} FINAL
6697
+ ORDER BY feedbackId, writeVersion DESC, timestamp DESC
6698
+ LIMIT 1 BY feedbackId
6699
+ ) AS current
6700
+ WHERE isNotNull(traceId)
6701
+ AND traceId IN (SELECT traceId FROM root_scope)
6605
6702
  )`);
6606
6703
  const predicate = plan.where ? compilePredicate(plan.where, parameters) : "1";
6607
6704
  ctes.push(`candidates AS (