@mastra/clickhouse 1.18.0-alpha.0 → 1.18.0-alpha.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.
@@ -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.0"
6
+ version: "1.18.0-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.18.0-alpha.0",
2
+ "version": "1.18.0-alpha.1",
3
3
  "package": "@mastra/clickhouse",
4
4
  "exports": {},
5
5
  "modules": {}
package/dist/index.cjs CHANGED
@@ -27,9 +27,9 @@ let _mastra_core_storage = require("@mastra/core/storage");
27
27
  _mastra_core_storage = __toESM(_mastra_core_storage, 1);
28
28
  let _mastra_core_agent = require("@mastra/core/agent");
29
29
  let _mastra_core_base = require("@mastra/core/base");
30
+ let crypto$1 = require("crypto");
30
31
  let _mastra_core_utils = require("@mastra/core/utils");
31
32
  let _mastra_core_features = require("@mastra/core/features");
32
- let crypto$1 = require("crypto");
33
33
  let _mastra_core_evals = require("@mastra/core/evals");
34
34
  //#region src/storage/db/replication.ts
35
35
  const DEFAULT_ZOOKEEPER_PATH = "/clickhouse/tables/{shard}/{database}/{table}";
@@ -4668,18 +4668,79 @@ async function batchCreateFeedback(client, args) {
4668
4668
  clickhouse_settings: CH_INSERT_SETTINGS
4669
4669
  });
4670
4670
  }
