@mastra/mysql 0.3.4 → 0.4.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/CHANGELOG.md CHANGED
@@ -1,5 +1,57 @@
1
1
  # @mastra/mysql
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Added atomic caller-defined dataset IDs for idempotent dataset creation across built-in storage adapters. Supplying `id` to `mastra.datasets.create()` now creates the dataset once and resolves compatible retries to the persisted record; incompatible immutable identity fields throw `DATASET_ID_CONFLICT`. ([#19370](https://github.com/mastra-ai/mastra/pull/19370))
8
+
9
+ - Added caller-defined dataset item identities for safe retries across all dataset storage adapters. ([#19384](https://github.com/mastra-ai/mastra/pull/19384))
10
+
11
+ Dataset items can now include an `externalId` when calling `addItem` or `addItems`:
12
+
13
+ ```ts
14
+ await dataset.addItem({
15
+ externalId: 'source-item-123',
16
+ input: { prompt: 'Hello' },
17
+ });
18
+ ```
19
+
20
+ Retrying with the same identity and payload returns the existing item. Reusing an identity with different content returns a typed conflict, including during concurrent writes. Updates and deletes preserve the identity, Spanner retries transactions without changing the outcome, and MySQL batch writes now preserve every supported dataset item field.
21
+
22
+ ### Patch Changes
23
+
24
+ - Raised the `@mastra/core` peer dependency floor to `>=1.51.0-0` so the dataset item identity helpers used by the storage adapters are available at runtime. ([#19384](https://github.com/mastra-ai/mastra/pull/19384))
25
+
26
+ - Updated dependencies [[`bd6d240`](https://github.com/mastra-ai/mastra/commit/bd6d2402db93dddaef0721667e7e8a030e7c6e16), [`0111486`](https://github.com/mastra-ai/mastra/commit/01114867612593eef5cfa2fda6a1194dfedda841), [`96a3749`](https://github.com/mastra-ai/mastra/commit/96a37492235f5b8076b3e3177d83ed5a5e44a640), [`fe1bda0`](https://github.com/mastra-ai/mastra/commit/fe1bda06f6af92a694a51712db747cda1e7185f0), [`25e7c12`](https://github.com/mastra-ai/mastra/commit/25e7c126a770069ae7fb7ecf1d2adb40e017b009), [`1ce5121`](https://github.com/mastra-ai/mastra/commit/1ce512155d122bb21f47d98383e82ffbf84b39e8), [`fb8aea3`](https://github.com/mastra-ai/mastra/commit/fb8aea384291e77311be3a64ee1717320d5c3c73), [`4adc391`](https://github.com/mastra-ai/mastra/commit/4adc3911075249c352bb4832d2471922826344de), [`a5c6337`](https://github.com/mastra-ai/mastra/commit/a5c6337d23c7686c81a32ce62f550f610543a240), [`3cfc47a`](https://github.com/mastra-ai/mastra/commit/3cfc47a6b89940aadd0f46fb01ae9624a73a865d), [`2bb7817`](https://github.com/mastra-ai/mastra/commit/2bb78176112fde628483de2830528f7eee911e56), [`51d9870`](https://github.com/mastra-ai/mastra/commit/51d987032c689c2855374d0f244f5d654da809d1), [`5cab274`](https://github.com/mastra-ai/mastra/commit/5cab2744250e22d12fefa7b32637dce224233cee), [`7fa27d3`](https://github.com/mastra-ai/mastra/commit/7fa27d3b6f5ed68cd34e454a4d3ad9c482a0cfbc), [`8b97958`](https://github.com/mastra-ai/mastra/commit/8b979589f9aa59ba67cac565949475f2ffeb4ac3), [`8410541`](https://github.com/mastra-ai/mastra/commit/84105412c60ecd3bb33a9838146f59c4b588228f), [`a58dcbb`](https://github.com/mastra-ai/mastra/commit/a58dcbb546d7e1d65ebdc1f39e55f0908fcd9391), [`aa38805`](https://github.com/mastra-ai/mastra/commit/aa38805b878b827403be785eb90688d7172f5a40), [`153bd3b`](https://github.com/mastra-ai/mastra/commit/153bd3b396bdfed6b74cf43de12db8fd2d83c04a), [`45a8e65`](https://github.com/mastra-ai/mastra/commit/45a8e65e1556d1362cb3f25187023c36de26661d), [`e955965`](https://github.com/mastra-ai/mastra/commit/e955965dce575a903e37cf054d28ea99aa48785e), [`2d22570`](https://github.com/mastra-ai/mastra/commit/2d22570c7dfdd02123d0ecc529efb05ccba2d9fc), [`07bb863`](https://github.com/mastra-ai/mastra/commit/07bb8631919c6f7cf377dccd45b096e0f17fbed0), [`c8ed116`](https://github.com/mastra-ai/mastra/commit/c8ed11699f62bcac70102ab4ec84d80d20541da6), [`01b338c`](https://github.com/mastra-ai/mastra/commit/01b338c56271f0219606710e3e8b26dee27ac6c2), [`a99eae8`](https://github.com/mastra-ai/mastra/commit/a99eae8908e500c1b2d12f9d277be616b98617a5), [`860ef7e`](https://github.com/mastra-ai/mastra/commit/860ef7e77d92b63469cbe5857aa1e626197e43e9), [`17e818c`](https://github.com/mastra-ai/mastra/commit/17e818c51a958ba90641b1a959dc38faf8c034e9), [`edce8d2`](https://github.com/mastra-ai/mastra/commit/edce8d2769f19e27a05737c627af2d765472a4f8), [`8a586ec`](https://github.com/mastra-ai/mastra/commit/8a586eca9a4914f31dff6140d0d45ac375b00669), [`4451dfe`](https://github.com/mastra-ai/mastra/commit/4451dfe857428e7abcc0261a507a2e186dae6d47), [`8b7361d`](https://github.com/mastra-ai/mastra/commit/8b7361d35de68b80d05d30a74e0c69e7218fd612), [`1d39058`](https://github.com/mastra-ai/mastra/commit/1d39058e548efd691799985d5c8af2737f1c3bd2), [`3927473`](https://github.com/mastra-ai/mastra/commit/392747323ddb10c643d12be7b9ae913159dfaeed), [`dce50dc`](https://github.com/mastra-ai/mastra/commit/dce50dc9a1c1fcd0f427bb5f6250ec74910cb04b), [`fd13f8e`](https://github.com/mastra-ai/mastra/commit/fd13f8e21990f9904c3eedba3a626bb4a929cdb8), [`634caff`](https://github.com/mastra-ai/mastra/commit/634caff29a9200ad058b67d53f96d9e5832fb8a2), [`f703f87`](https://github.com/mastra-ai/mastra/commit/f703f878de072d51fda557f9c50867d8252bef05), [`3e26c87`](https://github.com/mastra-ai/mastra/commit/3e26c87de0c5bc2583b795ce6ca5889b6b161acb), [`33f2b88`](https://github.com/mastra-ai/mastra/commit/33f2b88842c09a567f906fac4cb61cd5277ced59), [`177010f`](https://github.com/mastra-ai/mastra/commit/177010ff096d2e4b28d89803be5b1a4cad2a0d6b), [`0ad646f`](https://github.com/mastra-ai/mastra/commit/0ad646f71a530f2454664299e5e01bfd13fa12e5), [`b486abf`](https://github.com/mastra-ai/mastra/commit/b486abfa2a7528c6f527e4015c819ea9fa54aaad), [`54a51e0`](https://github.com/mastra-ai/mastra/commit/54a51e0a484fe1ebad3fb1f7ef5282a075709eb7), [`c43f3a9`](https://github.com/mastra-ai/mastra/commit/c43f3a9d1efde99b38789364ba4d0ba670f430e3), [`a5008f2`](https://github.com/mastra-ai/mastra/commit/a5008f22ae710ad9402ea9f2547d8c02f74d384b), [`e2d5f37`](https://github.com/mastra-ai/mastra/commit/e2d5f373bd289be534d5f8694d34465010533df6), [`4ce0163`](https://github.com/mastra-ai/mastra/commit/4ce0163dc86e675a86809685c8ce6c49f1aeb87e), [`4378341`](https://github.com/mastra-ai/mastra/commit/43783412df5ea3dd35f5b1f6e4851e79c346fc89)]:
27
+ - @mastra/core@1.51.0
28
+
29
+ ## 0.4.0-alpha.0
30
+
31
+ ### Minor Changes
32
+
33
+ - Added atomic caller-defined dataset IDs for idempotent dataset creation across built-in storage adapters. Supplying `id` to `mastra.datasets.create()` now creates the dataset once and resolves compatible retries to the persisted record; incompatible immutable identity fields throw `DATASET_ID_CONFLICT`. ([#19370](https://github.com/mastra-ai/mastra/pull/19370))
34
+
35
+ - Added caller-defined dataset item identities for safe retries across all dataset storage adapters. ([#19384](https://github.com/mastra-ai/mastra/pull/19384))
36
+
37
+ Dataset items can now include an `externalId` when calling `addItem` or `addItems`:
38
+
39
+ ```ts
40
+ await dataset.addItem({
41
+ externalId: 'source-item-123',
42
+ input: { prompt: 'Hello' },
43
+ });
44
+ ```
45
+
46
+ Retrying with the same identity and payload returns the existing item. Reusing an identity with different content returns a typed conflict, including during concurrent writes. Updates and deletes preserve the identity, Spanner retries transactions without changing the outcome, and MySQL batch writes now preserve every supported dataset item field.
47
+
48
+ ### Patch Changes
49
+
50
+ - Raised the `@mastra/core` peer dependency floor to `>=1.51.0-0` so the dataset item identity helpers used by the storage adapters are available at runtime. ([#19384](https://github.com/mastra-ai/mastra/pull/19384))
51
+
52
+ - Updated dependencies [[`a99eae8`](https://github.com/mastra-ai/mastra/commit/a99eae8908e500c1b2d12f9d277be616b98617a5), [`fd13f8e`](https://github.com/mastra-ai/mastra/commit/fd13f8e21990f9904c3eedba3a626bb4a929cdb8), [`f703f87`](https://github.com/mastra-ai/mastra/commit/f703f878de072d51fda557f9c50867d8252bef05), [`0ad646f`](https://github.com/mastra-ai/mastra/commit/0ad646f71a530f2454664299e5e01bfd13fa12e5)]:
53
+ - @mastra/core@1.51.0-alpha.13
54
+
3
55
  ## 0.3.4
4
56
 
5
57
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -85,7 +85,7 @@ function transformToSqlValue(value) {
85
85
  }
86
86
  return value;
87
87
  }
88
- function prepareStatement({
88
+ function prepareInsertOnlyStatement({
89
89
  tableName,
90
90
  record,
91
91
  database
@@ -98,11 +98,22 @@ function prepareStatement({
98
98
  const columnIdentifiers = columns.map((column) => quoteIdentifier(column, "column name"));
99
99
  const values = columns.map((column) => transformToSqlValue(record[column]));
100
100
  const placeholders = columns.map(() => "?").join(", ");
101
- const updateAssignments = columnIdentifiers.map((column) => `${column} = ?`).join(", ");
102
- const sql = `INSERT INTO ${tableIdent} (${columnIdentifiers.join(", ")}) VALUES (${placeholders}) ON DUPLICATE KEY UPDATE ${updateAssignments}`;
103
101
  return {
104
- sql,
105
- args: [...values, ...values]
102
+ sql: `INSERT INTO ${tableIdent} (${columnIdentifiers.join(", ")}) VALUES (${placeholders})`,
103
+ args: values
104
+ };
105
+ }
106
+ function prepareStatement({
107
+ tableName,
108
+ record,
109
+ database
110
+ }) {
111
+ const statement = prepareInsertOnlyStatement({ tableName, record, database });
112
+ const columns = Object.keys(record).map((column) => quoteIdentifier(column, "column name"));
113
+ const updateAssignments = columns.map((column) => `${column} = ?`).join(", ");
114
+ return {
115
+ sql: `${statement.sql} ON DUPLICATE KEY UPDATE ${updateAssignments}`,
116
+ args: [...statement.args, ...statement.args]
106
117
  };
107
118
  }
108
119
  function prepareUpdateStatement({
@@ -470,6 +481,22 @@ var StoreOperationsMySQL = class extends storage.StoreOperations {
470
481
  );
471
482
  }
472
483
  }
484
+ async insertOnly({ tableName, record }) {
485
+ try {
486
+ const statement = prepareInsertOnlyStatement({ tableName, record, database: this.database });
487
+ await this.pool.execute(statement.sql, statement.args);
488
+ } catch (error$1) {
489
+ throw new error.MastraError(
490
+ {
491
+ id: "MYSQL_STORE_INSERT_FAILED",
492
+ domain: error.ErrorDomain.STORAGE,
493
+ category: error.ErrorCategory.THIRD_PARTY,
494
+ details: { tableName }
495
+ },
496
+ error$1
497
+ );
498
+ }
499
+ }
473
500
  async batchInsert({ tableName, records }) {
474
501
  if (records.length === 0) return;
475
502
  try {
@@ -2087,8 +2114,14 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2087
2114
  * Returns default index definitions for the datasets domain tables.
2088
2115
  * Currently no default indexes are defined for datasets.
2089
2116
  */
2090
- static getDefaultIndexDefs(_prefix = "") {
2091
- return [];
2117
+ static getDefaultIndexDefs(prefix = "") {
2118
+ return [
2119
+ {
2120
+ name: `${prefix}idx_dataset_items_dataset_externalid_version`,
2121
+ table: storage.TABLE_DATASET_ITEMS,
2122
+ columns: ["datasetId", "externalId", "datasetVersion"]
2123
+ }
2124
+ ];
2092
2125
  }
2093
2126
  /**
2094
2127
  * Exports DDL statements for all managed tables.
@@ -2128,6 +2161,9 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2128
2161
  */
2129
2162
  async createDefaultIndexes() {
2130
2163
  if (this.#skipDefaultIndexes) return;
2164
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
2165
+ await this.operations.createIndex(indexDef);
2166
+ }
2131
2167
  }
2132
2168
  /**
2133
2169
  * Creates custom user-defined indexes for this domain's tables.
@@ -2160,7 +2196,15 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2160
2196
  await this.operations.alterTable({
2161
2197
  tableName: storage.TABLE_DATASET_ITEMS,
2162
2198
  schema: storage.DATASET_ITEMS_SCHEMA,
2163
- ifNotExists: ["organizationId", "projectId"]
2199
+ ifNotExists: [
2200
+ "organizationId",
2201
+ "projectId",
2202
+ "requestContext",
2203
+ "source",
2204
+ "expectedTrajectory",
2205
+ "toolMocks",
2206
+ "externalId"
2207
+ ]
2164
2208
  });
2165
2209
  await this.createDefaultIndexes();
2166
2210
  await this.createCustomIndexes();
@@ -2211,11 +2255,16 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2211
2255
  id: row.id,
2212
2256
  datasetId: row.datasetId,
2213
2257
  datasetVersion: row.datasetVersion,
2258
+ externalId: row.externalId ?? null,
2214
2259
  organizationId: row.organizationId ?? null,
2215
2260
  projectId: row.projectId ?? null,
2216
2261
  input: parseJSON(row.input),
2217
2262
  groundTruth: row.groundTruth ? parseJSON(row.groundTruth) : void 0,
2263
+ expectedTrajectory: row.expectedTrajectory ? parseJSON(row.expectedTrajectory) : void 0,
2264
+ toolMocks: row.toolMocks ? parseJSON(row.toolMocks) : void 0,
2265
+ requestContext: row.requestContext ? parseJSON(row.requestContext) : void 0,
2218
2266
  metadata: row.metadata ? parseJSON(row.metadata) : void 0,
2267
+ source: row.source ? parseJSON(row.source) : void 0,
2219
2268
  createdAt: parseDateTime(row.createdAt) ?? /* @__PURE__ */ new Date(),
2220
2269
  updatedAt: parseDateTime(row.updatedAt) ?? /* @__PURE__ */ new Date()
2221
2270
  };
@@ -2225,13 +2274,18 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2225
2274
  id: row.id,
2226
2275
  datasetId: row.datasetId,
2227
2276
  datasetVersion: row.datasetVersion,
2277
+ externalId: row.externalId ?? null,
2228
2278
  organizationId: row.organizationId ?? null,
2229
2279
  projectId: row.projectId ?? null,
2230
2280
  validTo: row.validTo,
2231
2281
  isDeleted: Boolean(row.isDeleted),
2232
2282
  input: parseJSON(row.input),
2233
2283
  groundTruth: row.groundTruth ? parseJSON(row.groundTruth) : void 0,
2284
+ expectedTrajectory: row.expectedTrajectory ? parseJSON(row.expectedTrajectory) : void 0,
2285
+ toolMocks: row.toolMocks ? parseJSON(row.toolMocks) : void 0,
2286
+ requestContext: row.requestContext ? parseJSON(row.requestContext) : void 0,
2234
2287
  metadata: row.metadata ? parseJSON(row.metadata) : void 0,
2288
+ source: row.source ? parseJSON(row.source) : void 0,
2235
2289
  createdAt: parseDateTime(row.createdAt) ?? /* @__PURE__ */ new Date(),
2236
2290
  updatedAt: parseDateTime(row.updatedAt) ?? /* @__PURE__ */ new Date()
2237
2291
  };
@@ -2247,9 +2301,11 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2247
2301
  // --- Dataset CRUD ---
2248
2302
  async createDataset(input) {
2249
2303
  try {
2250
- const id = crypto$1.randomUUID();
2304
+ const id = input.id ?? crypto$1.randomUUID();
2305
+ if (input.id !== void 0) this.validateCallerDefinedDatasetId(input.id);
2251
2306
  const now = /* @__PURE__ */ new Date();
2252
- await this.operations.insert({
2307
+ const insert = input.id === void 0 ? this.operations.insert.bind(this.operations) : this.operations.insertOnly.bind(this.operations);
2308
+ await insert({
2253
2309
  tableName: storage.TABLE_DATASETS,
2254
2310
  record: {
2255
2311
  id,
@@ -2291,6 +2347,11 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2291
2347
  updatedAt: now
2292
2348
  };
2293
2349
  } catch (error$1) {
2350
+ if (input.id !== void 0 && storage.hasErrorCode(error$1, /* @__PURE__ */ new Set([1062, "ER_DUP_ENTRY"]))) {
2351
+ const existing = await this.getDatasetById({ id: input.id });
2352
+ if (existing) return this.resolveExistingDataset(existing, { ...input, id: input.id });
2353
+ }
2354
+ if (error$1 instanceof error.MastraError) throw error$1;
2294
2355
  throw new error.MastraError(
2295
2356
  {
2296
2357
  id: "MYSQL_CREATE_DATASET_FAILED",
@@ -2619,7 +2680,11 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2619
2680
  const tableVersionsName = formatTableName(storage.TABLE_DATASET_VERSIONS);
2620
2681
  const mergedInput = args.input ?? existing.input;
2621
2682
  const mergedGroundTruth = args.groundTruth ?? existing.groundTruth;
2683
+ const mergedExpectedTrajectory = args.expectedTrajectory ?? existing.expectedTrajectory;
2684
+ const mergedToolMocks = args.toolMocks ?? existing.toolMocks;
2685
+ const mergedRequestContext = args.requestContext ?? existing.requestContext;
2622
2686
  const mergedMetadata = args.metadata ?? existing.metadata;
2687
+ const mergedSource = args.source ?? existing.source;
2623
2688
  await connection.execute(`UPDATE ${tableDatasetsName} SET \`version\` = \`version\` + 1 WHERE id = ?`, [
2624
2689
  args.datasetId
2625
2690
  ]);
@@ -2636,16 +2701,21 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2636
2701
  [newVersion, args.id]
2637
2702
  );
2638
2703
  await connection.execute(
2639
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
2704
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`externalId\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`expectedTrajectory\`, \`toolMocks\`, \`requestContext\`, \`metadata\`, \`source\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
2640
2705
  [
2641
2706
  args.id,
2642
2707
  args.datasetId,
2643
2708
  newVersion,
2709
+ existing.externalId ?? null,
2644
2710
  parentOrganizationId,
2645
2711
  parentProjectId,
2646
2712
  jsonArg(mergedInput),
2647
2713
  jsonArg(mergedGroundTruth),
2714
+ jsonArg(mergedExpectedTrajectory),
2715
+ jsonArg(mergedToolMocks),
2716
+ jsonArg(mergedRequestContext),
2648
2717
  jsonArg(mergedMetadata),
2718
+ jsonArg(mergedSource),
2649
2719
  transformToSqlValue(existing.createdAt),
2650
2720
  transformToSqlValue(now)
2651
2721
  ]
@@ -2662,7 +2732,11 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2662
2732
  projectId: parentProjectId,
2663
2733
  input: mergedInput,
2664
2734
  groundTruth: mergedGroundTruth,
2735
+ expectedTrajectory: mergedExpectedTrajectory,
2736
+ toolMocks: mergedToolMocks,
2737
+ requestContext: mergedRequestContext,
2665
2738
  metadata: mergedMetadata,
2739
+ source: mergedSource,
2666
2740
  updatedAt: now
2667
2741
  };
2668
2742
  } catch (error$1) {
@@ -2715,16 +2789,21 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2715
2789
  [newVersion, id]
2716
2790
  );
2717
2791
  await connection.execute(
2718
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 1, ?, ?, ?, ?, ?)`,
2792
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`externalId\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`expectedTrajectory\`, \`toolMocks\`, \`requestContext\`, \`metadata\`, \`source\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, ?, NULL, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
2719
2793
  [
2720
2794
  id,
2721
2795
  datasetId,
2722
2796
  newVersion,
2797
+ existing.externalId ?? null,
2723
2798
  parentOrganizationId,
2724
2799
  parentProjectId,
2725
2800
  jsonArg(existing.input),
2726
2801
  jsonArg(existing.groundTruth),
2802
+ jsonArg(existing.expectedTrajectory),
2803
+ jsonArg(existing.toolMocks),
2804
+ jsonArg(existing.requestContext),
2727
2805
  jsonArg(existing.metadata),
2806
+ jsonArg(existing.source),
2728
2807
  transformToSqlValue(existing.createdAt),
2729
2808
  transformToSqlValue(now)
2730
2809
  ]
@@ -2957,70 +3036,89 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
2957
3036
  for (const item of input.items) {
2958
3037
  this.#rejectToolMocks(item.toolMocks);
2959
3038
  }
2960
- const dataset = await this.getDatasetById({ id: input.datasetId });
2961
- if (!dataset) {
2962
- throw new error.MastraError({
2963
- id: "MYSQL_BULK_ADD_ITEMS_DATASET_NOT_FOUND",
2964
- domain: error.ErrorDomain.STORAGE,
2965
- category: error.ErrorCategory.USER,
2966
- details: { datasetId: input.datasetId }
2967
- });
2968
- }
2969
3039
  const connection = await this.pool.getConnection();
2970
3040
  try {
2971
3041
  await connection.beginTransaction();
2972
- const now = /* @__PURE__ */ new Date();
2973
- const versionId = crypto$1.randomUUID();
2974
3042
  const tableDatasetsName = formatTableName(storage.TABLE_DATASETS);
2975
3043
  const tableItemsName = formatTableName(storage.TABLE_DATASET_ITEMS);
2976
3044
  const tableVersionsName = formatTableName(storage.TABLE_DATASET_VERSIONS);
2977
- await connection.execute(`UPDATE ${tableDatasetsName} SET \`version\` = \`version\` + 1 WHERE id = ?`, [
2978
- input.datasetId
2979
- ]);
2980
- const [versionRows] = await connection.execute(
2981
- `SELECT \`version\` FROM ${tableDatasetsName} WHERE id = ?`,
3045
+ const [datasetRows] = await connection.execute(
3046
+ `SELECT \`version\`, \`organizationId\`, \`projectId\` FROM ${tableDatasetsName} WHERE id = ? FOR UPDATE`,
2982
3047
  [input.datasetId]
2983
3048
  );
2984
- const newVersion = versionRows[0]?.version;
2985
- const parentOrganizationId = dataset.organizationId ?? null;
2986
- const parentProjectId = dataset.projectId ?? null;
2987
- const items = [];
2988
- for (const itemInput of input.items) {
2989
- const id = crypto$1.randomUUID();
2990
- items.push({ id, itemInput });
3049
+ const dataset = datasetRows[0];
3050
+ if (!dataset) {
3051
+ throw new error.MastraError({
3052
+ id: "MYSQL_BULK_ADD_ITEMS_DATASET_NOT_FOUND",
3053
+ domain: error.ErrorDomain.STORAGE,
3054
+ category: error.ErrorCategory.USER,
3055
+ details: { datasetId: input.datasetId }
3056
+ });
3057
+ }
3058
+ const externalIds = [...new Set(input.items.flatMap((item) => item.externalId ? [item.externalId] : []))];
3059
+ let historyRows = [];
3060
+ if (externalIds.length > 0) {
3061
+ const placeholders = externalIds.map(() => "?").join(", ");
3062
+ const [rows] = await connection.execute(
3063
+ `SELECT * FROM ${tableItemsName} WHERE \`datasetId\` = ? AND \`externalId\` IN (${placeholders}) ORDER BY \`datasetVersion\` ASC`,
3064
+ [input.datasetId, ...externalIds]
3065
+ );
3066
+ historyRows = rows.map((row) => this.mapItemFull(row));
3067
+ }
3068
+ const plan = this.planDatasetItemBatch(input.items, historyRows, crypto$1.randomUUID);
3069
+ const existingItems = new Map(
3070
+ [...plan.existingCurrentItems].map(([id, row]) => [id, this.datasetItemFromRow(row)])
3071
+ );
3072
+ if (plan.inserts.length === 0) {
3073
+ await connection.commit();
3074
+ return plan.resolvedIds.map((id) => existingItems.get(id));
3075
+ }
3076
+ const now = /* @__PURE__ */ new Date();
3077
+ const newVersion = Number(dataset.version) + 1;
3078
+ await connection.execute(`UPDATE ${tableDatasetsName} SET \`version\` = ? WHERE id = ?`, [
3079
+ newVersion,
3080
+ input.datasetId
3081
+ ]);
3082
+ const inserted = /* @__PURE__ */ new Map();
3083
+ for (const { id, item } of plan.inserts) {
2991
3084
  await connection.execute(
2992
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?)`,
3085
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`externalId\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`expectedTrajectory\`, \`toolMocks\`, \`requestContext\`, \`metadata\`, \`source\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, ?, NULL, 0, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
2993
3086
  [
2994
3087
  id,
2995
3088
  input.datasetId,
2996
3089
  newVersion,
2997
- parentOrganizationId,
2998
- parentProjectId,
2999
- jsonArg(itemInput.input),
3000
- jsonArg(itemInput.groundTruth),
3001
- jsonArg(itemInput.metadata),
3090
+ item.externalId ?? null,
3091
+ dataset.organizationId ?? null,
3092
+ dataset.projectId ?? null,
3093
+ jsonArg(item.input),
3094
+ jsonArg(item.groundTruth),
3095
+ jsonArg(item.expectedTrajectory),
3096
+ jsonArg(item.toolMocks),
3097
+ jsonArg(item.requestContext),
3098
+ jsonArg(item.metadata),
3099
+ jsonArg(item.source),
3002
3100
  transformToSqlValue(now),
3003
3101
  transformToSqlValue(now)
3004
3102
  ]
3005
3103
  );
3104
+ inserted.set(id, {
3105
+ id,
3106
+ datasetId: input.datasetId,
3107
+ datasetVersion: newVersion,
3108
+ externalId: item.externalId ?? null,
3109
+ organizationId: dataset.organizationId ?? null,
3110
+ projectId: dataset.projectId ?? null,
3111
+ ...item,
3112
+ createdAt: now,
3113
+ updatedAt: now
3114
+ });
3006
3115
  }
3007
3116
  await connection.execute(
3008
3117
  `INSERT INTO ${tableVersionsName} (\`id\`, \`datasetId\`, \`version\`, \`createdAt\`) VALUES (?, ?, ?, ?)`,
3009
- [versionId, input.datasetId, newVersion, transformToSqlValue(now)]
3118
+ [crypto$1.randomUUID(), input.datasetId, newVersion, transformToSqlValue(now)]
3010
3119
  );
3011
3120
  await connection.commit();
3012
- return items.map(({ id, itemInput }) => ({
3013
- id,
3014
- datasetId: input.datasetId,
3015
- datasetVersion: newVersion,
3016
- organizationId: parentOrganizationId,
3017
- projectId: parentProjectId,
3018
- input: itemInput.input,
3019
- groundTruth: itemInput.groundTruth,
3020
- metadata: itemInput.metadata,
3021
- createdAt: now,
3022
- updatedAt: now
3023
- }));
3121
+ return plan.resolvedIds.map((id) => inserted.get(id) ?? existingItems.get(id));
3024
3122
  } catch (error$1) {
3025
3123
  await connection.rollback();
3026
3124
  if (error$1 instanceof error.MastraError) throw error$1;
@@ -3078,16 +3176,21 @@ var DatasetsMySQL = class _DatasetsMySQL extends storage.DatasetsStorage {
3078
3176
  [newVersion, item.id]
3079
3177
  );
3080
3178
  await connection.execute(
3081
- `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`metadata\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, NULL, 1, ?, ?, ?, ?, ?)`,
3179
+ `INSERT INTO ${tableItemsName} (\`id\`, \`datasetId\`, \`datasetVersion\`, \`externalId\`, \`organizationId\`, \`projectId\`, \`validTo\`, \`isDeleted\`, \`input\`, \`groundTruth\`, \`expectedTrajectory\`, \`toolMocks\`, \`requestContext\`, \`metadata\`, \`source\`, \`createdAt\`, \`updatedAt\`) VALUES (?, ?, ?, ?, ?, ?, NULL, 1, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
3082
3180
  [
3083
3181
  item.id,
3084
3182
  input.datasetId,
3085
3183
  newVersion,
3184
+ item.externalId ?? null,
3086
3185
  parentOrganizationId,
3087
3186
  parentProjectId,
3088
3187
  jsonArg(item.input),
3089
3188
  jsonArg(item.groundTruth),
3189
+ jsonArg(item.expectedTrajectory),
3190
+ jsonArg(item.toolMocks),
3191
+ jsonArg(item.requestContext),
3090
3192
  jsonArg(item.metadata),
3193
+ jsonArg(item.source),
3091
3194
  transformToSqlValue(item.createdAt),
3092
3195
  transformToSqlValue(now)
3093
3196
  ]