@mastra/pg 1.9.0 → 1.9.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/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # @mastra/pg
2
2
 
3
+ ## 1.9.1-alpha.1
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed vector similarity queries to leverage HNSW and IVFFlat indexes. When querying without filters on an HNSW or IVFFlat-indexed table, ORDER BY and LIMIT are now placed inside the CTE so PostgreSQL can use the index for faster approximate nearest neighbor searches instead of scanning all rows. ([#14574](https://github.com/mastra-ai/mastra/pull/14574))
8
+
9
+ - Fixed vector operations failing when pgvector extension is installed in a custom schema. The search_path is now set before index creation and vector similarity queries, ensuring operator classes (e.g. vector_cosine_ops) and distance operators (e.g. <=>) resolve correctly regardless of where the extension is installed. Previously, only table creation set the search_path, causing CREATE INDEX and query operations to fail with unresolvable operator errors. ([#14526](https://github.com/mastra-ai/mastra/pull/14526))
10
+
11
+ - Added `entityVersionId`, `parentEntityVersionId`, and `rootEntityVersionId` columns to observability storage tables (spans, metrics, scores, feedback, logs) for filtering and grouping traces by entity version. Added ALTER TABLE migrations for existing databases. Added `targetType`, `targetId`, `agentVersion`, and `status` filters to `listExperiments`, and `traceId` and `status` filters to `listExperimentResults`. ([#15317](https://github.com/mastra-ai/mastra/pull/15317))
12
+
13
+ - Updated dependencies [[`cbdf3e1`](https://github.com/mastra-ai/mastra/commit/cbdf3e12b3d0c30a6e5347be658e2009648c130a), [`8fe46d3`](https://github.com/mastra-ai/mastra/commit/8fe46d354027f3f0f0846e64219772348de106dd), [`18c67db`](https://github.com/mastra-ai/mastra/commit/18c67dbb9c9ebc26f26f65f7d3ff836e5691ef46), [`8dcc77e`](https://github.com/mastra-ai/mastra/commit/8dcc77e78a5340f5848f74b9e9f1b3da3513c1f5), [`aa67fc5`](https://github.com/mastra-ai/mastra/commit/aa67fc59ee8a5eeff1f23eb05970b8d7a536c8ff), [`fa8140b`](https://github.com/mastra-ai/mastra/commit/fa8140bcd4251d2e3ac85fdc5547dfc4f372b5be), [`190f452`](https://github.com/mastra-ai/mastra/commit/190f45258b0640e2adfc8219fa3258cdc5b8f071), [`7e7bf60`](https://github.com/mastra-ai/mastra/commit/7e7bf606886bf374a6f9d4ca9b09dd83d0533372), [`184907d`](https://github.com/mastra-ai/mastra/commit/184907d775d8609c03c26e78ccaf37315f3aa287), [`0c4cd13`](https://github.com/mastra-ai/mastra/commit/0c4cd131931c04ac5405373c932a242dbe88edd6), [`b16a753`](https://github.com/mastra-ai/mastra/commit/b16a753d5748440248d7df82e29bb987a9c8386c)]:
14
+ - @mastra/core@1.25.0-alpha.3
15
+
16
+ ## 1.9.1-alpha.0
17
+
18
+ ### Patch Changes
19
+
20
+ - Fixed `batchInsert` and `batchUpdate` in `@mastra/pg` to run on a single Postgres transaction connection. ([#15312](https://github.com/mastra-ai/mastra/pull/15312))
21
+
22
+ This prevents pooled `BEGIN`/`COMMIT`/`ROLLBACK` calls from landing on different connections and leaving idle transactions open during batch writes.
23
+
24
+ - Fixed "column does not exist" errors when using experiment review features on databases created before the review pipeline was introduced. Startup now automatically migrates older experiment tables to the latest schema. ([#15304](https://github.com/mastra-ai/mastra/pull/15304))
25
+
3
26
  ## 1.9.0
4
27
 
5
28
  ### Minor Changes
@@ -3,7 +3,7 @@ name: mastra-pg
3
3
  description: Documentation for @mastra/pg. Use when working with @mastra/pg APIs, configuration, or implementation.
4
4
  metadata:
5
5
  package: "@mastra/pg"
6
- version: "1.9.0"
6
+ version: "1.9.1-alpha.1"
7
7
  ---
8
8
 
9
9
  ## When to use
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.9.0",
2
+ "version": "1.9.1-alpha.1",
3
3
  "package": "@mastra/pg",
4
4
  "exports": {},
5
5
  "modules": {}
@@ -118,8 +118,6 @@ export const agent = new Agent({
118
118
  })
119
119
  ```
120
120
 
121
- > **Warning:** Agent-level storage isn't supported when using [Mastra Cloud Store](https://mastra.ai/docs/mastra-cloud/deployment). If you use Mastra Cloud Store, configure storage on the Mastra instance instead. This limitation doesn't apply if you bring your own database.
122
-
123
121
  ## Threads and resources
124
122
 
125
123
  Mastra organizes conversations using two identifiers:
@@ -397,4 +397,4 @@ const response = await agent.generate('What do you know about me?', {
397
397
 
398
398
  - [Working memory with template](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-template)
399
399
  - [Working memory with schema](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-schema)
400
- - [Per-resource working memory](https://github.com/mastra-ai/mastra/tree/main/examples/memory-per-resource-example) - Complete example showing resource-scoped memory persistence
400
+ - [Per-resource working memory](https://github.com/mastra-ai/mastra/tree/main/examples/memory-per-resource-example): Complete example showing resource-scoped memory persistence
package/dist/index.cjs CHANGED
@@ -734,6 +734,25 @@ var PgVector = class extends vector.MastraVector {
734
734
  return null;
735
735
  }
736
736
  }
737
+ /**
738
+ * Sets search_path on the client connection so that vector operators (e.g. <=>, vector_cosine_ops)
739
+ * are resolvable when the pgvector extension is installed in a non-default schema.
740
+ *
741
+ * PostgreSQL's default search_path is ("$user", public). If the extension lives in a custom schema
742
+ * (e.g. "myapp"), operator classes and distance operators won't resolve without this.
743
+ */
744
+ async ensureSearchPath(client) {
745
+ if (!this.vectorExtensionSchema) {
746
+ await this.detectVectorExtensionSchema(client);
747
+ }
748
+ if (this.vectorExtensionSchema && this.vectorExtensionSchema !== "public" && this.vectorExtensionSchema !== "pg_catalog") {
749
+ const schemas = /* @__PURE__ */ new Set();
750
+ schemas.add(this.vectorExtensionSchema);
751
+ if (this.schema) schemas.add(this.schema);
752
+ schemas.add("public");
753
+ await client.query(`SET search_path TO ${[...schemas].map((s) => `"${s}"`).join(", ")}`);
754
+ }
755
+ }
737
756
  /**
738
757
  * Checks if the installed pgvector version supports halfvec type.
739
758
  * halfvec was introduced in pgvector 0.7.0.
@@ -947,6 +966,7 @@ var PgVector = class extends vector.MastraVector {
947
966
  }
948
967
  const client = await this.pool.connect();
949
968
  try {
969
+ await this.ensureSearchPath(client);
950
970
  await client.query("BEGIN");
951
971
  const translatedFilter = this.transformFilter(filter);
952
972
  const { sql: filterQuery, values: filterValues } = buildFilterQuery(translatedFilter, minScore, topK);
@@ -966,7 +986,23 @@ var PgVector = class extends vector.MastraVector {
966
986
  const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType, indexInfo.dimension);
967
987
  const distanceExpr = `embedding ${ops.distanceOperator} '${vectorStr}'::${qualifiedVectorType}`;
968
988
  const scoreExpr = ops.scoreExpr(distanceExpr);
969
- const query = `
989
+ const hasFilter = filterQuery.trim().length > 0;
990
+ const useIndexedOrder = indexInfo.type === "hnsw" && !hasFilter && minScore <= 0;
991
+ const query = useIndexedOrder ? `
992
+ WITH vector_scores AS (
993
+ SELECT
994
+ vector_id as id,
995
+ ${scoreExpr} as score,
996
+ metadata
997
+ ${includeVector ? ", embedding" : ""}
998
+ FROM ${tableName}
999
+ ORDER BY ${distanceExpr}
1000
+ LIMIT $2
1001
+ )
1002
+ SELECT *
1003
+ FROM vector_scores
1004
+ WHERE score > $1
1005
+ ORDER BY score DESC` : `
970
1006
  WITH vector_scores AS (
971
1007
  SELECT
972
1008
  vector_id as id,
@@ -1019,6 +1055,7 @@ var PgVector = class extends vector.MastraVector {
1019
1055
  const { tableName } = this.getTableName(indexName);
1020
1056
  const client = await this.pool.connect();
1021
1057
  try {
1058
+ await this.ensureSearchPath(client);
1022
1059
  await client.query("BEGIN");
1023
1060
  if (deleteFilter) {
1024
1061
  this.logger?.debug(`Deleting vectors matching filter before upsert`, { indexName, deleteFilter });
@@ -1269,9 +1306,6 @@ var PgVector = class extends vector.MastraVector {
1269
1306
  }
1270
1307
  });
1271
1308
  }
1272
- if (this.schema && this.vectorExtensionSchema && this.schema !== this.vectorExtensionSchema && this.vectorExtensionSchema !== "pg_catalog") {
1273
- await client.query(`SET search_path TO ${this.getSchemaName()}, "${this.vectorExtensionSchema}"`);
1274
- }
1275
1309
  const qualifiedVectorType = this.getVectorTypeName(vectorType);
1276
1310
  await client.query(`
1277
1311
  CREATE TABLE IF NOT EXISTS ${tableName} (
@@ -1414,6 +1448,7 @@ var PgVector = class extends vector.MastraVector {
1414
1448
  this.describeIndexCache.delete(indexName);
1415
1449
  return;
1416
1450
  }
1451
+ await this.ensureSearchPath(client);
1417
1452
  const effectiveVectorType = existingIndexInfo?.vectorType ?? vectorType;
1418
1453
  const metricOp = this.getVectorOps(effectiveVectorType, metric).operatorClass;
1419
1454
  let indexSQL;
@@ -1764,6 +1799,7 @@ var PgVector = class extends vector.MastraVector {
1764
1799
  });
1765
1800
  }
1766
1801
  client = await this.pool.connect();
1802
+ await this.ensureSearchPath(client);
1767
1803
  const { tableName } = this.getTableName(indexName);
1768
1804
  const indexInfo = await this.getIndexInfo({ indexName });
1769
1805
  const qualifiedVectorType = this.getVectorTypeName(indexInfo.vectorType, indexInfo.dimension);
@@ -2002,6 +2038,7 @@ var PoolAdapter = class {
2002
2038
  constructor($pool) {
2003
2039
  this.$pool = $pool;
2004
2040
  }
2041
+ $pool;
2005
2042
  connect() {
2006
2043
  return this.$pool.connect();
2007
2044
  }
@@ -2070,6 +2107,7 @@ var TransactionClient = class {
2070
2107
  constructor(client) {
2071
2108
  this.client = client;
2072
2109
  }
2110
+ client;
2073
2111
  async none(query, values) {
2074
2112
  await this.client.query(query, values);
2075
2113
  return null;
@@ -2499,36 +2537,39 @@ var PgDB = class extends base.MastraBase {
2499
2537
  return storage.getDefaultValue(type);
2500
2538
  }
2501
2539
  }
2502
- async insert({ tableName, record }) {
2503
- try {
2504
- this.addTimestampZColumns(record);
2505
- const filteredRecord = await this.filterRecordToKnownColumns(tableName, record);
2506
- const schemaName = getSchemaName(this.schemaName);
2507
- const columns = Object.keys(filteredRecord).map((col) => utils.parseSqlIdentifier(col, "column name"));
2508
- if (columns.length === 0) return;
2509
- const values = this.prepareValuesForInsert(filteredRecord, tableName);
2510
- const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
2511
- const fullTableName = getTableName({ indexName: tableName, schemaName });
2512
- const columnList = columns.map((c) => `"${c}"`).join(", ");
2513
- if (tableName === storage.TABLE_SPANS) {
2514
- const updateColumns = columns.filter((c) => c !== "traceId" && c !== "spanId");
2515
- if (updateColumns.length > 0) {
2516
- const updateClause = updateColumns.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ");
2517
- await this.client.none(
2518
- `INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})
2540
+ async executeInsert(client, { tableName, record }) {
2541
+ this.addTimestampZColumns(record);
2542
+ const filteredRecord = await this.filterRecordToKnownColumns(tableName, record);
2543
+ const schemaName = getSchemaName(this.schemaName);
2544
+ const columns = Object.keys(filteredRecord).map((col) => utils.parseSqlIdentifier(col, "column name"));
2545
+ if (columns.length === 0) return;
2546
+ const values = this.prepareValuesForInsert(filteredRecord, tableName);
2547
+ const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
2548
+ const fullTableName = getTableName({ indexName: tableName, schemaName });
2549
+ const columnList = columns.map((c) => `"${c}"`).join(", ");
2550
+ if (tableName === storage.TABLE_SPANS) {
2551
+ const updateColumns = columns.filter((c) => c !== "traceId" && c !== "spanId");
2552
+ if (updateColumns.length > 0) {
2553
+ const updateClause = updateColumns.map((c) => `"${c}" = EXCLUDED."${c}"`).join(", ");
2554
+ await client.none(
2555
+ `INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})
2519
2556
  ON CONFLICT ("traceId", "spanId") DO UPDATE SET ${updateClause}`,
2520
- values
2521
- );
2522
- } else {
2523
- await this.client.none(
2524
- `INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})
2525
- ON CONFLICT ("traceId", "spanId") DO NOTHING`,
2526
- values
2527
- );
2528
- }
2557
+ values
2558
+ );
2529
2559
  } else {
2530
- await this.client.none(`INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})`, values);
2560
+ await client.none(
2561
+ `INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})
2562
+ ON CONFLICT ("traceId", "spanId") DO NOTHING`,
2563
+ values
2564
+ );
2531
2565
  }
2566
+ } else {
2567
+ await client.none(`INSERT INTO ${fullTableName} (${columnList}) VALUES (${placeholders})`, values);
2568
+ }
2569
+ }
2570
+ async insert({ tableName, record }) {
2571
+ try {
2572
+ await this.executeInsert(this.client, { tableName, record });
2532
2573
  } catch (error$1) {
2533
2574
  throw new error.MastraError(
2534
2575
  {
@@ -3003,13 +3044,12 @@ Note: This migration may take some time for large tables.
3003
3044
  }
3004
3045
  async batchInsert({ tableName, records }) {
3005
3046
  try {
3006
- await this.client.query("BEGIN");
3007
- for (const record of records) {
3008
- await this.insert({ tableName, record });
3009
- }
3010
- await this.client.query("COMMIT");
3047
+ await this.client.tx(async (tx) => {
3048
+ for (const record of records) {
3049
+ await this.executeInsert(tx, { tableName, record });
3050
+ }
3051
+ });
3011
3052
  } catch (error$1) {
3012
- await this.client.query("ROLLBACK");
3013
3053
  throw new error.MastraError(
3014
3054
  {
3015
3055
  id: storage.createStorageErrorId("PG", "BATCH_INSERT", "FAILED"),
@@ -3287,30 +3327,7 @@ Note: This migration may take some time for large tables.
3287
3327
  data
3288
3328
  }) {
3289
3329
  try {
3290
- const filteredData = await this.filterRecordToKnownColumns(tableName, data);
3291
- if (Object.keys(filteredData).length === 0) return;
3292
- const setColumns = [];
3293
- const setValues = [];
3294
- let paramIndex = 1;
3295
- Object.entries(filteredData).forEach(([key, value]) => {
3296
- const parsedKey = utils.parseSqlIdentifier(key, "column name");
3297
- setColumns.push(`"${parsedKey}" = $${paramIndex++}`);
3298
- setValues.push(this.prepareValue(value, key, tableName));
3299
- });
3300
- const whereConditions = [];
3301
- const whereValues = [];
3302
- Object.entries(keys).forEach(([key, value]) => {
3303
- const parsedKey = utils.parseSqlIdentifier(key, "column name");
3304
- whereConditions.push(`"${parsedKey}" = $${paramIndex++}`);
3305
- whereValues.push(this.prepareValue(value, key, tableName));
3306
- });
3307
- const tableName_ = getTableName({
3308
- indexName: tableName,
3309
- schemaName: getSchemaName(this.schemaName)
3310
- });
3311
- const sql = `UPDATE ${tableName_} SET ${setColumns.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
3312
- const values = [...setValues, ...whereValues];
3313
- await this.client.none(sql, values);
3330
+ await this.executeUpdate(this.client, { tableName, keys, data });
3314
3331
  } catch (error$1) {
3315
3332
  throw new error.MastraError(
3316
3333
  {
@@ -3330,13 +3347,12 @@ Note: This migration may take some time for large tables.
3330
3347
  updates
3331
3348
  }) {
3332
3349
  try {
3333
- await this.client.query("BEGIN");
3334
- for (const { keys, data } of updates) {
3335
- await this.update({ tableName, keys, data });
3336
- }
3337
- await this.client.query("COMMIT");
3350
+ await this.client.tx(async (tx) => {
3351
+ for (const { keys, data } of updates) {
3352
+ await this.executeUpdate(tx, { tableName, keys, data });
3353
+ }
3354
+ });
3338
3355
  } catch (error$1) {
3339
- await this.client.query("ROLLBACK");
3340
3356
  throw new error.MastraError(
3341
3357
  {
3342
3358
  id: storage.createStorageErrorId("PG", "BATCH_UPDATE", "FAILED"),
@@ -3395,6 +3411,36 @@ Note: This migration may take some time for large tables.
3395
3411
  async deleteData({ tableName }) {
3396
3412
  return this.clearTable({ tableName });
3397
3413
  }
3414
+ async executeUpdate(client, {
3415
+ tableName,
3416
+ keys,
3417
+ data
3418
+ }) {
3419
+ const filteredData = await this.filterRecordToKnownColumns(tableName, data);
3420
+ if (Object.keys(filteredData).length === 0) return;
3421
+ const setColumns = [];
3422
+ const setValues = [];
3423
+ let paramIndex = 1;
3424
+ Object.entries(filteredData).forEach(([key, value]) => {
3425
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
3426
+ setColumns.push(`"${parsedKey}" = $${paramIndex++}`);
3427
+ setValues.push(this.prepareValue(value, key, tableName));
3428
+ });
3429
+ const whereConditions = [];
3430
+ const whereValues = [];
3431
+ Object.entries(keys).forEach(([key, value]) => {
3432
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
3433
+ whereConditions.push(`"${parsedKey}" = $${paramIndex++}`);
3434
+ whereValues.push(this.prepareValue(value, key, tableName));
3435
+ });
3436
+ const tableName_ = getTableName({
3437
+ indexName: tableName,
3438
+ schemaName: getSchemaName(this.schemaName)
3439
+ });
3440
+ const sql = `UPDATE ${tableName_} SET ${setColumns.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
3441
+ const values = [...setValues, ...whereValues];
3442
+ await client.none(sql, values);
3443
+ }
3398
3444
  };
3399
3445
  function getSchemaName2(schema) {
3400
3446
  return schema ? `"${utils.parseSqlIdentifier(schema, "schema name")}"` : void 0;
@@ -5308,6 +5354,16 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
5308
5354
  async init() {
5309
5355
  await this.#db.createTable({ tableName: storage.TABLE_EXPERIMENTS, schema: storage.EXPERIMENTS_SCHEMA });
5310
5356
  await this.#db.createTable({ tableName: storage.TABLE_EXPERIMENT_RESULTS, schema: storage.EXPERIMENT_RESULTS_SCHEMA });
5357
+ await this.#db.alterTable({
5358
+ tableName: storage.TABLE_EXPERIMENTS,
5359
+ schema: storage.EXPERIMENTS_SCHEMA,
5360
+ ifNotExists: ["agentVersion"]
5361
+ });
5362
+ await this.#db.alterTable({
5363
+ tableName: storage.TABLE_EXPERIMENT_RESULTS,
5364
+ schema: storage.EXPERIMENT_RESULTS_SCHEMA,
5365
+ ifNotExists: ["status", "tags"]
5366
+ });
5311
5367
  await this.createDefaultIndexes();
5312
5368
  await this.createCustomIndexes();
5313
5369
  }
@@ -5547,6 +5603,22 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
5547
5603
  conditions.push(`"datasetId" = $${paramIndex++}`);
5548
5604
  queryParams.push(args.datasetId);
5549
5605
  }
5606
+ if (args.targetType) {
5607
+ conditions.push(`"targetType" = $${paramIndex++}`);
5608
+ queryParams.push(args.targetType);
5609
+ }
5610
+ if (args.targetId) {
5611
+ conditions.push(`"targetId" = $${paramIndex++}`);
5612
+ queryParams.push(args.targetId);
5613
+ }
5614
+ if (args.agentVersion) {
5615
+ conditions.push(`"agentVersion" = $${paramIndex++}`);
5616
+ queryParams.push(args.agentVersion);
5617
+ }
5618
+ if (args.status) {
5619
+ conditions.push(`"status" = $${paramIndex++}`);
5620
+ queryParams.push(args.status);
5621
+ }
5550
5622
  const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
5551
5623
  const countResult = await this.#db.client.one(
5552
5624
  `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
@@ -5735,9 +5807,21 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
5735
5807
  try {
5736
5808
  const { page, perPage: perPageInput } = args.pagination;
5737
5809
  const tableName = getTableName2({ indexName: storage.TABLE_EXPERIMENT_RESULTS, schemaName: getSchemaName2(this.#schema) });
5810
+ const conditions = ['"experimentId" = $1'];
5811
+ const queryParams = [args.experimentId];
5812
+ let paramIndex = 2;
5813
+ if (args.traceId) {
5814
+ conditions.push(`"traceId" = $${paramIndex++}`);
5815
+ queryParams.push(args.traceId);
5816
+ }
5817
+ if (args.status) {
5818
+ conditions.push(`"status" = $${paramIndex++}`);
5819
+ queryParams.push(args.status);
5820
+ }
5821
+ const whereClause = `WHERE ${conditions.join(" AND ")}`;
5738
5822
  const countResult = await this.#db.client.one(
5739
- `SELECT COUNT(*) as count FROM ${tableName} WHERE "experimentId" = $1`,
5740
- [args.experimentId]
5823
+ `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
5824
+ queryParams
5741
5825
  );
5742
5826
  const total = parseInt(countResult.count, 10);
5743
5827
  if (total === 0) {
@@ -5747,8 +5831,8 @@ var ExperimentsPG = class _ExperimentsPG extends storage.ExperimentsStorage {
5747
5831
  const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
5748
5832
  const limitValue = perPageInput === false ? total : perPage;
5749
5833
  const rows = await this.#db.client.manyOrNone(
5750
- `SELECT * FROM ${tableName} WHERE "experimentId" = $1 ORDER BY "startedAt" ASC LIMIT $2 OFFSET $3`,
5751
- [args.experimentId, limitValue, offset]
5834
+ `SELECT * FROM ${tableName} ${whereClause} ORDER BY "startedAt" ASC LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
5835
+ [...queryParams, limitValue, offset]
5752
5836
  );
5753
5837
  return {
5754
5838
  results: (rows || []).map((row) => this.transformExperimentResultRow(row)),