@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.
package/dist/index.js CHANGED
@@ -3183,6 +3183,7 @@ CREATE TABLE IF NOT EXISTS ${TABLE_FEEDBACK_EVENTS} (
3183
3183
 
3184
3184
  -- IDs
3185
3185
  feedbackId String,
3186
+ writeVersion UInt64 DEFAULT 0,
3186
3187
  traceId Nullable(String),
3187
3188
  spanId Nullable(String),
3188
3189
  experimentId Nullable(String),
@@ -3470,6 +3471,7 @@ const ALL_MIGRATIONS = [
3470
3471
  addColumn(TABLE_SCORE_EVENTS, "entityVersionId", "Nullable(String)"),
3471
3472
  addColumn(TABLE_SCORE_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3472
3473
  addColumn(TABLE_SCORE_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3474
+ addColumn(TABLE_FEEDBACK_EVENTS, "writeVersion", "UInt64 DEFAULT 0"),
3473
3475
  addColumn(TABLE_FEEDBACK_EVENTS, "entityVersionId", "Nullable(String)"),
3474
3476
  addColumn(TABLE_FEEDBACK_EVENTS, "reviewStatus", "LowCardinality(String) DEFAULT 'needs-review'"),
3475
3477
  addColumn(TABLE_FEEDBACK_EVENTS, "parentEntityVersionId", "Nullable(String)"),
@@ -4633,6 +4635,26 @@ async function queryJson$2(client, query, params) {
4633
4635
  clickhouse_settings: CH_SETTINGS
4634
4636
  })).json();
4635
4637
  }
4638
+ async function feedbackRowsWithWriteVersions(client, feedbacks) {
4639
+ const identifiedFeedback = feedbacks.map((feedback) => ({
4640
+ ...feedback,
4641
+ feedbackId: feedback.feedbackId ?? ""
4642
+ }));
4643
+ const feedbackIds = [...new Set(identifiedFeedback.map((feedback) => feedback.feedbackId))];
4644
+ const existingVersions = await queryJson$2(client, `SELECT feedbackId, toString(max(writeVersion)) AS writeVersion
4645
+ FROM ${TABLE_FEEDBACK_EVENTS}
4646
+ WHERE feedbackId IN ({feedbackIds:Array(String)})
4647
+ GROUP BY feedbackId`, { feedbackIds });
4648
+ const versions = new Map(existingVersions.map((row) => [row.feedbackId, BigInt(row.writeVersion)]));
4649
+ return identifiedFeedback.map((feedback) => {
4650
+ const writeVersion = (versions.get(feedback.feedbackId) ?? 0n) + 1n;
4651
+ versions.set(feedback.feedbackId, writeVersion);
4652
+ return {
4653
+ ...feedbackRecordToRow(feedback),
4654
+ writeVersion: writeVersion.toString()
4655
+ };
4656
+ });
4657
+ }
4636
4658
  async function createFeedback(client, args) {
4637
4659
  await batchCreateFeedback(client, { feedbacks: [args.feedback] });
4638
4660
  }
@@ -4640,7 +4662,7 @@ async function batchCreateFeedback(client, args) {
4640
4662
  if (args.feedbacks.length === 0) return;
4641
4663
  await client.insert({
4642
4664
  table: TABLE_FEEDBACK_EVENTS,
4643
- values: args.feedbacks.map(feedbackRecordToRow),
4665
+ values: await feedbackRowsWithWriteVersions(client, args.feedbacks),
4644
4666
  format: "JSONEachRow",
4645
4667
  clickhouse_settings: CH_INSERT_SETTINGS
4646
4668
  });
@@ -4713,19 +4735,17 @@ async function hasFeedbackDeletionRequest(client, feedbackId, organizationId, re
4713
4735
  }
4714
4736
  async function updateFeedbackReviewStatus(client, args, replication) {
4715
4737
  const { feedbackId, reviewStatus } = parseUpdateFeedbackReviewStatusArgs(args);
4716
- const existingRow = (await queryJson$2(client, `SELECT * FROM ${TABLE_FEEDBACK_EVENTS} FINAL WHERE feedbackId = {feedbackId:String} LIMIT 1`, { feedbackId }))[0];
4738
+ const existingRow = (await queryJson$2(client, `SELECT * FROM ${TABLE_FEEDBACK_EVENTS} FINAL
4739
+ WHERE feedbackId = {feedbackId:String}
4740
+ ORDER BY writeVersion DESC, timestamp DESC
4741
+ LIMIT 1`, { feedbackId }))[0];
4717
4742
  if (!existingRow) throw feedbackNotFoundError(feedbackId);
4718
4743
  if (await hasFeedbackDeletionRequest(client, feedbackId, existingRow.organizationId, existingRow.resourceId)) throw feedbackNotFoundError(feedbackId);
4719
4744
  const updated = rowToFeedbackRecord({
4720
4745
  ...existingRow,
4721
4746
  reviewStatus
4722
4747
  });
4723
- await client.insert({
4724
- table: TABLE_FEEDBACK_EVENTS,
4725
- values: [feedbackRecordToRow(updated)],
4726
- format: "JSONEachRow",
4727
- clickhouse_settings: CH_INSERT_SETTINGS
4728
- });
4748
+ await batchCreateFeedback(client, { feedbacks: [updated] });
4729
4749
  if (await hasFeedbackDeletionRequest(client, feedbackId, existingRow.organizationId, existingRow.resourceId)) {
4730
4750
  await deleteFeedback(client, {
4731
4751
  feedbackIds: [feedbackId],
@@ -6437,6 +6457,44 @@ const SCORE_FIELDS = {
6437
6457
  parameterType: "String"
6438
6458
  }
6439
6459
  };
6460
+ const FEEDBACK_FIELDS = {
6461
+ feedbackType: {
6462
+ sql: "s.feedbackType",
6463
+ parameterType: "String"
6464
+ },
6465
+ feedbackSource: {
6466
+ sql: "s.feedbackSource",
6467
+ parameterType: "String"
6468
+ },
6469
+ feedbackUserId: {
6470
+ sql: "s.feedbackUserId",
6471
+ parameterType: "String"
6472
+ },
6473
+ sourceId: {
6474
+ sql: "s.sourceId",
6475
+ parameterType: "String"
6476
+ },
6477
+ entityVersionId: {
6478
+ sql: "s.entityVersionId",
6479
+ parameterType: "String"
6480
+ },
6481
+ parentEntityVersionId: {
6482
+ sql: "s.parentEntityVersionId",
6483
+ parameterType: "String"
6484
+ },
6485
+ rootEntityVersionId: {
6486
+ sql: "s.rootEntityVersionId",
6487
+ parameterType: "String"
6488
+ },
6489
+ timestamp: {
6490
+ sql: "s.timestamp",
6491
+ parameterType: "DateTime64(3, 'UTC')"
6492
+ },
6493
+ comment: {
6494
+ sql: "s.comment",
6495
+ parameterType: "String"
6496
+ }
6497
+ };
6440
6498
  const TRACE_SELECT = `
6441
6499
  r.traceId AS traceId,
6442
6500
  r.spanId AS rootSpanId,
@@ -6497,6 +6555,22 @@ function compileScalarPredicate(predicate, registry, parameters, allowMetadata =
6497
6555
  if (operator === void 0) throw new Error(`Unsupported trusted trace-query operator: ${predicate.operator}`);
6498
6556
  return `ifNull(${field.sql} ${operator} ${parameter}, ${predicate.operator === "ne" ? "1" : "0"})`;
6499
6557
  }
6558
+ function compileFeedbackScalarPredicate(predicate, parameters) {
6559
+ if (predicate.type === "boolean") return predicate.args.map((arg) => `(${compileFeedbackScalarPredicate(arg, parameters)})`).join(predicate.operator === "and" ? " AND " : " OR ");
6560
+ if (predicate.type === "not") return `NOT (${compileFeedbackScalarPredicate(predicate.arg, parameters)})`;
6561
+ if (predicate.field !== "value") return compileScalarPredicate(predicate, FEEDBACK_FIELDS, parameters);
6562
+ if (predicate.type === "presence") {
6563
+ const present = `(isNotNull(s.valueString) OR isNotNull(s.valueNumber))`;
6564
+ return predicate.operator === "exists" ? present : `NOT ${present}`;
6565
+ }
6566
+ return compileScalarPredicate(predicate, typeof (predicate.type === "membership" ? predicate.values[0] : predicate.value) === "number" ? { value: {
6567
+ sql: "s.valueNumber",
6568
+ parameterType: "Float64"
6569
+ } } : { value: {
6570
+ sql: "s.valueString",
6571
+ parameterType: "String"
6572
+ } }, parameters);
6573
+ }
6500
6574
  function collectRelationCollections(predicate, collections = /* @__PURE__ */ new Set()) {
6501
6575
  if (!predicate) return collections;
6502
6576
  if (predicate.type === "relation") collections.add(predicate.collection);
@@ -6506,11 +6580,11 @@ function collectRelationCollections(predicate, collections = /* @__PURE__ */ new
6506
6580
  }
6507
6581
  function compilePredicate(predicate, parameters) {
6508
6582
  if (predicate.type === "relation") {
6509
- const registry = predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS;
6510
6583
  const existence = `EXISTS (
6511
- SELECT 1 FROM ${predicate.collection === "spans" ? "current_spans" : "current_scores"} s
6512
- WHERE s.traceId = r.traceId
6513
- AND (${compileScalarPredicate(predicate.predicate, registry, parameters)})
6584
+ SELECT 1 FROM ${predicate.collection === "spans" ? "current_spans" : predicate.collection === "scores" ? "current_scores" : "current_feedback"} s
6585
+ WHERE isNotNull(s.traceId)
6586
+ AND s.traceId = r.traceId
6587
+ AND (${predicate.collection === "feedback" ? compileFeedbackScalarPredicate(predicate.predicate, parameters) : compileScalarPredicate(predicate.predicate, predicate.collection === "spans" ? SPAN_FIELDS : SCORE_FIELDS, parameters)})
6514
6588
  )`;
6515
6589
  return predicate.quantifier === "some" ? existence : `NOT ${existence}`;
6516
6590
  }
@@ -6579,6 +6653,29 @@ function compileClickHouseTraceQuery(plan) {
6579
6653
  AND traceId IN (SELECT traceId FROM root_scope)
6580
6654
  ORDER BY scoreId, timestamp DESC
6581
6655
  LIMIT 1 BY scoreId
6656
+ )`);
6657
+ if (relationCollections.has("feedback")) ctes.push(`current_feedback AS (
6658
+ SELECT
6659
+ traceId,
6660
+ feedbackType,
6661
+ feedbackSource,
6662
+ feedbackUserId,
6663
+ sourceId,
6664
+ valueString,
6665
+ valueNumber,
6666
+ comment,
6667
+ timestamp,
6668
+ entityVersionId,
6669
+ parentEntityVersionId,
6670
+ rootEntityVersionId
6671
+ FROM (
6672
+ SELECT *
6673
+ FROM ${TABLE_FEEDBACK_EVENTS} FINAL
6674
+ ORDER BY feedbackId, writeVersion DESC, timestamp DESC
6675
+ LIMIT 1 BY feedbackId
6676
+ ) AS current
6677
+ WHERE isNotNull(traceId)
6678
+ AND traceId IN (SELECT traceId FROM root_scope)
6582
6679
  )`);
6583
6680
  const predicate = plan.where ? compilePredicate(plan.where, parameters) : "1";
6584
6681
  ctes.push(`candidates AS (