@mastra/dsql 1.2.2 → 1.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/dist/index.js CHANGED
@@ -125,16 +125,21 @@ var PoolAdapter = class {
125
125
  const client = await this.$pool.connect();
126
126
  try {
127
127
  await client.query("BEGIN");
128
- const result = await callback(new TransactionClient(client));
129
- await client.query("COMMIT");
130
- return result;
131
- } catch (error) {
128
+ const txClient = new TransactionClient(client);
132
129
  try {
133
- await client.query("ROLLBACK");
134
- } catch (rollbackError) {
135
- console.error("Transaction rollback failed:", rollbackError);
130
+ const result = await callback(txClient);
131
+ await txClient.drain();
132
+ await client.query("COMMIT");
133
+ return result;
134
+ } catch (error) {
135
+ await txClient.drain().catch(() => void 0);
136
+ try {
137
+ await client.query("ROLLBACK");
138
+ } catch (rollbackError) {
139
+ console.error("Transaction rollback failed:", rollbackError);
140
+ }
141
+ throw error;
136
142
  }
137
- throw error;
138
143
  } finally {
139
144
  client.release();
140
145
  }
@@ -142,41 +147,85 @@ var PoolAdapter = class {
142
147
  };
143
148
  /**
144
149
  * Transaction client that wraps a PoolClient for executing queries within a transaction.
150
+ *
151
+ * Query methods are serialized through a tail promise (same pattern as
152
+ * PinnedClientAdapter). Callers such as memory.updateMessages historically
153
+ * did `queries.push(t.none(...))` then `await t.batch(queries)` — each
154
+ * `t.none()` is async and starts `client.query` immediately, so by the time
155
+ * batch runs, N queries are already in flight on one PoolClient. pg@8 queues
156
+ * those internally and emits a DeprecationWarning; pg@9 will throw.
157
+ * (#20820)
145
158
  */
146
159
  var TransactionClient = class {
147
160
  client;
161
+ /**
162
+ * Serialization tail. Without this gate, concurrent t.none()/t.query()
163
+ * from Promise.all / batch land on the same PoolClient at once.
164
+ */
165
+ #tail = Promise.resolve();
166
+ #error;
148
167
  constructor(client) {
149
168
  this.client = client;
150
169
  }
151
- async none(query, values) {
152
- await this.client.query(query, values);
153
- return null;
170
+ #enqueue(fn) {
171
+ const next = this.#tail.then(fn);
172
+ this.#tail = next.then(() => void 0, (error) => {
173
+ this.#error ??= { value: error };
174
+ });
175
+ return next;
154
176
  }
155
- async one(query, values) {
156
- const result = await this.client.query(query, values);
157
- if (result.rows.length === 0) throw new Error(`No data returned from query: ${truncateQuery(query)}`);
158
- if (result.rows.length > 1) throw new Error(`Multiple rows returned when one was expected: ${truncateQuery(query)}`);
159
- return result.rows[0];
177
+ /**
178
+ * Wait until every enqueued query has settled and surface the first failure.
179
+ * PoolAdapter calls this before COMMIT/ROLLBACK so those control
180
+ * statements never overlap in-flight work on the same client.
181
+ */
182
+ async drain() {
183
+ await this.#tail;
184
+ if (this.#error) {
185
+ const { value } = this.#error;
186
+ this.#error = void 0;
187
+ throw value;
188
+ }
189
+ }
190
+ none(query, values) {
191
+ return this.#enqueue(async () => {
192
+ await this.client.query(query, values);
193
+ return null;
194
+ });
160
195
  }
161
- async oneOrNone(query, values) {
162
- const result = await this.client.query(query, values);
163
- if (result.rows.length === 0) return null;
164
- if (result.rows.length > 1) throw new Error(`Multiple rows returned when one or none was expected: ${truncateQuery(query)}`);
165
- return result.rows[0];
196
+ one(query, values) {
197
+ return this.#enqueue(async () => {
198
+ const result = await this.client.query(query, values);
199
+ if (result.rows.length === 0) throw new Error(`No data returned from query: ${truncateQuery(query)}`);
200
+ if (result.rows.length > 1) throw new Error(`Multiple rows returned when one was expected: ${truncateQuery(query)}`);
201
+ return result.rows[0];
202
+ });
166
203
  }
167
- async any(query, values) {
168
- return (await this.client.query(query, values)).rows;
204
+ oneOrNone(query, values) {
205
+ return this.#enqueue(async () => {
206
+ const result = await this.client.query(query, values);
207
+ if (result.rows.length === 0) return null;
208
+ if (result.rows.length > 1) throw new Error(`Multiple rows returned when one or none was expected: ${truncateQuery(query)}`);
209
+ return result.rows[0];
210
+ });
169
211
  }
170
- async manyOrNone(query, values) {
212
+ any(query, values) {
213
+ return this.#enqueue(async () => {
214
+ return (await this.client.query(query, values)).rows;
215
+ });
216
+ }
217
+ manyOrNone(query, values) {
171
218
  return this.any(query, values);
172
219
  }
173
- async many(query, values) {
174
- const result = await this.client.query(query, values);
175
- if (result.rows.length === 0) throw new Error(`No data returned from query: ${truncateQuery(query)}`);
176
- return result.rows;
220
+ many(query, values) {
221
+ return this.#enqueue(async () => {
222
+ const result = await this.client.query(query, values);
223
+ if (result.rows.length === 0) throw new Error(`No data returned from query: ${truncateQuery(query)}`);
224
+ return result.rows;
225
+ });
177
226
  }
