@mastra/mysql 0.3.0-alpha.0 → 0.3.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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
  # @mastra/mysql
2
2
 
3
+ ## 0.3.0-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Added multi-tenant scoping columns (`organizationId`, `projectId`) to the experiments domain so experiment records and per-item results inherit the tenancy bucket of their parent dataset. ([#18388](https://github.com/mastra-ai/mastra/pull/18388))
8
+
9
+ `Experiment`, `ExperimentResult`, `CreateExperimentInput`, and `AddExperimentResultInput` now carry optional `organizationId` / `projectId` fields. `ListExperimentsInput` and `ListExperimentResultsInput` gain a `filters: ExperimentTenancyFilters` block (mirrors `DatasetTenancyFilters`) for scoping queries within a `(organizationId, projectId)` bucket. Tenancy is hydrated from the parent dataset on `createExperiment` and denormalized onto each `ExperimentResult` for efficient tenancy-scoped queries.
10
+
11
+ The corresponding columns are also added to the `mastra_experiments` and `mastra_experiment_results` table schemas. Existing rows backfill to `null`, matching the rest of the dataset-tenancy surface.
12
+
13
+ This release also clarifies the `targetType` contract via JSDoc:
14
+ - `CreateDatasetInput.targetType` remains optional. Datasets without a `TargetType` are **not experiment-eligible** — the experiment runner requires a non-null `CreateExperimentInput.targetType` to resolve an executor.
15
+ - `Experiment.targetType` / `CreateExperimentInput.targetType` stay required. An experiment by definition replays inputs against a specific target.
16
+
17
+ No behavior change for existing OSS-created experiments; the new fields are additive and optional.
18
+
19
+ Example:
20
+
21
+ ```ts
22
+ // Create an experiment scoped to a tenancy bucket. When the parent dataset
23
+ // already carries `organizationId` / `projectId`, `runExperiment` hydrates
24
+ // these fields automatically from the dataset record.
25
+ const experiment = await storage.createExperiment({
26
+ name: 'qa-regression',
27
+ datasetId: 'ds_123',
28
+ datasetVersion: 1,
29
+ targetType: 'agent',
30
+ targetId: 'agent_qa',
31
+ totalItems: 10,
32
+ organizationId: 'org_123',
33
+ projectId: 'proj_123',
34
+ });
35
+
36
+ // List experiments within a tenancy bucket.
37
+ const experiments = await storage.listExperiments({
38
+ pagination: { page: 0, perPage: 20 },
39
+ filters: { organizationId: 'org_123', projectId: 'proj_123' },
40
+ });
41
+
42
+ // List per-item results within the same bucket.
43
+ const results = await storage.listExperimentResults({
44
+ experimentId: experiment.id,
45
+ pagination: { page: 0, perPage: 50 },
46
+ filters: { organizationId: 'org_123', projectId: 'proj_123' },
47
+ });
48
+ ```
49
+
50
+ - Persist and filter dataset tenancy + candidate identity in storage adapters. ([#18314](https://github.com/mastra-ai/mastra/pull/18314))
51
+
52
+ `createDataset` now persists `organizationId`, `projectId`, `candidateKey`, and `candidateId`. `listDatasets` and `listItems` accept matching tenancy filters. Dataset items inherit `organizationId` / `projectId` from their parent dataset on insert, update, delete, and batch insert/delete — items are never settable per call (item tenancy follows dataset tenancy).
53
+
54
+ All new columns are nullable and added retroactively via each adapter's existing column-migration path; no breaking DDL. Existing rows continue to read and write fine; new writes can choose to stamp tenancy.
55
+
56
+ ```ts
57
+ await storage.createDataset({
58
+ name: 'candidates/missing-tool-call/incident-123',
59
+ organizationId: 'org_abc',
60
+ projectId: 'project_xyz',
61
+ candidateKey: 'missing-tool-call',
62
+ candidateId: 'incident-123',
63
+ });
64
+
65
+ await storage.listDatasets({
66
+ pagination: { page: 0, perPage: 20 },
67
+ filters: { organizationId: 'org_abc', projectId: 'project_xyz' },
68
+ });
69
+ ```
70
+
71
+ - Updated dependencies [[`5c4e9a4`](https://github.com/mastra-ai/mastra/commit/5c4e9a4cfb2216bb3ea7f8988ad3727f3b92bb3a), [`25961e3`](https://github.com/mastra-ai/mastra/commit/25961e3260ff3b1464637af8fcdb36210551c39f), [`7b29f33`](https://github.com/mastra-ai/mastra/commit/7b29f332a357a83e555f29e718e5f2fab9979943), [`24912b1`](https://github.com/mastra-ai/mastra/commit/24912b1f855d29ec36af4ef4bde1f7417e20cdf5), [`7686216`](https://github.com/mastra-ai/mastra/commit/7686216f37e74568feddec17cef3c3d24e10e60a), [`975c59a`](https://github.com/mastra-ai/mastra/commit/975c59ae363ee275fc55062392e1ffd2cbccbd53), [`d95f394`](https://github.com/mastra-ai/mastra/commit/d95f394fd24c8411886930d727679c4d5252aa26), [`f3f0c9d`](https://github.com/mastra-ai/mastra/commit/f3f0c9d7c878db5a13177871ce3523a14f14b311)]:
72
+ - @mastra/core@1.46.0-alpha.4
73
+
3
74
  ## 0.3.0-alpha.0
4
75
 
5
76
  ### Minor Changes
package/dist/index.cjs CHANGED
@@ -2132,6 +2132,16 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2132
2132
  await this.operations.createTable({ tableName: storage.TABLE_DATASETS, schema: storage.DATASETS_SCHEMA });
2133
2133
  await this.operations.createTable({ tableName: storage.TABLE_DATASET_ITEMS, schema: storage.DATASET_ITEMS_SCHEMA });
2134
2134
  await this.operations.createTable({ tableName: storage.TABLE_DATASET_VERSIONS, schema: storage.DATASET_VERSIONS_SCHEMA });
2135
+ await this.operations.alterTable({
2136
+ tableName: storage.TABLE_DATASETS,
2137
+ schema: storage.DATASETS_SCHEMA,
2138
+ ifNotExists: ["organizationId", "projectId", "candidateKey", "candidateId"]
2139
+ });
2140
+ await this.operations.alterTable({
2141
+ tableName: storage.TABLE_DATASET_ITEMS,
2142
+ schema: storage.DATASET_ITEMS_SCHEMA,
2143
+ ifNotExists: ["organizationId", "projectId"]
2144
+ });
2135
2145
  await this.createDefaultIndexes();
2136
2146
  await this.createCustomIndexes();
2137
2147
  }
@@ -2150,6 +2160,10 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2150
2160
  inputSchema: parseJSON(row.inputSchema),
2151
2161
  groundTruthSchema: parseJSON(row.groundTruthSchema),
2152
2162
  version: row.version,
2163
+ organizationId: row.organizationId ?? null,
2164
+ projectId: row.projectId ?? null,
2165
+ candidateKey: row.candidateKey ?? null,
2166
+ candidateId: row.candidateId ?? null,
2153
2167
  createdAt: parseDateTime(row.createdAt) ?? /* @__PURE__ */ new Date(),
2154
2168
  updatedAt: parseDateTime(row.updatedAt) ?? /* @__PURE__ */ new Date()
2155
2169
  };
@@ -2159,6 +2173,8 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2159
2173
  id: row.id,
2160
2174
  datasetId: row.datasetId,
2161
2175
  datasetVersion: row.datasetVersion,
2176
+ organizationId: row.organizationId ?? null,
2177
+ projectId: row.projectId ?? null,
2162
2178
  input: parseJSON(row.input),
2163
2179
  groundTruth: row.groundTruth ? parseJSON(row.groundTruth) : void 0,
2164
2180
  metadata: row.metadata ? parseJSON(row.metadata) : void 0,
@@ -2171,6 +2187,8 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2171
2187
  id: row.id,
2172
2188
  datasetId: row.datasetId,
2173
2189
  datasetVersion: row.datasetVersion,
2190
+ organizationId: row.organizationId ?? null,
2191
+ projectId: row.projectId ?? null,
2174
2192
  validTo: row.validTo,
2175
2193
  isDeleted: Boolean(row.isDeleted),
2176
2194
  input: parseJSON(row.input),
@@ -2203,6 +2221,10 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2203
2221
  inputSchema: jsonArg(input.inputSchema),
2204
2222
  groundTruthSchema: jsonArg(input.groundTruthSchema),
2205
2223
  version: 0,
2224
+ organizationId: input.organizationId ?? null,
2225
+ projectId: input.projectId ?? null,
2226
+ candidateKey: input.candidateKey ?? null,
2227
+ candidateId: input.candidateId ?? null,
2206
2228
  createdAt: now,
2207
2229
  updatedAt: now
2208
2230
  }
@@ -2215,6 +2237,10 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2215
2237
  inputSchema: input.inputSchema ?? void 0,
2216
2238
  groundTruthSchema: input.groundTruthSchema ?? void 0,
2217
2239
  version: 0,
2240
+ organizationId: input.organizationId ?? null,
2241
+ projectId: input.projectId ?? null,
2242
+ candidateKey: input.candidateKey ?? null,
2243
+ candidateId: input.candidateId ?? null,
2218
2244
  createdAt: now,
2219
2245
  updatedAt: now
2220
2246
  };
