@dbos-inc/dbos-sdk 5.1.3-preview → 5.1.5-preview

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.
@@ -2560,7 +2560,7 @@ class SystemDatabase {
2560
2560
  return rows[0].workflow_uuid;
2561
2561
  }
2562
2562
  async getQueuePartitions(queueName) {
2563
- // Recursive-CTE loose index scan: SELECT DISTINCT would scan every ENQUEUED row, whereas each iteration here is one seek on idx_workflow_status_partition_dequeue_v2, so cost scales with the number of partitions rather than the backlog depth.
2563
+ // Recursive-CTE loose index scan: SELECT DISTINCT would scan every ENQUEUED row, whereas each iteration here is one seek on idx_workflow_status_partition_dequeue_v3, so cost scales with the number of partitions rather than the backlog depth.
2564
2564
  const params = [queueName, workflow_1.StatusString.ENQUEUED];
2565
2565
  // Only partitions this application can actually dequeue from.
2566
2566
  const scope = this.#appNameFilter('application_name', this.appName, params);
@@ -2615,7 +2615,7 @@ class SystemDatabase {
2615
2615
  };
2616
2616
  /**
2617
2617
  * Workflows already running, which peer workers count against too. Kept as its own query per
2618
- * scope: the partition-scoped predicate rides idx_workflow_status_partition_dequeue_v2, which
2618
+ * scope: the partition-scoped predicate rides idx_workflow_status_partition_dequeue_v3, which
2619
2619
  * a queue-wide scan loses.
2620
2620
  */
2621
2621
  const pendingCount = async (partitionScoped) => {
@@ -3066,8 +3066,18 @@ class SystemDatabase {
3066
3066
  addFilter('executor_id', input.executorId);
3067
3067
  const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(' AND ')}` : '';
3068
3068
  const orderClause = `ORDER BY created_at ${input.sortDesc ? 'DESC' : 'ASC'}`;
3069
- const limitClause = input.limit ? `LIMIT ${input.limit}` : '';
3070
- const offsetClause = input.offset ? `OFFSET ${input.offset}` : '';
3069
+ let limitClause = '';
3070
+ if (input.limit) {
3071
+ limitClause = `LIMIT $${paramCounter}`;
3072
+ params.push(input.limit);
3073
+ paramCounter++;
3074
+ }
3075
+ let offsetClause = '';
3076
+ if (input.offset) {
3077
+ offsetClause = `OFFSET $${paramCounter}`;
3078
+ params.push(input.offset);
3079
+ paramCounter++;
3080
+ }
3071
3081
  const projection = [...selectColumns.map((c) => `workflow_status.${c}`), ...payloadColumns].join(', ');
3072
3082
  const query = `
3073
3083
  SELECT ${projection}
@@ -3106,9 +3116,12 @@ class SystemDatabase {
3106
3116
  groupSelectColumns.push(col);
3107
3117
  }
3108
3118
  }
3119
+ const params = [];
3109
3120
  if (input.timeBucketSizeMs !== undefined) {
3110
3121
  // Bucket on created_at — the indexed wall-clock timestamp on workflow_status.
3111
- const bucket = input.timeBucketSizeMs;
3122
+ // One placeholder shared by SELECT and GROUP BY, so Postgres sees the two expressions as identical.
3123
+ params.push(input.timeBucketSizeMs);
3124
+ const bucket = `$${params.length}::bigint`;
3112
3125
  const bucketExpr = `(CAST(FLOOR(created_at / ${bucket}) AS BIGINT) * ${bucket})`;
3113
3126
  groupNames.push('time_bucket');
3114
3127
  groupColumns.push(bucketExpr);
@@ -3138,8 +3151,7 @@ class SystemDatabase {
3138
3151
  throw new Error('At least one select_ flag must be set to True');
3139
3152
  }
3140
3153
  const whereClauses = [];
3141
- const params = [];
3142
- let paramIdx = 1;
3154
+ let paramIdx = params.length + 1;
3143
3155
  const addFilter = (column, values) => {
3144
3156
  if (!values || values.length === 0)
3145
3157
  return;
@@ -3261,10 +3273,12 @@ class SystemDatabase {
3261
3273
  groupSelectColumns.push(`${expr} AS ${colName}`);
3262
3274
  }
3263
3275
  }
3276
+ const params = [];
3264
3277
  if (input.timeBucketSizeMs !== undefined) {
3265
3278
  // Bucket on completed_at_epoch_ms — it's the indexed timestamp on
3266
3279
  // this table.
3267
- const bucket = input.timeBucketSizeMs;
3280
+ params.push(input.timeBucketSizeMs);
3281
+ const bucket = `$${params.length}::bigint`;
3268
3282
  const bucketExpr = `(CAST(FLOOR(completed_at_epoch_ms / ${bucket}) AS BIGINT) * ${bucket})`;
3269
3283
  groupNames.push('time_bucket');
3270
3284
  groupColumns.push(bucketExpr);
@@ -3292,8 +3306,7 @@ class SystemDatabase {
3292
3306
  throw new Error('At least one select_ flag must be set to True');
3293
3307
  }
3294
3308
  const whereClauses = [];
3295
- const params = [];
3296
- let paramIdx = 1;
3309
+ let paramIdx = params.length + 1;
3297
3310
  if (input.status && input.status.length > 0) {
3298
3311
  const placeholders = input.status.map((_, i) => `$${paramIdx + i}`).join(', ');
3299
3312
  whereClauses.push(`(${statusExpr}) IN (${placeholders})`);