178
- async query(query, values) {
179
- return this.client.query(query, values);
227
+ query(query, values) {
228
+ return this.#enqueue(() => this.client.query(query, values));
180
229
  }
181
230
  async batch(promises) {
182
231
  return Promise.all(promises);
@@ -1976,6 +2025,7 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
1976
2025
  hasMore: perPageInput === false ? false : offset + perPage < total
1977
2026
  };
1978
2027
  } catch (error) {
2028
+ if (error instanceof MastraError && error.category === ErrorCategory.USER) throw error;
1979
2029
  const mastraError = new MastraError({
1980
2030
  id: createStorageErrorId("DSQL", "LIST_THREADS", "FAILED"),
1981
2031
  domain: ErrorDomain.STORAGE,
@@ -1988,13 +2038,7 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
1988
2038
  }, error);
1989
2039
  this.logger?.error?.(mastraError.toString());
1990
2040
  this.logger?.trackException(mastraError);
1991
- return {
1992
- threads: [],
1993
- total: 0,
1994
- page,
1995
- perPage: perPageForResponse,
1996
- hasMore: false
1997
- };
2041
+ throw mastraError;
1998
2042
  }
1999
2043
  }
2000
2044
  async saveThread({ thread }) {
@@ -2128,7 +2172,14 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2128
2172
  }, error);
2129
2173
  });
2130
2174
  }
2131
- async _getIncludedMessages({ include }) {
2175
+ /**
2176
+ * Fetches the messages named by `include` together with their surrounding context.
2177
+ *
2178
+ * @param include - Message ids to pin, each with an optional before/after window.
2179
+ * @param resourceId - When set, restricts both the pinned messages and their context
2180
+ * to that resource so an id from another resource returns nothing.
2181
+ */
2182
+ async _getIncludedMessages({ include, resourceId }) {
2132
2183
  if (!include || include.length === 0) return null;
2133
2184
  const unionQueries = [];
2134
2185
  const params = [];
@@ -2139,17 +2190,18 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2139
2190
  });
2140
2191
  for (const inc of include) {
2141
2192
  const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
2193
+ const resourceCondition = resourceId ? ` AND "resourceId" = $${paramIdx + 3}` : "";
2142
2194
  unionQueries.push(`
2143
2195
  SELECT * FROM (
2144
2196
  WITH target_thread AS (
2145
- SELECT thread_id FROM ${tableName} WHERE id = $${paramIdx}
2197
+ SELECT thread_id FROM ${tableName} WHERE id = $${paramIdx}${resourceCondition}
2146
2198
  ),
2147
2199
  ordered_messages AS (
2148
2200
  SELECT
2149
2201
  *,
2150
2202
  ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
2151
2203
  FROM ${tableName}
2152
- WHERE thread_id = (SELECT thread_id FROM target_thread)
2204
+ WHERE thread_id = (SELECT thread_id FROM target_thread)${resourceCondition}
2153
2205
  )
2154
2206
  SELECT
2155
2207
  m.id,
@@ -2175,6 +2227,10 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2175
2227
  `);
2176
2228
  params.push(id, withPreviousMessages, withNextMessages);
2177
2229
  paramIdx += 3;
2230
+ if (resourceId) {
2231
+ params.push(resourceId);
2232
+ paramIdx += 1;
2233
+ }
2178
2234
  }
2179
2235
  const finalQuery = unionQueries.join(" UNION ALL ") + " ORDER BY \"createdAt\" ASC";
2180
2236
  const includedRows = await this.#db.client.manyOrNone(finalQuery, params);
@@ -2224,7 +2280,7 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2224
2280
  }, error);
2225
2281
  this.logger?.error?.(mastraError.toString());
2226
2282
  this.logger?.trackException(mastraError);
2227
- return { messages: [] };
2283
+ throw mastraError;
2228
2284
  }
2229
2285
  }
2230
2286
  async listMessages(args) {
@@ -2300,7 +2356,10 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2300
2356
  };
2301
2357
  const messageIds = new Set(messages.map((m) => m.id));
2302
2358
  if (include && include.length > 0) {
2303
- const includeMessages = await this._getIncludedMessages({ include });
2359
+ const includeMessages = await this._getIncludedMessages({
2360
+ include,
2361
+ resourceId
2362
+ });
2304
2363
  if (includeMessages) {
2305
2364
  for (const includeMsg of includeMessages) if (!messageIds.has(includeMsg.id)) {
2306
2365
  messages.push(includeMsg);
@@ -2331,6 +2390,7 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2331
2390
  hasMore
2332
2391
  };
2333
2392
  } catch (error) {
2393
+ if (error instanceof MastraError && error.category === ErrorCategory.USER) throw error;
2334
2394
  const mastraError = new MastraError({
2335
2395
  id: createStorageErrorId("DSQL", "LIST_MESSAGES", "FAILED"),
2336
2396
  domain: ErrorDomain.STORAGE,
@@ -2342,13 +2402,7 @@ var MemoryDSQL = class MemoryDSQL extends MemoryStorage {
2342
2402
  }, error);
2343
2403
  this.logger?.error?.(mastraError.toString());
2344
2404
  this.logger?.trackException(mastraError);
2345
- return {
2346
- messages: [],
2347
- total: 0,
2348
- page,
2349
- perPage: perPageForResponse,
2350
- hasMore: false
2351
- };
2405
+ throw mastraError;
2352
2406
  }
2353
2407
  }
2354
2408
  async saveMessages({ messages }) {