@mastra/libsql 1.27.1-alpha.0 → 1.27.1-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/dist/index.js CHANGED
@@ -2058,6 +2058,41 @@ var LibSQLDB = class extends MastraBase {
2058
2058
  });
2059
2059
  }
2060
2060
  /**
2061
+ * Updates multiple records in one write batch, with the same retry behavior as
2062
+ * {@link batchUpdate}. Returns, in input order, whether each update changed a row,
2063
+ * so callers can put extra conditions in `keys` (for example `{ endedAt: null }`).
2064
+ */
2065
+ async batchUpdateReportingChanges({ tableName, updates }) {
2066
+ return this.executeWriteOperationWithRetry(async () => {
2067
+ const changed = updates.map(() => false);
2068
+ const statements = [];
2069
+ const statementIndexes = [];
2070
+ for (const [index, { keys, data }] of updates.entries()) {
2071
+ const filteredData = await this.filterRecordToKnownColumns(tableName, data);
2072
+ if (Object.keys(filteredData).length === 0) continue;
2073
+ statements.push(prepareUpdateStatement({
2074
+ tableName,
2075
+ updates: filteredData,
2076
+ keys
2077
+ }));
2078
+ statementIndexes.push(index);
2079
+ }
2080
+ if (statements.length === 0) return changed;
2081
+ (await withClientWriteLock(this.client, () => this.client.batch(statements, "write"))).forEach((result, i) => {
2082
+ const index = statementIndexes[i];
2083
+ if (index !== void 0) changed[index] = result.rowsAffected > 0;
2084
+ });
2085
+ return changed;
2086
+ }, `batch update in table ${tableName}`).catch((error) => {
2087
+ throw new MastraError({
2088
+ id: createStorageErrorId("LIBSQL", "BATCH_UPDATE_REPORTING_CHANGES", "FAILED"),
2089
+ domain: ErrorDomain.STORAGE,
2090
+ category: ErrorCategory.THIRD_PARTY,
2091
+ details: { tableName }
2092
+ }, error);
2093
+ });
2094
+ }
2095
+ /**
2061
2096
  * Internal batch delete implementation without retry logic.
2062
2097
  * Each record can be deleted based on single or composite keys.
2063
2098
  */
@@ -2190,7 +2225,7 @@ var LibSQLDB = class extends MastraBase {
2190
2225
  * @returns The total count of matching records
2191
2226
  */
2192
2227
  async selectTotalCount({ tableName, whereClause }) {
2193
- const statement = `SELECT COUNT(*) as count FROM ${parseSqlIdentifier(tableName, "table name")} ${whereClause ? `${whereClause.sql}` : ""}`;
2228
+ const statement = `SELECT COUNT(*) as count FROM ${parseSqlIdentifier(tableName, "table name")} ${whereClause ? whereClause.sql : ""}`;
2194
2229
  const result = await this.client.execute({
2195
2230
  sql: statement,
2196
2231
  args: whereClause?.args ?? []
@@ -12562,24 +12597,27 @@ var ObservabilityLibSQL = class ObservabilityLibSQL extends ObservabilityStorage
12562
12597
  }, error);
12563
12598
  }
12564
12599
  }
12565
- async batchUpdateSpans(args) {
12600
+ #toSpanUpdates(records) {
12566
12601
  const now = (/* @__PURE__ */ new Date()).toISOString();
12602
+ return records.map((record) => {
12603
+ const data = { ...record.updates };
12604
+ if (data.endedAt instanceof Date) data.endedAt = data.endedAt.toISOString();
12605
+ if (data.startedAt instanceof Date) data.startedAt = data.startedAt.toISOString();
12606
+ data.updatedAt = now;
12607
+ return {
12608
+ keys: {
12609
+ spanId: record.spanId,
12610
+ traceId: record.traceId
12611
+ },
12612
+ data
12613
+ };
12614
+ });
12615
+ }
12616
+ async batchUpdateSpans(args) {
12567
12617
  try {
12568
12618
  return this.#db.batchUpdate({
12569
12619
  tableName: TABLE_SPANS,
12570
- updates: args.records.map((record) => {
12571
- const data = { ...record.updates };
12572
- if (data.endedAt instanceof Date) data.endedAt = data.endedAt.toISOString();
12573
- if (data.startedAt instanceof Date) data.startedAt = data.startedAt.toISOString();
12574
- data.updatedAt = now;
12575
- return {
12576
- keys: {
12577
- spanId: record.spanId,
12578
- traceId: record.traceId
12579
- },
12580
- data
12581
- };
12582
- })
12620
+ updates: this.#toSpanUpdates(args.records)
12583
12621
  });
12584
12622
  } catch (error) {
12585
12623
  throw new MastraError({
@@ -12589,6 +12627,30 @@ var ObservabilityLibSQL = class ObservabilityLibSQL extends ObservabilityStorage
12589
12627
  }, error);
12590
12628
  }
12591
12629
  }
