@holo-js/queue-db 0.1.3 → 0.1.5

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.d.ts CHANGED
@@ -20,7 +20,6 @@ type StoredFailedQueueJobRow = {
20
20
  exception: unknown;
21
21
  failed_at: unknown;
22
22
  };
23
- declare function isPlainObject(value: unknown): value is Record<string, unknown>;
24
23
  declare function assertQueueJsonValue(value: unknown, path: string, seen?: Set<unknown>): asserts value is QueueJsonValue;
25
24
  declare function normalizeIdentifierPath(value: string, label: string): string;
26
25
  declare function quoteIdentifierPath(dialect: Dialect, path: string): string;
@@ -34,7 +33,7 @@ declare function parseStoredQueueEnvelope(value: unknown): QueueJobEnvelope<Queu
34
33
  declare function parseStoredFailedQueueJobRow(row: StoredFailedQueueJobRow): QueueFailedJobRecord;
35
34
  declare function serializeQueueJson(value: unknown): string;
36
35
  declare function ensureConnectionReady(connection: DatabaseContext): Promise<DatabaseContext>;
37
-
36
+ declare function resolveDatabaseConnection(name: string): DatabaseContext;
38
37
  declare const queueDatabaseInternals: {
39
38
  assertQueueJsonValue: typeof assertQueueJsonValue;
40
39
  coerceOptionalInteger: typeof coerceOptionalInteger;
@@ -42,13 +41,13 @@ declare const queueDatabaseInternals: {
42
41
  coerceRequiredString: typeof coerceRequiredString;
43
42
  createPlaceholderList: typeof createPlaceholderList;
44
43
  ensureConnectionReady: typeof ensureConnectionReady;
45
- isPlainObject: typeof isPlainObject;
46
44
  normalizeIdentifierPath: typeof normalizeIdentifierPath;
47
45
  parseStoredFailedQueueJobRow: typeof parseStoredFailedQueueJobRow;
48
- parseStoredQueueEnvelope: typeof parseStoredQueueEnvelope;
49
46
  parseStoredPayload: typeof parseStoredPayload;
47
+ parseStoredQueueEnvelope: typeof parseStoredQueueEnvelope;
50
48
  parseStoredQueueJobRow: typeof parseStoredQueueJobRow;
51
49
  quoteIdentifierPath: typeof quoteIdentifierPath;
50
+ resolveDatabaseConnection: typeof resolveDatabaseConnection;
52
51
  serializeQueueJson: typeof serializeQueueJson;
53
52
  };
54
53
 
@@ -58,6 +57,7 @@ declare class DatabaseQueueDriverError extends Error {
58
57
  }
59
58
  declare function wrapDatabaseError(connectionName: string, action: string, error: unknown): DatabaseQueueDriverError;
60
59
  declare function normalizeQueueNames(queueNames: readonly string[] | undefined, fallbackQueueName: string): readonly string[];
60
+ declare function createPlaceholders(connection: DatabaseContext, count: number, startIndex?: number): readonly string[];
61
61
  declare class DatabaseQueueDriver implements QueueAsyncDriver {
62
62
  private readonly connection;
63
63
  private readonly context;
@@ -85,6 +85,7 @@ declare class DatabaseQueueDriver implements QueueAsyncDriver {
85
85
  }
86
86
  declare const databaseQueueDriverFactory: QueueDriverFactory<NormalizedQueueDatabaseConnectionConfig>;
87
87
  declare const databaseQueueDriverInternals: {
88
+ createPlaceholders: typeof createPlaceholders;
88
89
  normalizeDatabaseErrorMessage: typeof normalizeDatabaseErrorMessage;
89
90
  normalizeQueueNames: typeof normalizeQueueNames;
90
91
  wrapDatabaseError: typeof wrapDatabaseError;
@@ -95,10 +96,15 @@ declare function getFailedStoreConnection(): Promise<{
95
96
  connection: DatabaseContext;
96
97
  tableName: string;
97
98
  } | null>;
99
+ declare function loadFailedJobs(failedStore: {
100
+ connection: DatabaseContext;
101
+ tableName: string;
102
+ }, id?: string): Promise<readonly QueueFailedJobRecord[]>;
98
103
  declare const queueDbFailedJobStore: QueueFailedJobStore;
99
104
  declare const queueDbFailedStoreInternals: {
100
105
  getFailedStoreConfig: typeof getFailedStoreConfig;
101
106
  getFailedStoreConnection: typeof getFailedStoreConnection;
107
+ loadFailedJobs: typeof loadFailedJobs;
102
108
  };
103
109
 
104
110
  declare function createQueueDbRuntimeOptions(): Readonly<{
package/dist/index.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/database.ts
2
+ import { connectionAsyncContext, DB } from "@holo-js/db";
2
3
  function isPlainObject(value) {
3
4
  if (typeof value !== "object" || value === null || Array.isArray(value)) {
4
5
  return false;
@@ -93,16 +94,16 @@ function parseStoredPayload(value, label) {
93
94
  return parsed;
94
95
  }
95
96
  function parseStoredQueueJobRow(row) {
96
- return Object.freeze({
97
- id: coerceRequiredString(row.id, "Stored queue job id"),
98
- name: coerceRequiredString(row.job, "Stored queue job name"),
99
- connection: coerceRequiredString(row.connection, "Stored queue job connection"),
100
- queue: coerceRequiredString(row.queue, "Stored queue job queue"),
97
+ return parseStoredQueueEnvelope({
98
+ id: row.id,
99
+ name: row.job,
100
+ connection: row.connection,
101
+ queue: row.queue,
101
102
  payload: parseStoredPayload(row.payload, "Stored queue job payload"),
102
- attempts: coerceRequiredInteger(row.attempts, "Stored queue job attempts"),
103
- maxAttempts: coerceRequiredInteger(row.max_attempts, "Stored queue job max attempts"),
104
- ...typeof row.available_at === "undefined" || row.available_at === null ? {} : { availableAt: coerceRequiredInteger(row.available_at, "Stored queue job availability") },
105
- createdAt: coerceRequiredInteger(row.created_at, "Stored queue job creation time")
103
+ attempts: row.attempts,
104
+ maxAttempts: row.max_attempts,
105
+ availableAt: row.available_at,
106
+ createdAt: row.created_at
106
107
  });
107
108
  }
108
109
  function parseStoredQueueEnvelope(value) {
@@ -142,6 +143,13 @@ async function ensureConnectionReady(connection) {
142
143
  await connection.initialize();
143
144
  return connection;
144
145
  }
146
+ function resolveDatabaseConnection(name) {
147
+ const active = connectionAsyncContext.getActive()?.connection;
148
+ if (active && active.getConnectionName() === name) {
149
+ return active;
150
+ }
151
+ return DB.connection(name);
152
+ }
145
153
  var queueDatabaseInternals = {
146
154
  assertQueueJsonValue,
147
155
  coerceOptionalInteger,
@@ -149,20 +157,18 @@ var queueDatabaseInternals = {
149
157
  coerceRequiredString,
150
158
  createPlaceholderList,
151
159
  ensureConnectionReady,
152
- isPlainObject,
153
160
  normalizeIdentifierPath,
154
161
  parseStoredFailedQueueJobRow,
155
- parseStoredQueueEnvelope,
156
162
  parseStoredPayload,
163
+ parseStoredQueueEnvelope,
157
164
  parseStoredQueueJobRow,
158
165
  quoteIdentifierPath,
166
+ resolveDatabaseConnection,
159
167
  serializeQueueJson
160
168
  };
161
169
 
162
170
  // src/drivers/database.ts
163
171
  import { randomUUID } from "crypto";
164
- import { DB } from "@holo-js/db";
165
- import { connectionAsyncContext } from "@holo-js/db";
166
172
  function normalizeDatabaseErrorMessage(error) {
167
173
  if (error instanceof Error) {
168
174
  return error.message;
@@ -192,31 +198,24 @@ function normalizeQueueNames(queueNames, fallbackQueueName) {
192
198
  return Object.freeze(normalized.length > 0 ? normalized : [fallbackQueueName]);
193
199
  }
194
200
  function createPlaceholders(connection, count, startIndex = 1) {
195
- return queueDatabaseInternals.createPlaceholderList(connection.getDialect(), count, startIndex).split(", ");
196
- }
197
- function resolveDatabaseConnection(name) {
198
- const active = connectionAsyncContext.getActive()?.connection;
199
- if (active && active.getConnectionName() === name) {
200
- return active;
201
- }
202
- return DB.connection(name);
201
+ return createPlaceholderList(connection.getDialect(), count, startIndex).split(", ");
203
202
  }
204
203
  var DatabaseQueueDriver = class {
205
204
  constructor(connection, context) {
206
205
  this.connection = connection;
207
206
  this.context = context;
208
207
  this.name = connection.name;
209
- this.tableName = queueDatabaseInternals.normalizeIdentifierPath(connection.table, "Queue table name");
208
+ this.tableName = normalizeIdentifierPath(connection.table, "Queue table name");
210
209
  }
211
210
  name;
212
211
  driver = "database";
213
212
  mode = "async";
214
213
  tableName;
215
214
  async getConnection() {
216
- return queueDatabaseInternals.ensureConnectionReady(resolveDatabaseConnection(this.connection.connection));
215
+ return ensureConnectionReady(resolveDatabaseConnection(this.connection.connection));
217
216
  }
218
217
  getQuotedTable(connection) {
219
- return queueDatabaseInternals.quoteIdentifierPath(connection.getDialect(), this.tableName);
218
+ return quoteIdentifierPath(connection.getDialect(), this.tableName);
220
219
  }
221
220
  getExpiredReservationCutoff(now) {
222
221
  return now - this.connection.retryAfter * 1e3;
@@ -225,7 +224,7 @@ var DatabaseQueueDriver = class {
225
224
  return Object.freeze({
226
225
  reservationId,
227
226
  reservedAt,
228
- envelope: queueDatabaseInternals.parseStoredQueueJobRow(row)
227
+ envelope: parseStoredQueueJobRow(row)
229
228
  });
230
229
  }
231
230
  async dispatch(job) {
@@ -240,7 +239,7 @@ var DatabaseQueueDriver = class {
240
239
  job.name,
241
240
  job.connection,
242
241
  job.queue,
243
- queueDatabaseInternals.serializeQueueJson(job.payload),
242
+ serializeQueueJson(job.payload),
244
243
  job.attempts,
245
244
  job.maxAttempts,
246
245
  job.availableAt ?? job.createdAt,
@@ -277,7 +276,7 @@ var DatabaseQueueDriver = class {
277
276
  break;
278
277
  }
279
278
  const reservationId = `${input.workerId}:${randomUUID()}`;
280
- const nextAttempts = queueDatabaseInternals.coerceRequiredInteger(row.attempts, "Stored queue job attempts") + 1;
279
+ const nextAttempts = coerceRequiredInteger(row.attempts, "Stored queue job attempts") + 1;
281
280
  const [
282
281
  reservedAtPlaceholder,
283
282
  reservationPlaceholder,
@@ -378,6 +377,7 @@ var databaseQueueDriverFactory = {
378
377
  }
379
378
  };
380
379
  var databaseQueueDriverInternals = {
380
+ createPlaceholders,
381
381
  normalizeDatabaseErrorMessage,
382
382
  normalizeQueueNames,
383
383
  wrapDatabaseError
@@ -385,39 +385,49 @@ var databaseQueueDriverInternals = {
385
385
 
386
386
  // src/failed.ts
387
387
  import { randomUUID as randomUUID2 } from "crypto";
388
- import { DB as DB2 } from "@holo-js/db";
389
- import { connectionAsyncContext as connectionAsyncContext2 } from "@holo-js/db";
390
388
  import { getQueueRuntime } from "@holo-js/queue";
391
389
  function getFailedStoreConfig() {
392
390
  return getQueueRuntime().config.failed;
393
391
  }
394
- function resolveDatabaseConnection2(name) {
395
- const active = connectionAsyncContext2.getActive()?.connection;
396
- if (active && active.getConnectionName() === name) {
397
- return active;
398
- }
399
- return DB2.connection(name);
400
- }
401
392
  async function getFailedStoreConnection() {
402
393
  const config = getFailedStoreConfig();
403
394
  if (config === false) {
404
395
  return null;
405
396
  }
406
- const tableName = queueDatabaseInternals.normalizeIdentifierPath(config.table, "Failed jobs table name");
407
- const connection = await queueDatabaseInternals.ensureConnectionReady(resolveDatabaseConnection2(config.connection));
397
+ const tableName = normalizeIdentifierPath(config.table, "Failed jobs table name");
398
+ const connection = await ensureConnectionReady(resolveDatabaseConnection(config.connection));
408
399
  return {
409
400
  connection,
410
401
  tableName
411
402
  };
412
403
  }
404
+ async function loadFailedJobs(failedStore, id) {
405
+ const quotedTable = quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
406
+ const dialect = failedStore.connection.getDialect();
407
+ const filter = typeof id === "string" ? {
408
+ clause: ` WHERE id = ${dialect.createPlaceholder(1)}`,
409
+ bindings: [id],
410
+ source: "queue:failed:load"
411
+ } : {
412
+ clause: "",
413
+ bindings: void 0,
414
+ source: "queue:failed:list"
415
+ };
416
+ const result = await failedStore.connection.queryCompiled({
417
+ sql: `SELECT id, job_id, payload, exception, failed_at FROM ${quotedTable}${filter.clause} ORDER BY failed_at DESC, id DESC`,
418
+ bindings: filter.bindings,
419
+ source: filter.source
420
+ });
421
+ return Object.freeze(result.rows.map((row) => parseStoredFailedQueueJobRow(row)));
422
+ }
413
423
  var queueDbFailedJobStore = {
414
424
  async persistFailedJob(reserved, error) {
415
425
  const failedStore = await getFailedStoreConnection();
416
426
  if (!failedStore) {
417
427
  return null;
418
428
  }
419
- const quotedTable = queueDatabaseInternals.quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
420
- const placeholders = queueDatabaseInternals.createPlaceholderList(failedStore.connection.getDialect(), 7);
429
+ const quotedTable = quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
430
+ const placeholders = createPlaceholderList(failedStore.connection.getDialect(), 7);
421
431
  const record = Object.freeze({
422
432
  id: randomUUID2(),
423
433
  jobId: reserved.envelope.id,
@@ -433,7 +443,7 @@ var queueDbFailedJobStore = {
433
443
  reserved.envelope.name,
434
444
  reserved.envelope.connection,
435
445
  reserved.envelope.queue,
436
- queueDatabaseInternals.serializeQueueJson(reserved.envelope),
446
+ serializeQueueJson(reserved.envelope),
437
447
  record.exception,
438
448
  record.failedAt
439
449
  ],
@@ -446,28 +456,16 @@ var queueDbFailedJobStore = {
446
456
  if (!failedStore) {
447
457
  return Object.freeze([]);
448
458
  }
449
- const quotedTable = queueDatabaseInternals.quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
450
- const result = await failedStore.connection.queryCompiled({
451
- sql: `SELECT id, job_id, payload, exception, failed_at FROM ${quotedTable} ORDER BY failed_at DESC, id DESC`,
452
- source: "queue:failed:list"
453
- });
454
- return Object.freeze(result.rows.map((row) => queueDatabaseInternals.parseStoredFailedQueueJobRow(row)));
459
+ return loadFailedJobs(failedStore);
455
460
  },
456
461
  async retryFailedJobs(identifier, retry) {
457
462
  const failedStore = await getFailedStoreConnection();
458
463
  if (!failedStore) {
459
464
  return 0;
460
465
  }
461
- const quotedTable = queueDatabaseInternals.quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
466
+ const quotedTable = quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
462
467
  const dialect = failedStore.connection.getDialect();
463
- const records = await (identifier === "all" ? await this.listFailedJobs() : (() => {
464
- const placeholder = dialect.createPlaceholder(1);
465
- return failedStore.connection.queryCompiled({
466
- sql: `SELECT id, job_id, payload, exception, failed_at FROM ${quotedTable} WHERE id = ${placeholder}`,
467
- bindings: [identifier],
468
- source: "queue:failed:load"
469
- }).then((result) => Object.freeze(result.rows.map((row) => queueDatabaseInternals.parseStoredFailedQueueJobRow(row))));
470
- })());
468
+ const records = await loadFailedJobs(failedStore, identifier === "all" ? void 0 : identifier);
471
469
  let retried = 0;
472
470
  for (const record of records) {
473
471
  await retry(record);
@@ -486,7 +484,7 @@ var queueDbFailedJobStore = {
486
484
  if (!failedStore) {
487
485
  return false;
488
486
  }
489
- const quotedTable = queueDatabaseInternals.quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
487
+ const quotedTable = quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
490
488
  const placeholder = failedStore.connection.getDialect().createPlaceholder(1);
491
489
  const result = await failedStore.connection.executeCompiled({
492
490
  sql: `DELETE FROM ${quotedTable} WHERE id = ${placeholder}`,
@@ -500,7 +498,7 @@ var queueDbFailedJobStore = {
500
498
  if (!failedStore) {
501
499
  return 0;
502
500
  }
503
- const quotedTable = queueDatabaseInternals.quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
501
+ const quotedTable = quoteIdentifierPath(failedStore.connection.getDialect(), failedStore.tableName);
504
502
  const result = await failedStore.connection.executeCompiled({
505
503
  sql: `DELETE FROM ${quotedTable}`,
506
504
  source: "queue:failed:flush"
@@ -510,7 +508,8 @@ var queueDbFailedJobStore = {
510
508
  };
511
509
  var queueDbFailedStoreInternals = {
512
510
  getFailedStoreConfig,
513
- getFailedStoreConnection
511
+ getFailedStoreConnection,
512
+ loadFailedJobs
514
513
  };
515
514
 
516
515
  // src/runtime.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@holo-js/queue-db",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "Holo-JS Framework - DB-backed integrations for @holo-js/queue",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -23,13 +23,13 @@
23
23
  "test": "vitest --run"
24
24
  },
25
25
  "dependencies": {
26
- "@holo-js/db": "^0.1.3",
27
- "@holo-js/queue": "^0.1.3"
26
+ "@holo-js/db": "^0.1.5",
27
+ "@holo-js/queue": "^0.1.5"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.10.2",
31
31
  "tsup": "^8.3.5",
32
32
  "typescript": "^5.7.2",
33
- "vitest": "^2.1.8"
33
+ "vitest": "^4.1.5"
34
34
  }
35
35
  }