4671
- async function updateFeedbackReviewStatus(client, args) {
4672
- const { feedbackId, reviewStatus } = parseUpdateFeedbackReviewStatusArgs(args);
4673
- const existing = await queryJson$2(client, `SELECT * FROM ${TABLE_FEEDBACK_EVENTS} FINAL WHERE feedbackId = {feedbackId:String} LIMIT 1`, { feedbackId });
4674
- if (!existing[0]) throw new _mastra_core_error.MastraError({
4671
+ /**
4672
+ * Delete feedback events by feedbackId via lightweight DELETE. Optional
4673
+ * `organizationId` and `resourceId` values are ANDed into the predicate to
4674
+ * restrict deletion to records with matching scope fields.
4675
+ *
4676
+ * A durable deletion request is recorded before the lightweight delete. The
4677
+ * delete is immediately visible to subsequent reads; physical purge depends on
4678
+ * the table's configured retention TTL. The delta table is intentionally not
4679
+ * touched and expires through its fixed two-day TTL.
4680
+ */
4681
+ async function deleteFeedback(client, args, replication) {
4682
+ if (args.feedbackIds.length === 0) return;
4683
+ await recordDeletionRequest(client, {
4684
+ requestId: (0, crypto$1.randomUUID)(),
4685
+ organizationId: args.organizationId,
4686
+ resourceId: args.resourceId,
4687
+ signal: "feedback",
4688
+ predicateType: "itemIds",
4689
+ predicateValues: [...args.feedbackIds],
4690
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
4691
+ replication
4692
+ });
4693
+ const params = {};
4694
+ const idPlaceholders = [];
4695
+ for (let i = 0; i < args.feedbackIds.length; i++) {
4696
+ const name = `fid_${i}`;
4697
+ params[name] = args.feedbackIds[i];
4698
+ idPlaceholders.push(`{${name}:String}`);
4699
+ }
4700
+ const conditions = [`feedbackId IN (${idPlaceholders.join(", ")})`];
4701
+ if (args.organizationId !== void 0) {
4702
+ conditions.push("organizationId = {delOrganizationId:String}");
4703
+ params.delOrganizationId = args.organizationId;
4704
+ }
4705
+ if (args.resourceId !== void 0) {
4706
+ conditions.push("resourceId = {delResourceId:String}");
4707
+ params.delResourceId = args.resourceId;
4708
+ }
4709
+ await client.command({
4710
+ query: `DELETE FROM ${TABLE_FEEDBACK_EVENTS} WHERE ${conditions.join(" AND ")}`,
4711
+ query_params: params,
4712
+ clickhouse_settings: { lightweight_deletes_sync: isReplicationConfigured(replication) ? "2" : "1" }
4713
+ });
4714
+ }
4715
+ function feedbackNotFoundError(feedbackId) {
4716
+ return new _mastra_core_error.MastraError({
4675
4717
  id: "OBSERVABILITY_UPDATE_FEEDBACK_REVIEW_STATUS_NOT_FOUND",
4676
4718
  domain: _mastra_core_error.ErrorDomain.MASTRA_OBSERVABILITY,
4677
4719
  category: _mastra_core_error.ErrorCategory.USER,
4678
4720
  text: "Feedback record not found",
4679
4721
  details: { feedbackId }
4680
4722
  });
4723
+ }
4724
+ async function hasFeedbackDeletionRequest(client, feedbackId, organizationId, resourceId) {
4725
+ return (await queryJson$2(client, `SELECT 1 AS found FROM ${TABLE_DELETION_REQUESTS} FINAL
4726
+ WHERE signal = 'feedback'
4727
+ AND predicateType = 'itemIds'
4728
+ AND has(predicateValues, {feedbackId:String})
4729
+ AND (organizationId = '' OR organizationId = {organizationId:String})
4730
+ AND (resourceId = '' OR resourceId = {resourceId:String})
4731
+ LIMIT 1`, {
4732
+ feedbackId,
4733
+ organizationId: organizationId ?? "",
4734
+ resourceId: resourceId ?? ""
4735
+ })).length > 0;
4736
+ }
4737
+ async function updateFeedbackReviewStatus(client, args, replication) {
4738
+ 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];
4740
+ if (!existingRow) throw feedbackNotFoundError(feedbackId);
4741
+ if (await hasFeedbackDeletionRequest(client, feedbackId, existingRow.organizationId, existingRow.resourceId)) throw feedbackNotFoundError(feedbackId);
4681
4742
  const updated = rowToFeedbackRecord({
4682
- ...existing[0],
4743
+ ...existingRow,
4683
4744
  reviewStatus
4684
4745
  });
4685
4746
  await client.insert({
@@ -4688,6 +4749,14 @@ async function updateFeedbackReviewStatus(client, args) {
4688
4749
  format: "JSONEachRow",
4689
4750
  clickhouse_settings: CH_INSERT_SETTINGS
4690
4751
  });
4752
+ if (await hasFeedbackDeletionRequest(client, feedbackId, existingRow.organizationId, existingRow.resourceId)) {
4753
+ await deleteFeedback(client, {
4754
+ feedbackIds: [feedbackId],
4755
+ organizationId: existingRow.organizationId ?? void 0,
4756
+ resourceId: existingRow.resourceId ?? void 0
4757
+ }, replication);
4758
+ throw feedbackNotFoundError(feedbackId);
4759
+ }
4691
4760
  return updated;
4692
4761
  }
4693
4762
  async function listFeedback(client, args, strategy) {
@@ -5977,6 +6046,50 @@ async function batchCreateScores(client, args) {
5977
6046
  clickhouse_settings: CH_INSERT_SETTINGS
5978
6047
  });
5979
6048
  }
6049
+ /**
6050
+ * Delete score events by scoreId via lightweight DELETE. Optional
6051
+ * `organizationId` and `resourceId` values are ANDed into the predicate to
6052
+ * restrict deletion to records with matching scope fields.
6053
+ *
6054
+ * A durable deletion request is recorded before the lightweight delete. The
6055
+ * delete is immediately visible to subsequent reads; physical purge depends on
6056
+ * the table's configured retention TTL. The delta table is intentionally not
6057
+ * touched and expires through its fixed two-day TTL.
6058
+ */
6059
+ async function deleteScores(client, args, replication) {
6060
+ if (args.scoreIds.length === 0) return;
6061
+ await recordDeletionRequest(client, {
6062
+ requestId: (0, crypto$1.randomUUID)(),
6063
+ organizationId: args.organizationId,
6064
+ resourceId: args.resourceId,
6065
+ signal: "scores",
6066
+ predicateType: "itemIds",
6067
+ predicateValues: [...args.scoreIds],
6068
+ requestedAt: (/* @__PURE__ */ new Date()).toISOString(),
6069
+ replication
6070
+ });
6071
+ const params = {};
6072
+ const idPlaceholders = [];
6073
+ for (let i = 0; i < args.scoreIds.length; i++) {
6074
+ const name = `sid_${i}`;
6075
+ params[name] = args.scoreIds[i];
6076
+ idPlaceholders.push(`{${name}:String}`);
6077
+ }
6078
+ const conditions = [`scoreId IN (${idPlaceholders.join(", ")})`];
6079
+ if (args.organizationId !== void 0) {
6080
+ conditions.push("organizationId = {delOrganizationId:String}");
6081
+ params.delOrganizationId = args.organizationId;
6082
+ }
6083
+ if (args.resourceId !== void 0) {
6084
+ conditions.push("resourceId = {delResourceId:String}");
6085
+ params.delResourceId = args.resourceId;
6086
+ }
6087
+ await client.command({
6088
+ query: `DELETE FROM ${TABLE_SCORE_EVENTS} WHERE ${conditions.join(" AND ")}`,
6089
+ query_params: params,
6090
+ clickhouse_settings: { lightweight_deletes_sync: isReplicationConfigured(replication) ? "2" : "1" }
6091
+ });
6092
+ }
5980
6093
  async function listScores(client, args, strategy) {
5981
6094
  const parsed = _mastra_core_storage.listScoresArgsSchema.parse(args);
5982
6095
  const deltaCursorEnabled = deltaPollingSupported(strategy);
@@ -7948,6 +8061,19 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7948
8061
  }, error);
7949
8062
  }
