@nicnocquee/dataqueue 1.20.0 → 1.22.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/src/queue.ts CHANGED
@@ -421,7 +421,7 @@ export const cancelAllUpcomingJobs = async (
421
421
  filters?: {
422
422
  jobType?: string;
423
423
  priority?: number;
424
- runAt?: Date;
424
+ runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
425
425
  tags?: { values: string[]; mode?: TagQueryMode };
426
426
  },
427
427
  ): Promise<number> => {
@@ -443,8 +443,32 @@ export const cancelAllUpcomingJobs = async (
443
443
  params.push(filters.priority);
444
444
  }
445
445
  if (filters.runAt) {
446
- query += ` AND run_at = $${paramIdx++}`;
447
- params.push(filters.runAt);
446
+ if (filters.runAt instanceof Date) {
447
+ query += ` AND run_at = $${paramIdx++}`;
448
+ params.push(filters.runAt);
449
+ } else if (typeof filters.runAt === 'object') {
450
+ const ops = filters.runAt;
451
+ if (ops.gt) {
452
+ query += ` AND run_at > $${paramIdx++}`;
453
+ params.push(ops.gt);
454
+ }
455
+ if (ops.gte) {
456
+ query += ` AND run_at >= $${paramIdx++}`;
457
+ params.push(ops.gte);
458
+ }
459
+ if (ops.lt) {
460
+ query += ` AND run_at < $${paramIdx++}`;
461
+ params.push(ops.lt);
462
+ }
463
+ if (ops.lte) {
464
+ query += ` AND run_at <= $${paramIdx++}`;
465
+ params.push(ops.lte);
466
+ }
467
+ if (ops.eq) {
468
+ query += ` AND run_at = $${paramIdx++}`;
469
+ params.push(ops.eq);
470
+ }
471
+ }
448
472
  }
449
473
  if (
450
474
  filters.tags &&
@@ -661,3 +685,123 @@ export const getJobsByTags = async <
661
685
  client.release();
662
686
  }
663
687
  };
688
+
689
+ export const getJobs = async <PayloadMap, T extends keyof PayloadMap & string>(
690
+ pool: Pool,
691
+ filters?: {
692
+ jobType?: string;
693
+ priority?: number;
694
+ runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
695
+ tags?: { values: string[]; mode?: TagQueryMode };
696
+ },
697
+ limit = 100,
698
+ offset = 0,
699
+ ): Promise<JobRecord<PayloadMap, T>[]> => {
700
+ const client = await pool.connect();
701
+ try {
702
+ let query = `SELECT id, job_type AS "jobType", payload, status, max_attempts AS "maxAttempts", attempts, priority, run_at AS "runAt", timeout_ms AS "timeoutMs", created_at AS "createdAt", updated_at AS "updatedAt", started_at AS "startedAt", completed_at AS "completedAt", last_failed_at AS "lastFailedAt", locked_at AS "lockedAt", locked_by AS "lockedBy", error_history AS "errorHistory", failure_reason AS "failureReason", next_attempt_at AS "nextAttemptAt", last_failed_at AS "lastFailedAt", last_retried_at AS "lastRetriedAt", last_cancelled_at AS "lastCancelledAt", pending_reason AS "pendingReason", tags FROM job_queue`;
703
+ const params: any[] = [];
704
+ let where: string[] = [];
705
+ let paramIdx = 1;
706
+ if (filters) {
707
+ if (filters.jobType) {
708
+ where.push(`job_type = $${paramIdx++}`);
709
+ params.push(filters.jobType);
710
+ }
711
+ if (filters.priority !== undefined) {
712
+ where.push(`priority = $${paramIdx++}`);
713
+ params.push(filters.priority);
714
+ }
715
+ if (filters.runAt) {
716
+ if (filters.runAt instanceof Date) {
717
+ where.push(`run_at = $${paramIdx++}`);
718
+ params.push(filters.runAt);
719
+ } else if (
720
+ typeof filters.runAt === 'object' &&
721
+ (filters.runAt.gt !== undefined ||
722
+ filters.runAt.gte !== undefined ||
723
+ filters.runAt.lt !== undefined ||
724
+ filters.runAt.lte !== undefined ||
725
+ filters.runAt.eq !== undefined)
726
+ ) {
727
+ const ops = filters.runAt as {
728
+ gt?: Date;
729
+ gte?: Date;
730
+ lt?: Date;
731
+ lte?: Date;
732
+ eq?: Date;
733
+ };
734
+ if (ops.gt) {
735
+ where.push(`run_at > $${paramIdx++}`);
736
+ params.push(ops.gt);
737
+ }
738
+ if (ops.gte) {
739
+ where.push(`run_at >= $${paramIdx++}`);
740
+ params.push(ops.gte);
741
+ }
742
+ if (ops.lt) {
743
+ where.push(`run_at < $${paramIdx++}`);
744
+ params.push(ops.lt);
745
+ }
746
+ if (ops.lte) {
747
+ where.push(`run_at <= $${paramIdx++}`);
748
+ params.push(ops.lte);
749
+ }
750
+ if (ops.eq) {
751
+ where.push(`run_at = $${paramIdx++}`);
752
+ params.push(ops.eq);
753
+ }
754
+ }
755
+ }
756
+ if (
757
+ filters.tags &&
758
+ filters.tags.values &&
759
+ filters.tags.values.length > 0
760
+ ) {
761
+ const mode = filters.tags.mode || 'all';
762
+ const tagValues = filters.tags.values;
763
+ switch (mode) {
764
+ case 'exact':
765
+ where.push(`tags = $${paramIdx++}`);
766
+ params.push(tagValues);
767
+ break;
768
+ case 'all':
769
+ where.push(`tags @> $${paramIdx++}`);
770
+ params.push(tagValues);
771
+ break;
772
+ case 'any':
773
+ where.push(`tags && $${paramIdx++}`);
774
+ params.push(tagValues);
775
+ break;
776
+ case 'none':
777
+ where.push(`NOT (tags && $${paramIdx++})`);
778
+ params.push(tagValues);
779
+ break;
780
+ default:
781
+ where.push(`tags @> $${paramIdx++}`);
782
+ params.push(tagValues);
783
+ }
784
+ }
785
+ }
786
+ if (where.length > 0) {
787
+ query += ` WHERE ${where.join(' AND ')}`;
788
+ }
789
+ // Always add LIMIT and OFFSET as the last parameters
790
+ paramIdx = params.length + 1;
791
+ query += ` ORDER BY created_at DESC LIMIT $${paramIdx++} OFFSET $${paramIdx}`;
792
+ params.push(limit, offset);
793
+ const result = await client.query(query, params);
794
+ log(`Found ${result.rows.length} jobs`);
795
+ return result.rows.map((job) => ({
796
+ ...job,
797
+ payload: job.payload,
798
+ timeoutMs: job.timeoutMs,
799
+ failureReason: job.failureReason,
800
+ }));
801
+ } catch (error) {
802
+ log(`Error getting jobs: ${error}`);
803
+ throw error;
804
+ } finally {
805
+ client.release();
806
+ }
807
+ };
package/src/types.ts CHANGED
@@ -164,6 +164,25 @@ export interface Processor {
164
164
  start: () => Promise<number>;
165
165
  }