12630
+ async batchUpdateUnendedSpans(args) {
12631
+ try {
12632
+ const changed = await this.#db.batchUpdateReportingChanges({
12633
+ tableName: TABLE_SPANS,
12634
+ updates: this.#toSpanUpdates(args.records).map((update) => ({
12635
+ ...update,
12636
+ keys: {
12637
+ ...update.keys,
12638
+ endedAt: null
12639
+ }
12640
+ }))
12641
+ });
12642
+ return { updated: args.records.filter((_, index) => changed[index]).map(({ traceId, spanId }) => ({
12643
+ traceId,
12644
+ spanId
12645
+ })) };
12646
+ } catch (error) {
12647
+ throw new MastraError({
12648
+ id: createStorageErrorId("LIBSQL", "BATCH_UPDATE_UNENDED_SPANS", "FAILED"),
12649
+ domain: ErrorDomain.STORAGE,
12650
+ category: ErrorCategory.USER
12651
+ }, error);
12652
+ }
12653
+ }
12592
12654
  async batchDeleteTraces(args) {
12593
12655
  this.assertUnscopedBatchDeleteTraces(args);
12594
12656
  try {
@@ -15277,6 +15339,9 @@ var WorkflowsLibSQL = class WorkflowsLibSQL extends WorkflowsStorage {
15277
15339
  supportsConcurrentUpdates() {
15278
15340
  return true;
15279
15341
  }
15342
+ supportsGuardedSnapshotWrites() {
15343
+ return true;
15344
+ }
15280
15345
  parseWorkflowRun(row) {
15281
15346
  let parsedSnapshot = row.snapshot;
15282
15347
  if (typeof parsedSnapshot === "string") try {
@@ -15550,7 +15615,7 @@ var WorkflowsLibSQL = class WorkflowsLibSQL extends WorkflowsStorage {
15550
15615
  }
15551
15616
  }), "updateWorkflowState");
15552
15617
  }
15553
- async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence }) {
15618
+ async persistWorkflowSnapshot({ workflowName, runId, resourceId, snapshot, createdAt, updatedAt, fence, expectedStatus }) {
15554
15619
  const now = /* @__PURE__ */ new Date();
15555
15620
  const createdAtValue = (createdAt ?? now).toISOString();
15556
15621
  const updatedAtValue = (updatedAt ?? now).toISOString();
@@ -15558,21 +15623,30 @@ var WorkflowsLibSQL = class WorkflowsLibSQL extends WorkflowsStorage {
15558
15623
  workflowName,
15559
15624
  runId
15560
15625
  });
15626
+ const expected = expectedStatus === void 0 ? [] : Array.isArray(expectedStatus) ? expectedStatus : [expectedStatus];
15627
+ const guard = expectedStatus === void 0 ? "" : expected.length ? ` WHERE json_extract(${TABLE_WORKFLOW_SNAPSHOT}.snapshot, '$.status') IN (${expected.map(() => "?").join(", ")})` : " WHERE 0";
15561
15628
  const check = this.#runFenceCheck(fence, runId, "persistWorkflowSnapshot");
15562
- await this.executeWithRetry(() => withRunFence(this.#client, check, (writer) => writer.execute({
15629
+ return (await this.executeWithRetry(() => withRunFence(this.#client, check, (writer) => writer.execute({
15563
15630
  sql: `INSERT INTO ${TABLE_WORKFLOW_SNAPSHOT} (workflow_name, run_id, resourceId, snapshot, createdAt, updatedAt)
15564
15631
  VALUES (?, ?, ?, jsonb(?), ?, ?)
15565
15632
  ON CONFLICT(workflow_name, run_id)
15566
- DO UPDATE SET resourceId = COALESCE(excluded.resourceId, ${TABLE_WORKFLOW_SNAPSHOT}.resourceId), snapshot = excluded.snapshot, updatedAt = excluded.updatedAt`,
15633
+ DO UPDATE SET resourceId = COALESCE(excluded.resourceId, ${TABLE_WORKFLOW_SNAPSHOT}.resourceId), snapshot = excluded.snapshot, updatedAt = excluded.updatedAt${guard}`,
15567
15634
  args: [
15568
15635
  workflowName,
15569
15636
  runId,
15570
15637
  resourceId ?? null,
15571
15638
  safeStringify(snapshot),
15572
15639
  createdAtValue,
15573
- updatedAtValue
15640
+ updatedAtValue,
15641
+ ...expected
15574
15642
  ]
15575
- })), "persistWorkflowSnapshot");
15643
+ })), "persistWorkflowSnapshot")).rowsAffected > 0;
15644
+ }
15645
+ async loadWorkflowRunStatus({ workflowName, runId }) {
15646
+ return (await this.#client.execute({
15647
+ sql: `SELECT json_extract(snapshot, '$.status') AS status FROM ${TABLE_WORKFLOW_SNAPSHOT} WHERE workflow_name = ? AND run_id = ?`,
15648
+ args: [workflowName, runId]
15649
+ })).rows?.[0]?.status ?? null;
15576
15650
  }
15577
15651
  async loadWorkflowSnapshot({ workflowName, runId }) {
15578
15652
  this.logger.debug("Loading workflow snapshot", {