7950
8063
  }
8064
+ async deleteScores(args) {
8065
+ try {
8066
+ await deleteScores(this.#client, args, this.#replication);
8067
+ } catch (error) {
8068
+ if (error instanceof _mastra_core_error.MastraError) throw error;
8069
+ throw new _mastra_core_error.MastraError({
8070
+ id: (0, _mastra_core_storage.createStorageErrorId)("CLICKHOUSE", "DELETE_SCORES", "FAILED"),
8071
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
8072
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
8073
+ details: { count: args.scoreIds.length }
8074
+ }, error);
8075
+ }
8076
+ }
7951
8077
  async getScoreById(scoreId) {
7952
8078
  try {
7953
8079
  return await getScoreById(this.#client, scoreId);
@@ -7986,9 +8112,22 @@ var ObservabilityStorageClickhouseVNext = class extends _mastra_core_storage.Obs
7986
8112
  }, error);
7987
8113
  }
7988
8114
  }
8115
+ async deleteFeedback(args) {
8116
+ try {
8117
+ await deleteFeedback(this.#client, args, this.#replication);
8118
+ } catch (error) {
8119
+ if (error instanceof _mastra_core_error.MastraError) throw error;
8120
+ throw new _mastra_core_error.MastraError({
8121
+ id: (0, _mastra_core_storage.createStorageErrorId)("CLICKHOUSE", "DELETE_FEEDBACK", "FAILED"),
8122
+ domain: _mastra_core_error.ErrorDomain.STORAGE,
8123
+ category: _mastra_core_error.ErrorCategory.THIRD_PARTY,
8124
+ details: { count: args.feedbackIds.length }
8125
+ }, error);
8126
+ }
8127
+ }
7989
8128
  async updateFeedbackReviewStatus(args) {
7990
8129
  try {
7991
- return await updateFeedbackReviewStatus(this.#client, args);
8130
+ return await updateFeedbackReviewStatus(this.#client, args, this.#replication);
7992
8131
  } catch (error) {
7993
8132
  if (error instanceof _mastra_core_error.MastraError) throw error;
7994
8133
  throw new _mastra_core_error.MastraError({