166
166
 
167
+ export interface DatabaseSSLConfig {
168
+ /**
169
+ * CA certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
170
+ */
171
+ ca?: string;
172
+ /**
173
+ * Client certificate as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
174
+ */
175
+ cert?: string;
176
+ /**
177
+ * Client private key as PEM string or file path. If the value starts with 'file://', it will be loaded from file, otherwise treated as PEM string.
178
+ */
179
+ key?: string;
180
+ /**
181
+ * Whether to reject unauthorized certificates (default: true)
182
+ */
183
+ rejectUnauthorized?: boolean;
184
+ }
185
+
167
186
  export interface JobQueueConfig {
168
187
  databaseConfig: {
169
188
  connectionString?: string;
@@ -172,7 +191,7 @@ export interface JobQueueConfig {
172
191
  database?: string;
173
192
  user?: string;
174
193
  password?: string;
175
- ssl?: any;
194
+ ssl?: DatabaseSSLConfig;
176
195
  };
177
196
  verbose?: boolean;
178
197
  }
@@ -225,6 +244,17 @@ export interface JobQueue<PayloadMap> {
225
244
  limit?: number,
226
245
  offset?: number,
227
246
  ) => Promise<JobRecord<PayloadMap, T>[]>;
247
+ /**
248
+ * Get jobs by filters.
249
+ /**
250
+ * Get jobs by filters.
251
+ */
252
+ getJobs: <T extends JobType<PayloadMap>>(filters?: {
253
+ jobType?: string;
254
+ priority?: number;
255
+ runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
256
+ tags?: { values: string[]; mode?: TagQueryMode };
257
+ }) => Promise<JobRecord<PayloadMap, T>[]>;
228
258
  /**
229
259
  * Retry a job given its ID.
230
260
  * - This will set the job status back to 'pending', clear the locked_at and locked_by, and allow it to be picked up by other workers.
@@ -253,13 +283,13 @@ export interface JobQueue<PayloadMap> {
253
283
  * - The filters are:
254
284
  * - jobType: The job type to cancel.
255
285
  * - priority: The priority of the job to cancel.
256
- * - runAt: The time the job is scheduled to run at.
286
+ * - runAt: The time the job is scheduled to run at (now supports gt/gte/lt/lte/eq).
257
287
  * - tags: An object with 'values' (string[]) and 'mode' (TagQueryMode) for tag-based cancellation.
258
288
  */
259
289
  cancelAllUpcomingJobs: (filters?: {
260
290
  jobType?: string;
261
291
  priority?: number;
262
- runAt?: Date;
292
+ runAt?: Date | { gt?: Date; gte?: Date; lt?: Date; lte?: Date; eq?: Date };
263
293
  tags?: { values: string[]; mode?: TagQueryMode };
264
294
  }) => Promise<number>;
265
295
  /**