@mastra/clickhouse 1.7.1-alpha.0 → 1.7.1-alpha.2

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 CHANGED
@@ -1,5 +1,33 @@
1
1
  # @mastra/clickhouse
2
2
 
3
+ ## 1.7.1-alpha.2
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed agent streams intermittently hanging when observability storage was backed by Replicated/Shared ClickHouse. Startup no longer re-applies no-op schema updates (e.g. `ADD COLUMN IF NOT EXISTS`, `ADD INDEX IF NOT EXISTS`, `MODIFY TTL`), so it no longer triggers replica-lag retry errors that could leave storage in a stuck state. ([#16420](https://github.com/mastra-ai/mastra/pull/16420))
8
+
9
+ - Updated dependencies [[`7ad5585`](https://github.com/mastra-ai/mastra/commit/7ad55856406f1de398dc713f6a9eaa78b2784bb6), [`210ea7a`](https://github.com/mastra-ai/mastra/commit/210ea7af559791b73a44fc9c12179908aaa3183f), [`83218c8`](https://github.com/mastra-ai/mastra/commit/83218c88b37773c9424fbe733b37be556e55e94d), [`265ec9f`](https://github.com/mastra-ai/mastra/commit/265ec9f887b5c81255c873a76ff7796f16e4f99b), [`6ce80bf`](https://github.com/mastra-ai/mastra/commit/6ce80bf4872a891e0bddf8b80561a80584efb14b), [`9268531`](https://github.com/mastra-ai/mastra/commit/9268531e7ec4be98beeba3b3ae8be0a7ea380662), [`13ead79`](https://github.com/mastra-ai/mastra/commit/13ead79149486b88144db7e11e6ff551caef5be1), [`bd36d8e`](https://github.com/mastra-ai/mastra/commit/bd36d8eb6de8c9a0310352649dbd4b06703c2299), [`8ac9141`](https://github.com/mastra-ai/mastra/commit/8ac9141439caa8fdd674944c4d84f29b3c730296)]:
10
+ - @mastra/core@1.33.0-alpha.10
11
+
12
+ ## 1.7.1-alpha.1
13
+
14
+ ### Patch Changes
15
+
16
+ - Respect optional `resourceId` in `getThreadById` so scoped thread lookups return `null` when the thread belongs to a different resource. ([#14237](https://github.com/mastra-ai/mastra/pull/14237))
17
+
18
+ Example:
19
+
20
+ ```typescript
21
+ const thread = await memory.getThreadById({
22
+ threadId: 'my-thread-id',
23
+ resourceId: 'my-user-id',
24
+ });
25
+ // Returns null if the thread does not belong to 'my-user-id'.
26
+ ```
27
+
28
+ - Updated dependencies [[`7c275a8`](https://github.com/mastra-ai/mastra/commit/7c275a810595e1a6c41ccc39720531ab65734700), [`890b24c`](https://github.com/mastra-ai/mastra/commit/890b24cc7d32ed6aa4dfe253e54dc6bf4099f690), [`0f48ebf`](https://github.com/mastra-ai/mastra/commit/0f48ebfc7ac7897b2092a189f45751924cf56d1c), [`f180e49`](https://github.com/mastra-ai/mastra/commit/f180e4990e71b04c9a475b523584071712f0048f), [`9260e01`](https://github.com/mastra-ai/mastra/commit/9260e015276fb1b500f7878ee452b47476bf1583), [`2f6c54e`](https://github.com/mastra-ai/mastra/commit/2f6c54e17c041cac1def54baaa6b771647836414), [`e06a159`](https://github.com/mastra-ai/mastra/commit/e06a1598ca07a6c3778aefc2a2d288363c6294ff), [`db34bc6`](https://github.com/mastra-ai/mastra/commit/db34bc6fb36cf125bda0c46be4d3fdc774b70cc4)]:
29
+ - @mastra/core@1.33.0-alpha.8
30
+
3
31
  ## 1.7.1-alpha.0
4
32
 
5
33
  ### Patch Changes
@@ -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.7.1-alpha.0"
6
+ version: "1.7.1-alpha.2"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.7.1-alpha.0",
2
+ "version": "1.7.1-alpha.2",
3
3
  "package": "@mastra/clickhouse",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -51,7 +51,7 @@ import { Mastra } from '@mastra/core'
51
51
  import { MastraCompositeStore } from '@mastra/core/storage'
52
52
  import { PostgresStore } from '@mastra/pg'
53
53
  import { ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'
54
- import { Observability, DefaultExporter } from '@mastra/observability'
54
+ import { Observability, MastraStorageExporter } from '@mastra/observability'
55
55
 
56
56
  const observabilityStore = new ObservabilityStorageClickhouseVNext({
57
57
  url: process.env.CLICKHOUSE_URL!,
@@ -74,14 +74,14 @@ export const mastra = new Mastra({
74
74
  configs: {
75
75
  default: {
76
76
  serviceName: 'mastra',
77
- exporters: [new DefaultExporter()],
77
+ exporters: [new MastraStorageExporter()],
78
78
  },
79
79
  },
80
80
  }),
81
81
  })
82
82
  ```
83
83
 
84
- `DefaultExporter` automatically selects the `insert-only` strategy when ClickHouse is the observability backend, which gives the highest write throughput. See [tracing strategies](https://mastra.ai/docs/observability/tracing/exporters/default) for details.
84
+ `MastraStorageExporter` automatically selects the `insert-only` strategy when ClickHouse is the observability backend, which gives the highest write throughput. See [tracing strategies](https://mastra.ai/docs/observability/tracing/exporters/mastra-storage) for details.
85
85
 
86
86
  ### Observability with the legacy domain
87
87
 
@@ -226,7 +226,7 @@ import { Mastra } from '@mastra/core'
226
226
  import { MastraCompositeStore } from '@mastra/core/storage'
227
227
  import { PostgresStore } from '@mastra/pg'
228
228
  import { ObservabilityStorageClickhouseVNext } from '@mastra/clickhouse'
229
- import { Observability, DefaultExporter } from '@mastra/observability'
229
+ import { Observability, MastraStorageExporter } from '@mastra/observability'
230
230
 
231
231
  export const mastra = new Mastra({
232
232
  storage: new MastraCompositeStore({
@@ -247,7 +247,7 @@ export const mastra = new Mastra({
247
247
  configs: {
248
248
  default: {
249
249
  serviceName: 'mastra',
250
- exporters: [new DefaultExporter()],
250
+ exporters: [new MastraStorageExporter()],
251
251
  },
252
252
  },
253
253
  }),
@@ -287,14 +287,14 @@ In CI/CD pipelines, set `disableInit: true` on `ClickhouseStore` and run `init()
287
287
 
288
288
  ClickHouse is the recommended backend for production observability:
289
289
 
290
- - **Insert-only strategy**: `DefaultExporter` writes completed spans in batches without per-span updates, which is the highest-throughput strategy available.
290
+ - **Insert-only strategy**: `MastraStorageExporter` writes completed spans in batches without per-span updates, which is the highest-throughput strategy available.
291
291
  - **Columnar compression**: Span attributes and log payloads compress well compared to the same data in row-oriented databases.
292
292
 
293
- For the full strategy matrix and production guidance, see the [`DefaultExporter` reference](https://mastra.ai/docs/observability/tracing/exporters/default).
293
+ For the full strategy matrix and production guidance, see the [`MastraStorageExporter` reference](https://mastra.ai/docs/observability/tracing/exporters/mastra-storage).
294
294
 
295
295
  ## Related
296
296
 
297
297
  - [Storage overview](https://mastra.ai/reference/storage/overview)
298
298
  - [Composite storage](https://mastra.ai/reference/storage/composite)
299
- - [`DefaultExporter`](https://mastra.ai/docs/observability/tracing/exporters/default)
299
+ - [`MastraStorageExporter`](https://mastra.ai/docs/observability/tracing/exporters/mastra-storage)
300
300
  - [Observability overview](https://mastra.ai/docs/observability/overview)
@@ -242,4 +242,4 @@ const storage = new MastraCompositeStore({
242
242
 
243
243
  > **Note:** `ObservabilityStorageClickhouseVNext` is the current observability domain implementation. The legacy `ObservabilityStorageClickhouse` class is also exported and remains supported for projects that have not migrated. See the [ClickHouse storage reference](https://mastra.ai/reference/storage/clickhouse) for details.
244
244
 
245
- > **Info:** This approach is also required when using storage providers that don't support observability (like Convex, DynamoDB, or Cloudflare). See the [DefaultExporter documentation](https://mastra.ai/docs/observability/tracing/exporters/default) for the full list of supported providers.
245
+ > **Info:** This approach is also required when using storage providers that don't support observability (like Convex, DynamoDB, or Cloudflare). See the [MastraStorageExporter documentation](https://mastra.ai/docs/observability/tracing/exporters/mastra-storage) for the full list of supported providers.
package/dist/index.cjs CHANGED
@@ -1458,7 +1458,10 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
1458
1458
  );
1459
1459
  }
1460
1460
  }
1461
- async getThreadById({ threadId }) {
1461
+ async getThreadById({
1462
+ threadId,
1463
+ resourceId
1464
+ }) {
1462
1465
  try {
1463
1466
  const result = await this.client.query({
1464
1467
  query: `SELECT
@@ -1483,7 +1486,7 @@ var MemoryStorageClickhouse = class extends storage.MemoryStorage {
1483
1486
  });
1484
1487
  const rows = await result.json();
1485
1488
  const thread = transformRow(rows.data[0]);
1486
- if (!thread) {
1489
+ if (!thread || resourceId !== void 0 && thread.resourceId !== resourceId) {
1487
1490
  return null;
1488
1491
  }
1489
1492
  return {
@@ -3421,44 +3424,56 @@ var ALL_TABLE_DDL = [
3421
3424
  ];
3422
3425
  var ALL_MV_DDL = [TRACE_ROOTS_MV_DDL, TRACE_BRANCHES_MV_DDL];
3423
3426
  var DISCOVERY_MV_DDL = [DISCOVERY_VALUES_MV_DDL, DISCOVERY_PAIRS_MV_DDL];
3427
+ var addColumn = (table, name, type) => ({
3428
+ kind: "column",
3429
+ table,
3430
+ name,
3431
+ sql: `ALTER TABLE ${table} ADD COLUMN IF NOT EXISTS ${name} ${type}`
3432
+ });
3433
+ var addBloomIndex = (table, name, column) => ({
3434
+ kind: "index",
3435
+ table,
3436
+ name,
3437
+ sql: `ALTER TABLE ${table} ADD INDEX IF NOT EXISTS ${name} ${column} TYPE bloom_filter(0.01) GRANULARITY 2`
3438
+ });
3424
3439
  var ALL_MIGRATIONS = [
3425
3440
  // Span events
3426
- `ALTER TABLE ${TABLE_SPAN_EVENTS} ADD COLUMN IF NOT EXISTS entityVersionId Nullable(String)`,
3427
- `ALTER TABLE ${TABLE_SPAN_EVENTS} ADD COLUMN IF NOT EXISTS parentEntityVersionId Nullable(String)`,
3428
- `ALTER TABLE ${TABLE_SPAN_EVENTS} ADD COLUMN IF NOT EXISTS rootEntityVersionId Nullable(String)`,
3441
+ addColumn(TABLE_SPAN_EVENTS, "entityVersionId", "Nullable(String)"),
3442
+ addColumn(TABLE_SPAN_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3443
+ addColumn(TABLE_SPAN_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3429
3444
  // Trace roots
3430
- `ALTER TABLE ${TABLE_TRACE_ROOTS} ADD COLUMN IF NOT EXISTS entityVersionId Nullable(String)`,
3431
- `ALTER TABLE ${TABLE_TRACE_ROOTS} ADD COLUMN IF NOT EXISTS parentEntityVersionId Nullable(String)`,
3432
- `ALTER TABLE ${TABLE_TRACE_ROOTS} ADD COLUMN IF NOT EXISTS rootEntityVersionId Nullable(String)`,
3445
+ addColumn(TABLE_TRACE_ROOTS, "entityVersionId", "Nullable(String)"),
3446
+ addColumn(TABLE_TRACE_ROOTS, "parentEntityVersionId", "Nullable(String)"),
3447
+ addColumn(TABLE_TRACE_ROOTS, "rootEntityVersionId", "Nullable(String)"),
3433
3448
  // Metrics
3434
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD COLUMN IF NOT EXISTS entityVersionId Nullable(String)`,
3435
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD COLUMN IF NOT EXISTS parentEntityVersionId Nullable(String)`,
3436
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD COLUMN IF NOT EXISTS rootEntityVersionId Nullable(String)`,
3449
+ addColumn(TABLE_METRIC_EVENTS, "entityVersionId", "Nullable(String)"),
3450
+ addColumn(TABLE_METRIC_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3451
+ addColumn(TABLE_METRIC_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3437
3452
  // Logs
3438
- `ALTER TABLE ${TABLE_LOG_EVENTS} ADD COLUMN IF NOT EXISTS entityVersionId Nullable(String)`,
3439
- `ALTER TABLE ${TABLE_LOG_EVENTS} ADD COLUMN IF NOT EXISTS parentEntityVersionId Nullable(String)`,
3440
- `ALTER TABLE ${TABLE_LOG_EVENTS} ADD COLUMN IF NOT EXISTS rootEntityVersionId Nullable(String)`,
3453
+ addColumn(TABLE_LOG_EVENTS, "entityVersionId", "Nullable(String)"),
3454
+ addColumn(TABLE_LOG_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3455
+ addColumn(TABLE_LOG_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3441
3456
  // Scores
3442
- `ALTER TABLE ${TABLE_SCORE_EVENTS} ADD COLUMN IF NOT EXISTS entityVersionId Nullable(String)`,
3443
- `ALTER TABLE ${TABLE_SCORE_EVENTS} ADD COLUMN IF NOT EXISTS parentEntityVersionId Nullable(String)`,
3444
- `ALTER TABLE ${TABLE_SCORE_EVENTS} ADD COLUMN IF NOT EXISTS rootEntityVersionId Nullable(String)`,
3457
+ addColumn(TABLE_SCORE_EVENTS, "entityVersionId", "Nullable(String)"),
3458
+ addColumn(TABLE_SCORE_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3459
+ addColumn(TABLE_SCORE_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3445
3460
  // Feedback
3446
- `ALTER TABLE ${TABLE_FEEDBACK_EVENTS} ADD COLUMN IF NOT EXISTS entityVersionId Nullable(String)`,
3447
- `ALTER TABLE ${TABLE_FEEDBACK_EVENTS} ADD COLUMN IF NOT EXISTS parentEntityVersionId Nullable(String)`,
3448
- `ALTER TABLE ${TABLE_FEEDBACK_EVENTS} ADD COLUMN IF NOT EXISTS rootEntityVersionId Nullable(String)`,
3461
+ addColumn(TABLE_FEEDBACK_EVENTS, "entityVersionId", "Nullable(String)"),
3462
+ addColumn(TABLE_FEEDBACK_EVENTS, "parentEntityVersionId", "Nullable(String)"),
3463
+ addColumn(TABLE_FEEDBACK_EVENTS, "rootEntityVersionId", "Nullable(String)"),
3449
3464
  // Metric skip indexes — additive, instant DDL. Existing parts keep no index
3450
3465
  // until merged or `MATERIALIZE INDEX` is run; new parts are bloom-filtered
3451
3466
  // immediately. With normal retention turning over the table, the index
3452
3467
  // converges to full coverage without an explicit backfill.
3453
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_traceId traceId TYPE bloom_filter(0.01) GRANULARITY 2`,
3454
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_threadId threadId TYPE bloom_filter(0.01) GRANULARITY 2`,
3455
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_resourceId resourceId TYPE bloom_filter(0.01) GRANULARITY 2`,
3456
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_userId userId TYPE bloom_filter(0.01) GRANULARITY 2`,
3457
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_organizationId organizationId TYPE bloom_filter(0.01) GRANULARITY 2`,
3458
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_experimentId experimentId TYPE bloom_filter(0.01) GRANULARITY 2`,
3459
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_runId runId TYPE bloom_filter(0.01) GRANULARITY 2`,
3460
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_sessionId sessionId TYPE bloom_filter(0.01) GRANULARITY 2`,
3461
- `ALTER TABLE ${TABLE_METRIC_EVENTS} ADD INDEX IF NOT EXISTS idx_requestId requestId TYPE bloom_filter(0.01) GRANULARITY 2`
3468
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_traceId", "traceId"),
3469
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_threadId", "threadId"),
3470
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_resourceId", "resourceId"),
3471
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_userId", "userId"),
3472
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_organizationId", "organizationId"),
3473
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_experimentId", "experimentId"),
3474
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_runId", "runId"),
3475
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_sessionId", "sessionId"),
3476
+ addBloomIndex(TABLE_METRIC_EVENTS, "idx_requestId", "requestId")
3462
3477
  ];
3463
3478
  var ALL_TABLE_NAMES = [
3464
3479
  TABLE_SPAN_EVENTS,
@@ -3487,8 +3502,8 @@ var SIGNAL_TO_TABLES = {
3487
3502
  scores: [TABLE_SCORE_EVENTS],
3488
3503
  feedback: [TABLE_FEEDBACK_EVENTS]
3489
3504
  };
3490
- function buildRetentionDDL(retention) {
3491
- const statements = [];
3505
+ function buildRetentionEntries(retention) {
3506
+ const entries = [];
3492
3507
  for (const [signal, days] of Object.entries(retention)) {
3493
3508
  const safeDays = Math.floor(Number(days));
3494
3509
  if (!Number.isFinite(safeDays) || safeDays <= 0) continue;
@@ -3497,10 +3512,24 @@ function buildRetentionDDL(retention) {
3497
3512
  for (const table of tables) {
3498
3513
  const col = SIGNAL_TTL_COLUMNS[table];
3499
3514
  if (!col) continue;
3500
- statements.push(`ALTER TABLE ${table} MODIFY TTL ${col} + INTERVAL ${safeDays} DAY`);
3515
+ entries.push({
3516
+ table,
3517
+ column: col,
3518
+ days: safeDays,
3519
+ sql: `ALTER TABLE ${table} MODIFY TTL ${col} + INTERVAL ${safeDays} DAY`
3520
+ });
3501
3521
  }
3502
3522
  }
3503
- return statements;
3523
+ return entries;
3524
+ }
3525
+ function parseTtlExpression(expr) {
3526
+ const match = expr.match(/TTL\s+(?:`([^`]+)`|(\w+))\s*\+\s*(?:toIntervalDay\((\d+)\)|INTERVAL\s+(\d+)\s+DAY)/i);
3527
+ if (!match) return null;
3528
+ const column = match[1] ?? match[2];
3529
+ if (!column) return null;
3530
+ const days = Number(match[3] ?? match[4]);
3531
+ if (!Number.isFinite(days)) return null;
3532
+ return { column, days };
3504
3533
  }
3505
3534
  var CH_SETTINGS = {
3506
3535
  date_time_input_format: "best_effort",
@@ -5961,6 +5990,74 @@ time for large databases. Please ensure you have a backup before proceeding.
5961
5990
  ===========================================================================
5962
5991
  `;
5963
5992
  }
5993
+ async function filterAppliedMigrations(client, migrations) {
5994
+ if (migrations.length === 0) return migrations;
5995
+ const tables = [...new Set(migrations.map((m) => m.table))];
5996
+ let existingColumns;
5997
+ let existingIndices;
5998
+ try {
5999
+ [existingColumns, existingIndices] = await Promise.all([
6000
+ queryNamesByTable(
6001
+ client,
6002
+ `SELECT table, name FROM system.columns WHERE database = currentDatabase() AND table IN ({tables:Array(String)})`,
6003
+ tables
6004
+ ),
6005
+ queryNamesByTable(
6006
+ client,
6007
+ `SELECT table, name FROM system.data_skipping_indices WHERE database = currentDatabase() AND table IN ({tables:Array(String)})`,
6008
+ tables
6009
+ )
6010
+ ]);
6011
+ } catch {
6012
+ return migrations;
6013
+ }
6014
+ return migrations.filter((m) => {
6015
+ const present = m.kind === "column" ? existingColumns.get(m.table) : existingIndices.get(m.table);
6016
+ if (!present) return true;
6017
+ return !present.has(m.name);
6018
+ });
6019
+ }
6020
+ async function filterAppliedRetention(client, entries) {
6021
+ if (entries.length === 0) return entries;
6022
+ const tables = [...new Set(entries.map((e) => e.table))];
6023
+ let createQueries;
6024
+ try {
6025
+ const result = await client.query({
6026
+ query: `SELECT name, create_table_query FROM system.tables WHERE database = currentDatabase() AND name IN ({tables:Array(String)})`,
6027
+ query_params: { tables },
6028
+ format: "JSONEachRow"
6029
+ });
6030
+ const rows = await result.json();
6031
+ createQueries = new Map(rows.map((r) => [r.name, r.create_table_query ?? ""]));
6032
+ } catch {
6033
+ return entries;
6034
+ }
6035
+ return entries.filter((e) => {
6036
+ const createQuery = createQueries.get(e.table);
6037
+ if (!createQuery) return true;
6038
+ const current = parseTtlExpression(createQuery);
6039
+ if (!current) return true;
6040
+ return current.column !== e.column || current.days !== e.days;
6041
+ });
6042
+ }
6043
+ async function queryNamesByTable(client, query, tables) {
6044
+ const result = await client.query({
6045
+ query,
6046
+ query_params: { tables },
6047
+ format: "JSONEachRow"
6048
+ });
6049
+ const rows = await result.json();
6050
+ const out = /* @__PURE__ */ new Map();
6051
+ for (const row of rows) {
6052
+ let set = out.get(row.table);
6053
+ if (!set) {
6054
+ set = /* @__PURE__ */ new Set();
6055
+ out.set(row.table, set);
6056
+ }
6057
+ set.add(row.name);
6058
+ }
6059
+ return out;
6060
+ }
5964
6061
  var ObservabilityStorageClickhouseVNext = class extends storage.ObservabilityStorage {
5965
6062
  #client;
5966
6063
  #retention;
@@ -5990,13 +6087,14 @@ var ObservabilityStorageClickhouseVNext = class extends storage.ObservabilitySto
5990
6087
  for (const ddl of [...ALL_TABLE_DDL, ...ALL_MV_DDL]) {
5991
6088
  await this.#client.command({ query: ddl });
5992
6089
  }
5993
- for (const migration of ALL_MIGRATIONS) {
5994
- await this.#client.command({ query: migration });
6090
+ const pendingMigrations = await filterAppliedMigrations(this.#client, ALL_MIGRATIONS);
6091
+ for (const migration of pendingMigrations) {
6092
+ await this.#client.command({ query: migration.sql });
5995
6093
  }
5996
6094
  if (this.#retention) {
5997
- const ttlStatements = buildRetentionDDL(this.#retention);
5998
- for (const stmt of ttlStatements) {
5999
- await this.#client.command({ query: stmt });
6095
+ const pendingRetention = await filterAppliedRetention(this.#client, buildRetentionEntries(this.#retention));
6096
+ for (const entry of pendingRetention) {
6097
+ await this.#client.command({ query: entry.sql });
6000
6098
  }
6001
6099
  }
6002
6100
  } catch (error$1) {