@@ -2337,7 +2363,28 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2337
2363
  async listDatasets(args) {
2338
2364
  try {
2339
2365
  const { page, perPage: perPageInput } = args.pagination;
2340
- const whereClause = { sql: "", args: [] };
2366
+ const filterParts = [];
2367
+ const filterArgs = [];
2368
+ if (args.filters?.organizationId !== void 0) {
2369
+ filterParts.push(`${quoteIdentifier("organizationId", "column name")} = ?`);
2370
+ filterArgs.push(args.filters.organizationId);
2371
+ }
2372
+ if (args.filters?.projectId !== void 0) {
2373
+ filterParts.push(`${quoteIdentifier("projectId", "column name")} = ?`);
2374
+ filterArgs.push(args.filters.projectId);
2375
+ }
2376
+ if (args.filters?.candidateKey !== void 0) {
2377
+ filterParts.push(`${quoteIdentifier("candidateKey", "column name")} = ?`);
2378
+ filterArgs.push(args.filters.candidateKey);
2379
+ }
2380
+ if (args.filters?.candidateId !== void 0) {
2381
+ filterParts.push(`${quoteIdentifier("candidateId", "column name")} = ?`);
2382
+ filterArgs.push(args.filters.candidateId);
2383
+ }
2384
+ const whereClause = {
2385
+ sql: filterParts.length > 0 ? `WHERE ${filterParts.join(" AND ")}` : "",
2386
+ args: filterArgs
2387
+ };
2341
2388
  const total = await this.operations.loadTotalCount({ tableName: storage.TABLE_DATASETS, whereClause });
2342
2389
  if (total === 0) {
2343
2390
  return {
@@ -2390,17 +2437,22 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2390
2437
  await connection.execute(`UPDATE ${tableDatasetsName} SET \`version\` = \`version\` + 1 WHERE id = ?`, [
2391
2438
  args.datasetId
2392
2439
  ]);
2393
- const [versionRows] = await connection.execute(
2394
- `SELECT \`version\` FROM ${tableDatasetsName} WHERE id = ?`,
2440
+ const [datasetRows] = await connection.execute(
2441
+ `SELECT \`version\`, \`organizationId\`, \`projectId\` FROM ${tableDatasetsName} WHERE id = ?`,
2395
2442
  [args.datasetId]
2396
2443
  );
2397
- const newVersion = versionRows[0]?.version;
2444
+ const parentRow = datasetRows[0];
2445
+ const newVersion = parentRow?.version;
2446
+ const parentOrganizationId = parentRow?.organizationId ?? null;
2447
+ const parentProjectId = parentRow?.projectId ?? null;
2398
2448
  await connection.execute(
2399
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2449
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2400
2450
  [
2401
2451
  id,
2402
2452
  args.datasetId,
2403
2453
  newVersion,
2454
+ parentOrganizationId,
2455
+ parentProjectId,
2404
2456
  jsonArg(args.input),
2405
2457
  jsonArg(args.groundTruth),
2406
2458
  jsonArg(args.metadata),
@@ -2417,6 +2469,8 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2417
2469
  id,
2418
2470
  datasetId: args.datasetId,
2419
2471
  datasetVersion: newVersion,
2472
+ organizationId: parentOrganizationId,
2473
+ projectId: parentProjectId,
2420
2474
  input: args.input,
2421
2475
  groundTruth: args.groundTruth,
2422
2476
  metadata: args.metadata,
@@ -2471,21 +2525,26 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2471
2525
  await connection.execute(`UPDATE ${tableDatasetsName} SET \`version\` = \`version\` + 1 WHERE id = ?`, [
2472
2526
  args.datasetId
2473
2527
  ]);
2474
- const [versionRows] = await connection.execute(
2475
- `SELECT \`version\` FROM ${tableDatasetsName} WHERE id = ?`,
2528
+ const [datasetRows] = await connection.execute(
2529
+ `SELECT \`version\`, \`organizationId\`, \`projectId\` FROM ${tableDatasetsName} WHERE id = ?`,
2476
2530
  [args.datasetId]
2477
2531
  );
2478
- const newVersion = versionRows[0]?.version;
2532
+ const parentRow = datasetRows[0];
2533
+ const newVersion = parentRow?.version;
2534
+ const parentOrganizationId = parentRow?.organizationId ?? null;
2535
+ const parentProjectId = parentRow?.projectId ?? null;
2479
2536
  await connection.execute(
2480
2537
  `UPDATE ${tableItemsName} SET \`validTo\` = ? WHERE \`id\` = ? AND \`validTo\` IS NULL AND \`isDeleted\` = 0`,
2481
2538
  [newVersion, args.id]
2482
2539
  );
2483
2540
  await connection.execute(
2484
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2541
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2485
2542
  [
2486
2543
  args.id,
2487
2544
  args.datasetId,
2488
2545
  newVersion,
2546
+ parentOrganizationId,
2547
+ parentProjectId,
2489
2548
  jsonArg(mergedInput),
2490
2549
  jsonArg(mergedGroundTruth),
2491
2550
  jsonArg(mergedMetadata),
@@ -2501,6 +2560,8 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2501
2560
  return {
2502
2561
  ...existing,
2503
2562
  datasetVersion: newVersion,
2563
+ organizationId: parentOrganizationId,
2564
+ projectId: parentProjectId,
2504
2565
  input: mergedInput,
2505
2566
  groundTruth: mergedGroundTruth,
2506
2567
  metadata: mergedMetadata,
@@ -2543,21 +2604,26 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2543
2604
  await connection.execute(`UPDATE ${tableDatasetsName} SET \`version\` = \`version\` + 1 WHERE id = ?`, [
2544
2605
  datasetId
2545
2606
  ]);
2546
- const [versionRows] = await connection.execute(
2547
- `SELECT \`version\` FROM ${tableDatasetsName} WHERE id = ?`,
2607
+ const [datasetRows] = await connection.execute(
2608
+ `SELECT \`version\`, \`organizationId\`, \`projectId\` FROM ${tableDatasetsName} WHERE id = ?`,
2548
2609
  [datasetId]
2549
2610
  );
2550
- const newVersion = versionRows[0]?.version;
2611
+ const parentRow = datasetRows[0];
2612
+ const newVersion = parentRow?.version;
2613
+ const parentOrganizationId = parentRow?.organizationId ?? null;
2614
+ const parentProjectId = parentRow?.projectId ?? null;
2551
2615
  await connection.execute(
2552
2616
  `UPDATE ${tableItemsName} SET \`validTo\` = ? WHERE \`id\` = ? AND \`validTo\` IS NULL AND \`isDeleted\` = 0`,
2553
2617
  [newVersion, id]
2554
2618
  );
2555
2619
  await connection.execute(
2556
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, NULL, 1, ?, ?, ?, ?, ?)`,
2620
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 1, ?, ?, ?, ?, ?)`,
2557
2621
  [
2558
2622
  id,
2559
2623
  datasetId,
2560
2624
  newVersion,
2625
+ parentOrganizationId,
2626
+ parentProjectId,
2561
2627
  jsonArg(existing.input),
2562
2628
  jsonArg(existing.groundTruth),
2563
2629
  jsonArg(existing.metadata),
@@ -2666,6 +2732,14 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2666
2732
  conditions.push(`\`validTo\` IS NULL`);
2667
2733
  conditions.push(`\`isDeleted\` = 0`);
2668
2734
  }
2735
+ if (args.filters?.organizationId !== void 0) {
2736
+ conditions.push(`\`organizationId\` = ?`);
2737
+ params.push(args.filters.organizationId);
2738
+ }
2739
+ if (args.filters?.projectId !== void 0) {
2740
+ conditions.push(`\`projectId\` = ?`);
2741
+ params.push(args.filters.projectId);
2742
+ }
2669
2743
  if (args.search) {
2670
2744
  conditions.push(`(LOWER(\`input\`) LIKE ? OR LOWER(COALESCE(\`groundTruth\`, '')) LIKE ?)`);
2671
2745
  const searchPattern = `%${args.search.toLowerCase()}%`;
@@ -2810,16 +2884,20 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2810
2884
  [input.datasetId]
2811
2885
  );
2812
2886
  const newVersion = versionRows[0]?.version;
2887
+ const parentOrganizationId = dataset.organizationId ?? null;
2888
+ const parentProjectId = dataset.projectId ?? null;
2813
2889
  const items = [];
2814
2890
  for (const itemInput of input.items) {
2815
2891
  const id = crypto$1.randomUUID();
2816
2892
  items.push({ id, itemInput });
2817
2893
  await connection.execute(
2818
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2894
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2819
2895
  [
2820
2896
  id,
2821
2897
  input.datasetId,
2822
2898
  newVersion,
2899
+ parentOrganizationId,
2900
+ parentProjectId,
2823
2901
  jsonArg(itemInput.input),
2824
2902
  jsonArg(itemInput.groundTruth),
2825
2903
  jsonArg(itemInput.metadata),
@@ -2837,6 +2915,8 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2837
2915
  id,
2838
2916
  datasetId: input.datasetId,
2839
2917
  datasetVersion: newVersion,
2918
+ organizationId: parentOrganizationId,
2919
+ projectId: parentProjectId,
2840
2920
  input: itemInput.input,
2841
2921
  groundTruth: itemInput.groundTruth,
2842
2922
  metadata: itemInput.metadata,
@@ -2892,17 +2972,21 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2892
2972
  [input.datasetId]
2893
2973
  );
2894
2974
  const newVersion = versionRows[0]?.version;
2975
+ const parentOrganizationId = dataset.organizationId ?? null;
2976
+ const parentProjectId = dataset.projectId ?? null;
2895
2977
  for (const item of currentItems) {
2896
2978
  await connection.execute(
2897
2979
  `UPDATE ${tableItemsName} SET \`validTo\` = ? WHERE \`id\` = ? AND \`validTo\` IS NULL AND \`isDeleted\` = 0`,
2898
2980
  [newVersion, item.id]
2899
2981
  );
2900
2982
  await connection.execute(
2901
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, NULL, 1, ?, ?, ?, ?, ?)`,
2983
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 1, ?, ?, ?, ?, ?)`,
2902
2984
  [
2903
2985
  item.id,
2904
2986
  input.datasetId,
2905
2987
  newVersion,
2988
+ parentOrganizationId,
2989
+ parentProjectId,
2906
2990
  jsonArg(item.input),
2907
2991
  jsonArg(item.groundTruth),
2908
2992
  jsonArg(item.metadata),
@@ -2954,10 +3038,22 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
2954
3038
  static MANAGED_TABLES = [storage.TABLE_EXPERIMENTS, storage.TABLE_EXPERIMENT_RESULTS];
2955
3039
  /**
2956
3040
  * Returns default index definitions for the experiments domain tables.
2957
- * Currently no default indexes are defined for experiments.
2958
3041
  */
2959
3042
  static getDefaultIndexDefs(_prefix = "") {
2960
- return [];
3043
+ return [
3044
+ // Tenancy: leading-tenant indexes for multi-tenant scans (parity with
3045
+ // pg/libsql/spanner/mongodb experiments adapters).
3046
+ {
3047
+ name: "idx_experiments_org_project",
3048
+ table: storage.TABLE_EXPERIMENTS,
3049
+ columns: ["organizationId", "projectId"]
3050
+ },
3051
+ {
3052
+ name: "idx_experiment_results_org_project",
3053
+ table: storage.TABLE_EXPERIMENT_RESULTS,
3054
+ columns: ["organizationId", "projectId"]
3055
+ }
3056
+ ];
2961
3057
  }
2962
3058
  /**
2963
3059
  * Exports DDL statements for all managed tables.
@@ -2988,10 +3084,12 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
2988
3084
  }
2989
3085
  /**
2990
3086
  * Creates default indexes for optimal query performance.
2991
- * Currently no default indexes are defined for experiments.
2992
3087
  */
2993
3088
  async createDefaultIndexes() {
2994
3089
  if (this.#skipDefaultIndexes) return;
3090
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
3091
+ await this.operations.createIndex(indexDef);
3092
+ }
2995
3093
  }
2996
3094
  /**
2997
3095
  * Creates custom user-defined indexes for this domain's tables.
@@ -3005,6 +3103,16 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3005
3103
  async init() {
3006
3104
  await this.operations.createTable({ tableName: storage.TABLE_EXPERIMENTS, schema: storage.EXPERIMENTS_SCHEMA });
3007
3105
  await this.operations.createTable({ tableName: storage.TABLE_EXPERIMENT_RESULTS, schema: storage.EXPERIMENT_RESULTS_SCHEMA });
3106
+ await this.operations.alterTable({
3107
+ tableName: storage.TABLE_EXPERIMENTS,
3108
+ schema: storage.EXPERIMENTS_SCHEMA,
3109
+ ifNotExists: ["organizationId", "projectId"]
3110
+ });
3111
+ await this.operations.alterTable({
3112
+ tableName: storage.TABLE_EXPERIMENT_RESULTS,
3113
+ schema: storage.EXPERIMENT_RESULTS_SCHEMA,
3114
+ ifNotExists: ["organizationId", "projectId"]
3115
+ });
3008
3116
  await this.createDefaultIndexes();
3009
3117
  await this.createCustomIndexes();
3010
3118
  }
@@ -3017,6 +3125,8 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3017
3125
  id: row.id,
3018
3126
  datasetId: row.datasetId ?? null,
3019
3127
  datasetVersion: row.datasetVersion ?? null,
3128
+ organizationId: row.organizationId ?? null,
3129
+ projectId: row.projectId ?? null,
3020
3130
  targetType: row.targetType,
3021
3131
  targetId: row.targetId,
3022
3132
  name: row.name ?? void 0,
@@ -3039,6 +3149,8 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3039
3149
  experimentId: row.experimentId,
3040
3150
  itemId: row.itemId,
3041
3151
  itemDatasetVersion: row.itemDatasetVersion ?? null,
3152
+ organizationId: row.organizationId ?? null,
3153
+ projectId: row.projectId ?? null,
3042
3154
  input: parseJSON2(row.input),
3043
3155
  output: row.output ? parseJSON2(row.output) : null,
3044
3156
  groundTruth: row.groundTruth ? parseJSON2(row.groundTruth) : null,
@@ -3062,6 +3174,8 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3062
3174
  id,
3063
3175
  datasetId: input.datasetId ?? null,
3064
3176
  datasetVersion: input.datasetVersion ?? null,
3177
+ organizationId: input.organizationId ?? null,
3178
+ projectId: input.projectId ?? null,
3065
3179
  targetType: input.targetType,
3066
3180
  targetId: input.targetId,
3067
3181
  name: input.name ?? null,
@@ -3082,6 +3196,8 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3082
3196
  id,
3083
3197
  datasetId: input.datasetId,
3084
3198
  datasetVersion: input.datasetVersion,
3199
+ organizationId: input.organizationId ?? null,
3200
+ projectId: input.projectId ?? null,
3085
3201
  targetType: input.targetType,
3086
3202
  targetId: input.targetId,
3087
3203
  name: input.name,
@@ -3176,6 +3292,17 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3176
3292
  conditions.push(`${quoteIdentifier("datasetId", "column name")} = ?`);
3177
3293
  params.push(args.datasetId);
3178
3294
  }
3295
+ if (args.filters) {
3296
+ const { organizationId, projectId } = args.filters;
3297
+ if (organizationId !== void 0) {
3298
+ conditions.push(`${quoteIdentifier("organizationId", "column name")} = ?`);
3299
+ params.push(organizationId);
3300
+ }
3301
+ if (projectId !== void 0) {
3302
+ conditions.push(`${quoteIdentifier("projectId", "column name")} = ?`);
3303
+ params.push(projectId);
3304
+ }
3305
+ }
3179
3306
  const whereClause = {
3180
3307
  sql: conditions.length > 0 ? ` WHERE ${conditions.join(" AND ")}` : "",
3181
3308
  args: params
@@ -3279,6 +3406,8 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3279
3406
  experimentId: input.experimentId,
3280
3407
  itemId: input.itemId,
3281
3408
  itemDatasetVersion: input.itemDatasetVersion ?? null,
3409
+ organizationId: input.organizationId ?? null,
3410
+ projectId: input.projectId ?? null,
3282
3411
  input: JSON.stringify(input.input),
3283
3412
  output: input.output ? JSON.stringify(input.output) : null,
3284
3413
  groundTruth: input.groundTruth ? JSON.stringify(input.groundTruth) : null,
@@ -3297,6 +3426,8 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3297
3426
  experimentId: input.experimentId,
3298
3427
  itemId: input.itemId,
3299
3428
  itemDatasetVersion: input.itemDatasetVersion,
3429
+ organizationId: input.organizationId ?? null,
3430
+ projectId: input.projectId ?? null,
3300
3431
  input: input.input,
3301
3432
  output: input.output,
3302
3433
  groundTruth: input.groundTruth,
@@ -3414,9 +3545,30 @@ var ExperimentsMySQL = class _ExperimentsMySQL extends storage.ExperimentsStorag
3414
3545
  async listExperimentResults(args) {
3415
3546
  try {
3416
3547
  const { page, perPage: perPageInput } = args.pagination;
3548
+ const conditions = [`${quoteIdentifier("experimentId", "column name")} = ?`];
3549
+ const params = [args.experimentId];
3550
+ if (args.traceId) {
3551
+ conditions.push(`${quoteIdentifier("traceId", "column name")} = ?`);
3552
+ params.push(args.traceId);
3553
+ }
3554
+ if (args.status) {
3555
+ conditions.push(`${quoteIdentifier("status", "column name")} = ?`);
3556
+ params.push(args.status);
3557
+ }
3558
+ if (args.filters) {
3559
+ const { organizationId, projectId } = args.filters;
3560
+ if (organizationId !== void 0) {
3561
+ conditions.push(`${quoteIdentifier("organizationId", "column name")} = ?`);
3562
+ params.push(organizationId);
3563
+ }
3564
+ if (projectId !== void 0) {
3565
+ conditions.push(`${quoteIdentifier("projectId", "column name")} = ?`);
3566
+ params.push(projectId);
3567
+ }
3568
+ }
3417
3569
  const whereClause = {
3418
- sql: ` WHERE ${quoteIdentifier("experimentId", "column name")} = ?`,
3419
- args: [args.experimentId]
3570
+ sql: ` WHERE ${conditions.join(" AND ")}`,
3571
+ args: params
3420
3572
  };
3421
3573
  const total = await this.operations.loadTotalCount({ tableName: storage.TABLE_EXPERIMENT_RESULTS, whereClause });
3422
3574
  if (total === 0) {