@mastra/duckdb 1.10.0 → 1.11.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.
@@ -687,6 +687,23 @@ function jsonV(val) {
687
687
  if (val === null || val === void 0) return "NULL";
688
688
  return DuckDBConnection.sqlValue(JSON.stringify(val));
689
689
  }
690
+ /**
691
+ * Trim, drop blank, and dedupe tags before they are written, matching the
692
+ * PostgreSQL and ClickHouse stores so tag predicates and discovery agree.
693
+ */
694
+ function normalizeTags(tags) {
695
+ if (!Array.isArray(tags)) return [];
696
+ const seen = /* @__PURE__ */ new Set();
697
+ const result = [];
698
+ for (const t of tags) {
699
+ if (typeof t !== "string") continue;
700
+ const trimmed = t.trim();
701
+ if (trimmed === "" || seen.has(trimmed)) continue;
702
+ seen.add(trimmed);
703
+ result.push(trimmed);
704
+ }
705
+ return result;
706
+ }
690
707
  /** Coerce a value to a Date. Throws if value is nullish. */
691
708
  function toDate(val) {
692
709
  if (val === null || val === void 0) throw new Error("Expected date value but received null/undefined");
@@ -2719,6 +2736,10 @@ const TRACE_FIELDS = {
2719
2736
  status: {
2720
2737
  sql: TRACE_STATUS_SQL,
2721
2738
  parameterType: "scalar"
2739
+ },
2740
+ tags: {
2741
+ sql: "r.tags",
2742
+ parameterType: "scalar"
2722
2743
  }
2723
2744
  };
2724
2745
  const SPAN_FIELDS = {
@@ -2921,6 +2942,25 @@ function compileScalarPredicate(predicate, registry, allowMetadata = false) {
2921
2942
  sql: `${field.sql} IS ${predicate.operator === "exists" ? "NOT " : ""}NULL`,
2922
2943
  values: fieldValues
2923
2944
  };
2945
+ if (predicate.type === "collection") {
2946
+ const members = `coalesce(TRY_CAST(${field.sql} AS VARCHAR[]), []::VARCHAR[])`;
2947
+ if (!("value" in predicate)) return {
2948
+ sql: `len(${members}) ${predicate.operator === "empty" ? "=" : ">"} 0`,
2949
+ values: fieldValues
2950
+ };
2951
+ if (predicate.operator === "includes") return {
2952
+ sql: `list_contains(${members}, ?)`,
2953
+ values: [...fieldValues, predicate.value]
2954
+ };
2955
+ return {
2956
+ sql: `len(${members}) > 0 AND NOT list_contains(${members}, ?)`,
2957
+ values: [
2958
+ ...fieldValues,
2959
+ ...fieldValues,
2960
+ predicate.value
2961
+ ]
2962
+ };
2963
+ }
2924
2964
  if (predicate.type === "membership") {
2925
2965
  const list = predicate.values.map(() => parameterSql(field.parameterType)).join(", ");
2926
2966
  if (predicate.operator === "in") return {
@@ -2985,7 +3025,7 @@ function compileFeedbackScalarPredicate(predicate) {
2985
3025
  values: compiled.values
2986
3026
  };
2987
3027
  }
2988
- if (predicate.field !== "value") return compileScalarPredicate(predicate, FEEDBACK_FIELDS);
3028
+ if (predicate.field !== "value" || predicate.type === "collection") return compileScalarPredicate(predicate, FEEDBACK_FIELDS);
2989
3029
  if (predicate.type === "presence") return {
2990
3030
  sql: `s.value IS ${predicate.operator === "exists" ? "NOT " : ""}NULL`,
2991
3031
  values: []
@@ -3073,7 +3113,14 @@ function collectThreadRelatedCollections(predicate, collections) {
3073
3113
  else collectThreadRelatedCollections(predicate.arg, collections);
3074
3114
  return collections;
3075
3115
  }
3076
- function compileDuckDBTraceScope(relatedCollections) {
3116
+ function compileDuckDBTraceScope(relatedCollections, scope) {
3117
+ const tenantConditions = (alias) => scope ? [`${alias}.organizationId = ?`, ...scope.resourceId === void 0 ? [] : [`${alias}.resourceId = ?`]] : [];
3118
+ const tenantValues = scope ? scope.resourceId === void 0 ? [scope.organizationId] : [scope.organizationId, scope.resourceId] : [];
3119
+ const tenantWhere = (alias) => {
3120
+ const conditions = tenantConditions(alias);
3121
+ return conditions.length ? `\n WHERE ${conditions.join(" AND ")}` : "";
3122
+ };
3123
+ const values = [...tenantValues];
3077
3124
  const ctes = [
3078
3125
  `root_events AS (
3079
3126
  SELECT
@@ -3096,12 +3143,16 @@ function compileDuckDBTraceScope(relatedCollections) {
3096
3143
  `root_scope AS (
3097
3144
  SELECT *
3098
3145
  FROM current_roots r
3099
- WHERE r.endedAt IS NOT NULL
3100
- AND r.startedAt >= CAST(? AS TIMESTAMP)
3101
- AND r.startedAt < CAST(? AS TIMESTAMP)
3146
+ WHERE ${[
3147
+ "r.endedAt IS NOT NULL",
3148
+ "r.startedAt >= CAST(? AS TIMESTAMP)",
3149
+ "r.startedAt < CAST(? AS TIMESTAMP)",
3150
+ ...tenantConditions("r")
3151
+ ].join("\n AND ")}
3102
3152
  )`
3103
3153
  ];
3104
- if (relatedCollections.has("spans")) ctes.push(`current_span_rows AS (
3154
+ if (relatedCollections.has("spans")) {
3155
+ ctes.push(`current_span_rows AS (
3105
3156
  SELECT
3106
3157
  e.*,
3107
3158
  coalesce(
@@ -3113,7 +3164,7 @@ function compileDuckDBTraceScope(relatedCollections) {
3113
3164
  ORDER BY CASE WHEN e.endedAt IS NULL THEN 1 ELSE 0 END ASC, e.cursorId DESC
3114
3165
  ) AS currentRank
3115
3166
  FROM span_events e
3116
- INNER JOIN root_scope roots ON roots.traceId = e.traceId
3167
+ INNER JOIN root_scope roots ON roots.traceId = e.traceId${tenantWhere("e")}
3117
3168
  ),
3118
3169
  current_spans AS (
3119
3170
  SELECT
@@ -3140,20 +3191,36 @@ function compileDuckDBTraceScope(relatedCollections) {
3140
3191
  FROM current_span_rows
3141
3192
  WHERE currentRank = 1
3142
3193
  )`);
3143
- if (relatedCollections.has("scores")) ctes.push(`current_scores AS (
3194
+ values.push(...tenantValues);
3195
+ }
3196
+ if (relatedCollections.has("scores")) {
3197
+ ctes.push(`current_scores AS (
3144
3198
  SELECT s.*
3145
3199
  FROM score_events s
3146
- INNER JOIN root_scope roots ON roots.traceId = s.traceId
3200
+ INNER JOIN root_scope roots ON roots.traceId = s.traceId${tenantWhere("s")}
3147
3201
  )`);
3148
- if (relatedCollections.has("feedback")) ctes.push(`current_feedback AS (
3202
+ values.push(...tenantValues);
3203
+ }
3204
+ if (relatedCollections.has("feedback")) {
3205
+ ctes.push(`current_feedback AS (
3149
3206
  SELECT f.*
3150
3207
  FROM feedback_events f
3151
- INNER JOIN root_scope roots ON roots.traceId = f.traceId
3208
+ INNER JOIN root_scope roots ON roots.traceId = f.traceId${tenantWhere("f")}
3152
3209
  )`);
3153
- return ctes;
3210
+ values.push(...tenantValues);
3211
+ }
3212
+ return {
3213
+ ctes,
3214
+ values
3215
+ };
3154
3216
  }
3155
3217
  function compileDuckDBTraceQuery(plan) {
3156
- const values = [plan.timeRange.from, plan.timeRange.to];
3218
+ const { ctes, values: scopeValues } = compileDuckDBTraceScope(collectRelatedCollections(plan.where), plan.scope);
3219
+ const values = [
3220
+ plan.timeRange.from,
3221
+ plan.timeRange.to,
3222
+ ...scopeValues
3223
+ ];
3157
3224
  const conditions = [
3158
3225
  `r.endedAt IS NOT NULL`,
3159
3226
  `r.startedAt >= CAST(? AS TIMESTAMP)`,
@@ -3164,7 +3231,6 @@ function compileDuckDBTraceQuery(plan) {
3164
3231
  conditions.push(`(${predicate.sql})`);
3165
3232
  values.push(...predicate.values);
3166
3233
  }
3167
- const ctes = compileDuckDBTraceScope(collectRelatedCollections(plan.where));
3168
3234
  ctes.push(`candidates AS (
3169
3235
  SELECT ${TRACE_SELECT}${plan.paginationMode === "delta" ? ", r.cursorId AS deltaWatermark" : ""}
3170
3236
  FROM root_scope r
@@ -3246,10 +3312,14 @@ LIMIT ?`,
3246
3312
  };
3247
3313
  }
3248
3314
  function compileDuckDBThreadQuery(plan) {
3249
- const values = [plan.traces.timeRange.from, plan.traces.timeRange.to];
3250
3315
  const relatedCollections = collectRelatedCollections(plan.traces.where);
3251
3316
  collectThreadRelatedCollections(plan.where, relatedCollections);
3252
- const ctes = compileDuckDBTraceScope(relatedCollections);
3317
+ const { ctes, values: scopeValues } = compileDuckDBTraceScope(relatedCollections, plan.scope);
3318
+ const values = [
3319
+ plan.traces.timeRange.from,
3320
+ plan.traces.timeRange.to,
3321
+ ...scopeValues
3322
+ ];
3253
3323
  let eligibilitySql = "TRUE";
3254
3324
  if (plan.traces.where) {
3255
3325
  const eligibility = compilePredicate(plan.traces.where);
@@ -3307,12 +3377,17 @@ function discoveryCollections(scope) {
3307
3377
  return scope === "trace" ? /* @__PURE__ */ new Set() : /* @__PURE__ */ new Set([scope]);
3308
3378
  }
3309
3379
  function compileDuckDBTraceQueryObservedFields(plan) {
3310
- const values = [plan.timeRange.from, plan.timeRange.to];
3380
+ const { ctes, values: scopeValues } = compileDuckDBTraceScope(/* @__PURE__ */ new Set(), plan.scope);
3381
+ const values = [
3382
+ plan.timeRange.from,
3383
+ plan.timeRange.to,
3384
+ ...scopeValues
3385
+ ];
3311
3386
  if (plan.search) values.push(plan.search);
3312
3387
  values.push(plan.limit + 1);
3313
3388
  const search = plan.search ? `AND strpos(lower('metadata.' || entry.key), lower(?)) > 0` : "";
3314
3389
  return {
3315
- sql: `WITH ${compileDuckDBTraceScope(/* @__PURE__ */ new Set()).join(",\n ")}
3390
+ sql: `WITH ${ctes.join(",\n ")}
3316
3391
  SELECT 'metadata.' || entry.key AS path, count(*) AS occurrences
3317
3392
  FROM root_scope r, LATERAL json_each(r.metadata) entry
3318
3393
  WHERE entry.type = 'VARCHAR'
@@ -3329,10 +3404,18 @@ LIMIT ?`,
3329
3404
  };
3330
3405
  }
3331
3406
  function compileDuckDBTraceQueryValues(plan) {
3332
- const values = [plan.timeRange.from, plan.timeRange.to];
3333
- const ctes = compileDuckDBTraceScope(discoveryCollections(plan.predicateScope));
3407
+ const { ctes, values: scopeValues } = compileDuckDBTraceScope(discoveryCollections(plan.predicateScope), plan.scope);
3408
+ const values = [
3409
+ plan.timeRange.from,
3410
+ plan.timeRange.to,
3411
+ ...scopeValues
3412
+ ];
3334
3413
  let fieldSql;
3335
- if (plan.predicateScope === "trace" && plan.path.startsWith("metadata.")) {
3414
+ let source = discoverySource(plan.predicateScope);
3415
+ if (plan.predicateScope === "trace" && plan.path === "tags") {
3416
+ fieldSql = "unnest(list_distinct(TRY_CAST(r.tags AS VARCHAR[])))";
3417
+ source = `${source} WHERE r.tags IS NOT NULL`;
3418
+ } else if (plan.predicateScope === "trace" && plan.path.startsWith("metadata.")) {
3336
3419
  const jsonPath = `$.${JSON.stringify(plan.path.slice(9))}`;
3337
3420
  fieldSql = `NULLIF(trim(CASE WHEN json_type(r.metadata, ?) = 'VARCHAR' THEN json_extract_string(r.metadata, ?) END), '')`;
3338
3421
  values.push(jsonPath, jsonPath);
@@ -3342,7 +3425,7 @@ function compileDuckDBTraceQueryValues(plan) {
3342
3425
  const search = plan.search ? "AND strpos(lower(CAST(value AS VARCHAR)), lower(?)) > 0" : "";
3343
3426
  return {
3344
3427
  sql: `WITH ${ctes.join(",\n ")}, extracted AS (
3345
- SELECT ${fieldSql} AS value FROM ${discoverySource(plan.predicateScope)}
3428
+ SELECT ${fieldSql} AS value FROM ${source}
3346
3429
  )
3347
3430
  SELECT CAST(value AS VARCHAR) AS value, count(*) AS count
3348
3431
  FROM extracted
@@ -3940,7 +4023,7 @@ function createStartSpanRow(s) {
3940
4023
  serviceName: s.serviceName ?? null,
3941
4024
  attributes: s.attributes ?? null,
3942
4025
  metadata: s.metadata ?? null,
3943
- tags: s.tags ?? null,
4026
+ tags: s.tags == null ? null : normalizeTags(s.tags),
3944
4027
  scope: s.scope ?? null,
3945
4028
  links: null,
3946
4029
  input: s.input ?? null,
@@ -3979,7 +4062,7 @@ function createEndSpanRow(s) {
3979
4062
  serviceName: s.serviceName ?? null,
3980
4063
  attributes: s.attributes ?? null,
3981
4064
  metadata: s.metadata ?? null,
3982
- tags: s.tags ?? null,
4065
+ tags: s.tags == null ? null : normalizeTags(s.tags),
3983
4066
  scope: s.scope ?? null,
3984
4067
  links: s.links ?? null,
3985
4068
  input: s.input ?? null,
@@ -4782,7 +4865,8 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends Observ
4782
4865
  "logs",
4783
4866
  "trace-query",
4784
4867
  "trace-query-discovery",
4785
- "thread-query"
4868
+ "thread-query",
4869
+ "trace-query-tenant-scope"
4786
4870
  ];
4787
4871
  return [
4788
4872
  "metrics",
@@ -4790,7 +4874,8 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends Observ
4790
4874
  "delta-polling",
4791
4875
  "trace-query",
4792
4876
  "trace-query-discovery",
4793
- "thread-query"
4877
+ "thread-query",
4878
+ "trace-query-tenant-scope"
4794
4879
  ];
4795
4880
  }
4796
4881
  async createSpan(args) {
@@ -4945,4 +5030,4 @@ var ObservabilityStorageDuckDB = class ObservabilityStorageDuckDB extends Observ
4945
5030
  //#endregion
4946
5031
  export { ObservabilityStorageDuckDB };
4947
5032
 
4948
- //# sourceMappingURL=observability-D3311DPa.js.map
5033
+ //# sourceMappingURL=observability-DtZoxBur.js.map