@nest-native/jobs 0.1.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.
Files changed (68) hide show
  1. package/README.md +115 -0
  2. package/dist/dialects/mysql/index.d.ts +2 -0
  3. package/dist/dialects/mysql/index.js +21 -0
  4. package/dist/dialects/mysql/index.js.map +1 -0
  5. package/dist/dialects/mysql/job-store.d.ts +35 -0
  6. package/dist/dialects/mysql/job-store.js +150 -0
  7. package/dist/dialects/mysql/job-store.js.map +1 -0
  8. package/dist/dialects/mysql/schema.d.ts +255 -0
  9. package/dist/dialects/mysql/schema.js +47 -0
  10. package/dist/dialects/mysql/schema.js.map +1 -0
  11. package/dist/dialects/postgres/index.d.ts +2 -0
  12. package/dist/dialects/postgres/index.js +21 -0
  13. package/dist/dialects/postgres/index.js.map +1 -0
  14. package/dist/dialects/postgres/job-store.d.ts +32 -0
  15. package/dist/dialects/postgres/job-store.js +145 -0
  16. package/dist/dialects/postgres/job-store.js.map +1 -0
  17. package/dist/dialects/postgres/schema.d.ts +262 -0
  18. package/dist/dialects/postgres/schema.js +37 -0
  19. package/dist/dialects/postgres/schema.js.map +1 -0
  20. package/dist/dialects/sqlite/index.d.ts +2 -0
  21. package/dist/dialects/sqlite/index.js +21 -0
  22. package/dist/dialects/sqlite/index.js.map +1 -0
  23. package/dist/dialects/sqlite/job-store.d.ts +32 -0
  24. package/dist/dialects/sqlite/job-store.js +155 -0
  25. package/dist/dialects/sqlite/job-store.js.map +1 -0
  26. package/dist/dialects/sqlite/schema.d.ts +279 -0
  27. package/dist/dialects/sqlite/schema.js +37 -0
  28. package/dist/dialects/sqlite/schema.js.map +1 -0
  29. package/dist/enqueue-input.d.ts +12 -0
  30. package/dist/enqueue-input.js +26 -0
  31. package/dist/enqueue-input.js.map +1 -0
  32. package/dist/errors.d.ts +18 -0
  33. package/dist/errors.js +33 -0
  34. package/dist/errors.js.map +1 -0
  35. package/dist/index.d.ts +10 -0
  36. package/dist/index.js +30 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/interfaces.d.ts +125 -0
  39. package/dist/interfaces.js +10 -0
  40. package/dist/interfaces.js.map +1 -0
  41. package/dist/job-handler.decorator.d.ts +31 -0
  42. package/dist/job-handler.decorator.js +18 -0
  43. package/dist/job-handler.decorator.js.map +1 -0
  44. package/dist/jobs-claimer.service.d.ts +37 -0
  45. package/dist/jobs-claimer.service.js +121 -0
  46. package/dist/jobs-claimer.service.js.map +1 -0
  47. package/dist/jobs-handler.explorer.d.ts +24 -0
  48. package/dist/jobs-handler.explorer.js +67 -0
  49. package/dist/jobs-handler.explorer.js.map +1 -0
  50. package/dist/jobs-worker.d.ts +21 -0
  51. package/dist/jobs-worker.js +40 -0
  52. package/dist/jobs-worker.js.map +1 -0
  53. package/dist/jobs.module.d.ts +19 -0
  54. package/dist/jobs.module.js +49 -0
  55. package/dist/jobs.module.js.map +1 -0
  56. package/dist/jobs.service.d.ts +25 -0
  57. package/dist/jobs.service.js +55 -0
  58. package/dist/jobs.service.js.map +1 -0
  59. package/dist/testing/harness.d.ts +61 -0
  60. package/dist/testing/harness.js +86 -0
  61. package/dist/testing/harness.js.map +1 -0
  62. package/dist/testing/index.d.ts +1 -0
  63. package/dist/testing/index.js +19 -0
  64. package/dist/testing/index.js.map +1 -0
  65. package/dist/tokens.d.ts +10 -0
  66. package/dist/tokens.js +15 -0
  67. package/dist/tokens.js.map +1 -0
  68. package/package.json +107 -0
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @nest-native/jobs
2
+
3
+ <p align="center">Background jobs for NestJS without Redis — a Drizzle-backed job queue (SQLite, Postgres &amp; MySQL) with transactional enqueue, retries, delayed and unique jobs.</p>
4
+
5
+ <p align="center">
6
+ <a href="https://www.npmjs.com/package/@nest-native/jobs"><img src="https://img.shields.io/npm/v/@nest-native/jobs.svg" alt="NPM Version" /></a>
7
+ <a href="https://www.npmjs.com/package/@nest-native/jobs"><img src="https://img.shields.io/npm/dm/@nest-native/jobs.svg" alt="NPM Downloads" /></a>
8
+ <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="Package License" /></a>
9
+ <img src="https://img.shields.io/badge/coverage-100%25-brightgreen.svg" alt="Test Coverage" />
10
+ </p>
11
+
12
+ > [!NOTE]
13
+ > **v0.x — early but stable.** The producer, claimer, handler discovery, and the three Drizzle stores are implemented and tested at 100% coverage. SQLite, Postgres, and MySQL are supported.
14
+
15
+ ## The problem it solves
16
+
17
+ Most NestJS apps grow a first background job long before they need a queueing *system*: send a welcome email after signup, generate a report, retry a flaky webhook. The official NestJS answer is `@nestjs/bullmq` — which means **operating Redis** for what is often a handful of jobs a minute. And because Redis is a second system, the classic dual-write bug appears on day one: the signup commits but the process crashes before `queue.add()` — the email is never sent. Or `queue.add()` succeeds and the transaction rolls back — a welcome email for a user that does not exist.
18
+
19
+ `@nest-native/jobs` stores jobs in the **same Drizzle database your app already has**:
20
+
21
+ - **Transactional enqueue** — `enqueue()` inserts the job row *inside your business transaction* (via [`@nestjs-cls/transactional`](https://www.npmjs.com/package/@nestjs-cls/transactional)). The job exists if and only if your writes committed.
22
+ - **Nest-native execution** — declare a class with `@JobHandler('email.welcome')`, register it as a provider, and the claimer dispatches to it with full DI. Handlers are discovered at bootstrap; duplicate names throw at startup.
23
+ - **Retries, delays, priorities, unique jobs** — jittered exponential backoff (or `RetryableError`'s explicit `delayMs`), `PermanentError` to fail fast, `runAt`/`delayMs` scheduling, `priority` ordering, and `uniqueKey` dedup among active jobs.
24
+ - **Zero runtime dependencies** — everything (Nest, Drizzle, your driver) is a peer you already installed.
25
+
26
+ ## Install
27
+
28
+ ```bash
29
+ npm install @nest-native/jobs
30
+ # plus your driver (peer dependencies):
31
+ npm install drizzle-orm @nestjs-cls/transactional better-sqlite3 # or pg / mysql2
32
+ ```
33
+
34
+ ## Entry points
35
+
36
+ | Import | Contents |
37
+ | --- | --- |
38
+ | `@nest-native/jobs` | core engine — `JobsService` (enqueue), `JobsClaimer` + `runWorkerLoop`, `@JobHandler` + `JobsHandlerExplorer`, `RetryableError`/`PermanentError`, the `JobStore` seam, `JobsModule` |
39
+ | `@nest-native/jobs/sqlite` | better-sqlite3 (synchronous) store + the `jobs` table definition |
40
+ | `@nest-native/jobs/postgres` | node-postgres (async) store + table definition |
41
+ | `@nest-native/jobs/mysql` | mysql2 (async) store + table definition |
42
+ | `@nest-native/jobs/testing` | `drainJobs` + `RecordingJobHandler` for hermetic tests |
43
+
44
+ ## Usage
45
+
46
+ ```ts
47
+ // app.module.ts — wire CLS + the dialect store once
48
+ JobsModule.forRoot({
49
+ drizzleInstanceToken: DRIZZLE,
50
+ store: new SqliteJobStore(),
51
+ });
52
+
53
+ // user.service.ts — enqueue inside the business transaction
54
+ @Injectable()
55
+ export class UserService {
56
+ constructor(
57
+ @InjectTransaction() private readonly db: AppDatabase,
58
+ private readonly jobs: JobsService<SqliteJobStore>,
59
+ ) {}
60
+
61
+ @Transactional()
62
+ register(email: string) {
63
+ this.db.insert(users).values({ email }).run();
64
+ this.jobs.enqueue({
65
+ name: 'email.welcome',
66
+ payload: { email },
67
+ uniqueKey: `welcome:${email}`, // dedup among active jobs
68
+ });
69
+ // both rows commit atomically; a throw rolls both back
70
+ }
71
+ }
72
+
73
+ // welcome-email.handler.ts — executed by the claimer, with full DI
74
+ @JobHandler('email.welcome')
75
+ @Injectable()
76
+ export class WelcomeEmailHandler implements JobHandler {
77
+ async handle(payload: Record<string, unknown>, ctx: JobContext) {
78
+ await this.mailer.send(String(payload.email)); // throw RetryableError / PermanentError to steer retries
79
+ }
80
+ }
81
+
82
+ // worker (same process or a dedicated one)
83
+ const controller = new AbortController();
84
+ void runWorkerLoop(app.get(JobsClaimer), { signal: controller.signal });
85
+ ```
86
+
87
+ Delivery is **at-least-once**: a worker crash mid-job means the row is reclaimed after `stuckTimeoutMs` and run again. Make handlers idempotent or key their side effects on `ctx.jobId`.
88
+
89
+ ### The uniqueKey contract
90
+
91
+ `uniqueKey` means "unique among **active** jobs", identically on all three dialects: a full unique index on `(name, unique_key)`, and terminal transitions (`completed`, `failed`) clear the key. Enqueueing a duplicate `(name, uniqueKey)` while one is pending/processing is a **no-op that returns the existing row**; once that job finishes, the key is free again. Jobs without a `uniqueKey` never collide.
92
+
93
+ ## Honest comparison
94
+
95
+ | | BullMQ (`@nestjs/bullmq`) | pg-boss | `@nest-native/jobs` |
96
+ | --- | --- | --- | --- |
97
+ | Backing store | Redis (required) | Postgres only | the Drizzle DB you already run — SQLite, Postgres, or MySQL |
98
+ | NestJS integration | official wrapper module | none (framework-agnostic) | native — module, DI, `@JobHandler` decorators |
99
+ | Enqueue in your DB transaction | no (Redis is a second system) | yes (raw SQL in your tx) | yes — first-class, via `@nestjs-cls/transactional` |
100
+ | Delivery | Redis push (blocking ops) | polling + LISTEN/NOTIFY | polling claimer |
101
+ | Throughput | very high | high | right-sized — polling batches, fine for most apps' background work |
102
+ | Repeatable / cron jobs | yes | yes | no (non-goal — use `@nestjs/schedule`) |
103
+ | Dashboards, rate limiting | yes | partial | no |
104
+ | Runtime dependencies | Redis server + client | `pg` | zero (peers you already have) |
105
+
106
+ If you need tens of thousands of jobs per second, sandboxed processors, or a dashboard, use BullMQ — it is excellent at that. If you run Postgres without Nest, pg-boss is battle-tested. This library is for the large middle: NestJS + Drizzle apps that want reliable background jobs **without operating another system**.
107
+
108
+ ## Non-goals (v0.1)
109
+
110
+ - **Cron / repeatable jobs** — `@nestjs/schedule` already does this well; combine it with `enqueue()` if you want scheduled work to flow through the queue.
111
+ - **Dashboards / UI**, **rate limiting**, **concurrency groups**.
112
+ - **LISTEN/NOTIFY push** — the claimer polls; `pollIntervalMs` is your latency knob.
113
+ - **Redis-class throughput** — this is a polling claimer over your relational DB, by design.
114
+
115
+ Part of the [nest-native](https://github.com/nest-native) family. Not affiliated with the NestJS core team. MIT licensed.
@@ -0,0 +1,2 @@
1
+ export * from './schema';
2
+ export * from './job-store';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ // @nest-native/jobs/mysql — the mysql2 (async) dialect:
18
+ // the `jobs` table definition + the MySQL store.
19
+ __exportStar(require("./schema"), exports);
20
+ __exportStar(require("./job-store"), exports);
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../dialects/mysql/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAwD;AACxD,iDAAiD;AACjD,2CAAyB;AACzB,8CAA4B"}
@@ -0,0 +1,35 @@
1
+ import type { EnqueueJobInput, JobRow, JobStore, ResolvedRunnerConfig } from '../../interfaces';
2
+ /**
3
+ * MySQL surfaces a unique-constraint violation as error code `ER_DUP_ENTRY`
4
+ * (errno `1062`). mysql2 sets both `error.code === 'ER_DUP_ENTRY'` and
5
+ * `error.errno === 1062`; Drizzle wraps driver errors in a `DrizzleQueryError`,
6
+ * so the code/errno may instead sit on `error.cause`. Check the code **and**
7
+ * the errno, on the error and on its `cause`, so the predicate is robust to
8
+ * both the driver's shape and Drizzle's wrapping.
9
+ */
10
+ export declare function isMysqlUniqueViolation(error: unknown): boolean;
11
+ /**
12
+ * MySQL (mysql2) job store. Every method is **asynchronous** — `enqueue`
13
+ * awaits the insert (call it with `await` inside an async `@Transactional`
14
+ * body), and the claimer's batch claim runs in an async transaction.
15
+ *
16
+ * Unlike Postgres, MySQL's `INSERT` has no `RETURNING`, so `enqueue` inserts
17
+ * the row (client-generated UUID id) and reads it back by id to return the
18
+ * canonical {@link JobRow}. A `(name, unique_key)` unique violation is the
19
+ * active-dedup no-op: the store returns the EXISTING active row instead.
20
+ */
21
+ export declare class MysqlJobStore implements JobStore {
22
+ enqueue(db: unknown, input: EnqueueJobInput<object>): Promise<JobRow>;
23
+ /**
24
+ * On a unique violation with a `uniqueKey`, the ACTIVE row that owns the
25
+ * `(name, uniqueKey)` pair — terminal rows cannot own it (their key is
26
+ * cleared to NULL). Any other error, or a vanished row (the owner completed
27
+ * between the insert and this read), resolves undefined so the caller
28
+ * rethrows the original error.
29
+ */
30
+ private findActiveDuplicate;
31
+ claimBatch(db: unknown, cfg: ResolvedRunnerConfig): Promise<JobRow[]>;
32
+ markCompleted(db: unknown, id: string): Promise<void>;
33
+ retry(db: unknown, id: string, delayMs: number, lastError?: string): Promise<void>;
34
+ markFailed(db: unknown, id: string, reason: string): Promise<void>;
35
+ }
@@ -0,0 +1,150 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MysqlJobStore = void 0;
4
+ exports.isMysqlUniqueViolation = isMysqlUniqueViolation;
5
+ const node_crypto_1 = require("node:crypto");
6
+ const drizzle_orm_1 = require("drizzle-orm");
7
+ const enqueue_input_1 = require("../../enqueue-input");
8
+ const schema_1 = require("./schema");
9
+ /**
10
+ * MySQL surfaces a unique-constraint violation as error code `ER_DUP_ENTRY`
11
+ * (errno `1062`). mysql2 sets both `error.code === 'ER_DUP_ENTRY'` and
12
+ * `error.errno === 1062`; Drizzle wraps driver errors in a `DrizzleQueryError`,
13
+ * so the code/errno may instead sit on `error.cause`. Check the code **and**
14
+ * the errno, on the error and on its `cause`, so the predicate is robust to
15
+ * both the driver's shape and Drizzle's wrapping.
16
+ */
17
+ function isMysqlUniqueViolation(error) {
18
+ return isDuplicate(error) || isDuplicate(error?.cause);
19
+ }
20
+ function isDuplicate(error) {
21
+ return hasProp(error, 'code', 'ER_DUP_ENTRY') || hasProp(error, 'errno', 1062);
22
+ }
23
+ function hasProp(error, key, value) {
24
+ return (typeof error === 'object' &&
25
+ error !== null &&
26
+ key in error &&
27
+ error[key] === value);
28
+ }
29
+ /**
30
+ * MySQL (mysql2) job store. Every method is **asynchronous** — `enqueue`
31
+ * awaits the insert (call it with `await` inside an async `@Transactional`
32
+ * body), and the claimer's batch claim runs in an async transaction.
33
+ *
34
+ * Unlike Postgres, MySQL's `INSERT` has no `RETURNING`, so `enqueue` inserts
35
+ * the row (client-generated UUID id) and reads it back by id to return the
36
+ * canonical {@link JobRow}. A `(name, unique_key)` unique violation is the
37
+ * active-dedup no-op: the store returns the EXISTING active row instead.
38
+ */
39
+ class MysqlJobStore {
40
+ async enqueue(db, input) {
41
+ const id = (0, node_crypto_1.randomUUID)();
42
+ const availableAt = (0, enqueue_input_1.resolveAvailableAt)(input).toISOString();
43
+ try {
44
+ await db.insert(schema_1.jobs).values({
45
+ id,
46
+ name: input.name,
47
+ // The one place the structural input payload widens to the stored shape.
48
+ payload: input.payload,
49
+ status: 'pending',
50
+ maxAttempts: input.maxAttempts ?? 10,
51
+ uniqueKey: input.uniqueKey ?? null,
52
+ priority: input.priority ?? 0,
53
+ availableAt,
54
+ createdAt: new Date().toISOString(),
55
+ });
56
+ }
57
+ catch (error) {
58
+ const existing = await this.findActiveDuplicate(db, input, error);
59
+ if (!existing)
60
+ throw error;
61
+ return existing;
62
+ }
63
+ const [row] = await db.select().from(schema_1.jobs).where((0, drizzle_orm_1.eq)(schema_1.jobs.id, id));
64
+ return row;
65
+ }
66
+ /**
67
+ * On a unique violation with a `uniqueKey`, the ACTIVE row that owns the
68
+ * `(name, uniqueKey)` pair — terminal rows cannot own it (their key is
69
+ * cleared to NULL). Any other error, or a vanished row (the owner completed
70
+ * between the insert and this read), resolves undefined so the caller
71
+ * rethrows the original error.
72
+ */
73
+ async findActiveDuplicate(db, input, error) {
74
+ if (!isMysqlUniqueViolation(error) || input.uniqueKey == null) {
75
+ return undefined;
76
+ }
77
+ const [existing] = await db
78
+ .select()
79
+ .from(schema_1.jobs)
80
+ .where((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.jobs.name, input.name), (0, drizzle_orm_1.eq)(schema_1.jobs.uniqueKey, input.uniqueKey)));
81
+ return existing;
82
+ }
83
+ async claimBatch(db, cfg) {
84
+ const now = new Date();
85
+ const nowIso = now.toISOString();
86
+ const stuckCutoff = new Date(now.getTime() - cfg.stuckTimeoutMs).toISOString();
87
+ return db.transaction(async (tx) => {
88
+ const candidates = await tx
89
+ .select({ id: schema_1.jobs.id })
90
+ .from(schema_1.jobs)
91
+ .where((0, drizzle_orm_1.or)((0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.jobs.status, 'pending'), (0, drizzle_orm_1.lte)(schema_1.jobs.availableAt, nowIso)), (0, drizzle_orm_1.and)((0, drizzle_orm_1.eq)(schema_1.jobs.status, 'processing'), (0, drizzle_orm_1.lte)(schema_1.jobs.claimedAt, stuckCutoff))))
92
+ .orderBy((0, drizzle_orm_1.desc)(schema_1.jobs.priority), (0, drizzle_orm_1.asc)(schema_1.jobs.availableAt))
93
+ .limit(cfg.batchSize);
94
+ if (candidates.length === 0)
95
+ return [];
96
+ const ids = candidates.map((c) => c.id);
97
+ await tx
98
+ .update(schema_1.jobs)
99
+ .set({ status: 'processing', claimedAt: nowIso, claimedBy: cfg.workerInstanceId })
100
+ .where((0, drizzle_orm_1.inArray)(schema_1.jobs.id, ids));
101
+ return tx
102
+ .select()
103
+ .from(schema_1.jobs)
104
+ .where((0, drizzle_orm_1.inArray)(schema_1.jobs.id, ids))
105
+ .orderBy((0, drizzle_orm_1.desc)(schema_1.jobs.priority), (0, drizzle_orm_1.asc)(schema_1.jobs.availableAt));
106
+ });
107
+ }
108
+ async markCompleted(db, id) {
109
+ await db
110
+ .update(schema_1.jobs)
111
+ .set({
112
+ status: 'completed',
113
+ processedAt: new Date().toISOString(),
114
+ lastError: null,
115
+ // Terminal → release the active-dedup key.
116
+ uniqueKey: null,
117
+ })
118
+ .where((0, drizzle_orm_1.eq)(schema_1.jobs.id, id));
119
+ }
120
+ async retry(db, id, delayMs, lastError) {
121
+ const nextAvailable = new Date(Date.now() + delayMs).toISOString();
122
+ await db
123
+ .update(schema_1.jobs)
124
+ .set({
125
+ status: 'pending',
126
+ attempts: (0, drizzle_orm_1.sql) `${schema_1.jobs.attempts} + 1`,
127
+ availableAt: nextAvailable,
128
+ claimedAt: null,
129
+ claimedBy: null,
130
+ lastError: lastError ?? null,
131
+ // Still active → the uniqueKey stays claimed.
132
+ })
133
+ .where((0, drizzle_orm_1.eq)(schema_1.jobs.id, id));
134
+ }
135
+ async markFailed(db, id, reason) {
136
+ await db
137
+ .update(schema_1.jobs)
138
+ .set({
139
+ status: 'failed',
140
+ attempts: (0, drizzle_orm_1.sql) `${schema_1.jobs.attempts} + 1`,
141
+ lastError: reason,
142
+ processedAt: new Date().toISOString(),
143
+ // Terminal → release the active-dedup key.
144
+ uniqueKey: null,
145
+ })
146
+ .where((0, drizzle_orm_1.eq)(schema_1.jobs.id, id));
147
+ }
148
+ }
149
+ exports.MysqlJobStore = MysqlJobStore;
150
+ //# sourceMappingURL=job-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"job-store.js","sourceRoot":"","sources":["../../../dialects/mysql/job-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * MySQL `jobs` table. Add it to your Drizzle schema and generate a migration
3
+ * with drizzle-kit. Timestamps are stored as ISO-8601 `varchar` so the row
4
+ * shape is identical across dialects (ISO-8601 compares lexicographically,
5
+ * which the claimer's `available_at` range query relies on).
6
+ */
7
+ export declare const jobs: import("drizzle-orm/mysql-core").MySqlTableWithColumns<{
8
+ name: "jobs";
9
+ schema: undefined;
10
+ columns: {
11
+ id: import("drizzle-orm/mysql-core").MySqlColumn<{
12
+ name: "id";
13
+ tableName: "jobs";
14
+ dataType: "string";
15
+ columnType: "MySqlVarChar";
16
+ data: string;
17
+ driverParam: string | number;
18
+ notNull: true;
19
+ hasDefault: false;
20
+ isPrimaryKey: true;
21
+ isAutoincrement: false;
22
+ hasRuntimeDefault: false;
23
+ enumValues: [string, ...string[]];
24
+ baseColumn: never;
25
+ identity: undefined;
26
+ generated: undefined;
27
+ }, {}, {}>;
28
+ name: import("drizzle-orm/mysql-core").MySqlColumn<{
29
+ name: "name";
30
+ tableName: "jobs";
31
+ dataType: "string";
32
+ columnType: "MySqlVarChar";
33
+ data: string;
34
+ driverParam: string | number;
35
+ notNull: true;
36
+ hasDefault: false;
37
+ isPrimaryKey: false;
38
+ isAutoincrement: false;
39
+ hasRuntimeDefault: false;
40
+ enumValues: [string, ...string[]];
41
+ baseColumn: never;
42
+ identity: undefined;
43
+ generated: undefined;
44
+ }, {}, {}>;
45
+ payload: import("drizzle-orm/mysql-core").MySqlColumn<{
46
+ name: "payload";
47
+ tableName: "jobs";
48
+ dataType: "json";
49
+ columnType: "MySqlJson";
50
+ data: Record<string, unknown>;
51
+ driverParam: string;
52
+ notNull: true;
53
+ hasDefault: false;
54
+ isPrimaryKey: false;
55
+ isAutoincrement: false;
56
+ hasRuntimeDefault: false;
57
+ enumValues: undefined;
58
+ baseColumn: never;
59
+ identity: undefined;
60
+ generated: undefined;
61
+ }, {}, {
62
+ $type: Record<string, unknown>;
63
+ }>;
64
+ status: import("drizzle-orm/mysql-core").MySqlColumn<{
65
+ name: "status";
66
+ tableName: "jobs";
67
+ dataType: "string";
68
+ columnType: "MySqlVarChar";
69
+ data: "pending" | "processing" | "completed" | "failed";
70
+ driverParam: string | number;
71
+ notNull: true;
72
+ hasDefault: false;
73
+ isPrimaryKey: false;
74
+ isAutoincrement: false;
75
+ hasRuntimeDefault: false;
76
+ enumValues: [string, ...string[]];
77
+ baseColumn: never;
78
+ identity: undefined;
79
+ generated: undefined;
80
+ }, {}, {
81
+ $type: "pending" | "processing" | "completed" | "failed";
82
+ }>;
83
+ attempts: import("drizzle-orm/mysql-core").MySqlColumn<{
84
+ name: "attempts";
85
+ tableName: "jobs";
86
+ dataType: "number";
87
+ columnType: "MySqlInt";
88
+ data: number;
89
+ driverParam: string | number;
90
+ notNull: true;
91
+ hasDefault: true;
92
+ isPrimaryKey: false;
93
+ isAutoincrement: false;
94
+ hasRuntimeDefault: false;
95
+ enumValues: undefined;
96
+ baseColumn: never;
97
+ identity: undefined;
98
+ generated: undefined;
99
+ }, {}, {}>;
100
+ maxAttempts: import("drizzle-orm/mysql-core").MySqlColumn<{
101
+ name: "max_attempts";
102
+ tableName: "jobs";
103
+ dataType: "number";
104
+ columnType: "MySqlInt";
105
+ data: number;
106
+ driverParam: string | number;
107
+ notNull: true;
108
+ hasDefault: true;
109
+ isPrimaryKey: false;
110
+ isAutoincrement: false;
111
+ hasRuntimeDefault: false;
112
+ enumValues: undefined;
113
+ baseColumn: never;
114
+ identity: undefined;
115
+ generated: undefined;
116
+ }, {}, {}>;
117
+ uniqueKey: import("drizzle-orm/mysql-core").MySqlColumn<{
118
+ name: "unique_key";
119
+ tableName: "jobs";
120
+ dataType: "string";
121
+ columnType: "MySqlVarChar";
122
+ data: string;
123
+ driverParam: string | number;
124
+ notNull: false;
125
+ hasDefault: false;
126
+ isPrimaryKey: false;
127
+ isAutoincrement: false;
128
+ hasRuntimeDefault: false;
129
+ enumValues: [string, ...string[]];
130
+ baseColumn: never;
131
+ identity: undefined;
132
+ generated: undefined;
133
+ }, {}, {}>;
134
+ priority: import("drizzle-orm/mysql-core").MySqlColumn<{
135
+ name: "priority";
136
+ tableName: "jobs";
137
+ dataType: "number";
138
+ columnType: "MySqlInt";
139
+ data: number;
140
+ driverParam: string | number;
141
+ notNull: true;
142
+ hasDefault: true;
143
+ isPrimaryKey: false;
144
+ isAutoincrement: false;
145
+ hasRuntimeDefault: false;
146
+ enumValues: undefined;
147
+ baseColumn: never;
148
+ identity: undefined;
149
+ generated: undefined;
150
+ }, {}, {}>;
151
+ availableAt: import("drizzle-orm/mysql-core").MySqlColumn<{
152
+ name: "available_at";
153
+ tableName: "jobs";
154
+ dataType: "string";
155
+ columnType: "MySqlVarChar";
156
+ data: string;
157
+ driverParam: string | number;
158
+ notNull: true;
159
+ hasDefault: false;
160
+ isPrimaryKey: false;
161
+ isAutoincrement: false;
162
+ hasRuntimeDefault: false;
163
+ enumValues: [string, ...string[]];
164
+ baseColumn: never;
165
+ identity: undefined;
166
+ generated: undefined;
167
+ }, {}, {}>;
168
+ claimedAt: import("drizzle-orm/mysql-core").MySqlColumn<{
169
+ name: "claimed_at";
170
+ tableName: "jobs";
171
+ dataType: "string";
172
+ columnType: "MySqlVarChar";
173
+ data: string;
174
+ driverParam: string | number;
175
+ notNull: false;
176
+ hasDefault: false;
177
+ isPrimaryKey: false;
178
+ isAutoincrement: false;
179
+ hasRuntimeDefault: false;
180
+ enumValues: [string, ...string[]];
181
+ baseColumn: never;
182
+ identity: undefined;
183
+ generated: undefined;
184
+ }, {}, {}>;
185
+ claimedBy: import("drizzle-orm/mysql-core").MySqlColumn<{
186
+ name: "claimed_by";
187
+ tableName: "jobs";
188
+ dataType: "string";
189
+ columnType: "MySqlVarChar";
190
+ data: string;
191
+ driverParam: string | number;
192
+ notNull: false;
193
+ hasDefault: false;
194
+ isPrimaryKey: false;
195
+ isAutoincrement: false;
196
+ hasRuntimeDefault: false;
197
+ enumValues: [string, ...string[]];
198
+ baseColumn: never;
199
+ identity: undefined;
200
+ generated: undefined;
201
+ }, {}, {}>;
202
+ processedAt: import("drizzle-orm/mysql-core").MySqlColumn<{
203
+ name: "processed_at";
204
+ tableName: "jobs";
205
+ dataType: "string";
206
+ columnType: "MySqlVarChar";
207
+ data: string;
208
+ driverParam: string | number;
209
+ notNull: false;
210
+ hasDefault: false;
211
+ isPrimaryKey: false;
212
+ isAutoincrement: false;
213
+ hasRuntimeDefault: false;
214
+ enumValues: [string, ...string[]];
215
+ baseColumn: never;
216
+ identity: undefined;
217
+ generated: undefined;
218
+ }, {}, {}>;
219
+ lastError: import("drizzle-orm/mysql-core").MySqlColumn<{
220
+ name: "last_error";
221
+ tableName: "jobs";
222
+ dataType: "string";
223
+ columnType: "MySqlText";
224
+ data: string;
225
+ driverParam: string;
226
+ notNull: false;
227
+ hasDefault: false;
228
+ isPrimaryKey: false;
229
+ isAutoincrement: false;
230
+ hasRuntimeDefault: false;
231
+ enumValues: [string, ...string[]];
232
+ baseColumn: never;
233
+ identity: undefined;
234
+ generated: undefined;
235
+ }, {}, {}>;
236
+ createdAt: import("drizzle-orm/mysql-core").MySqlColumn<{
237
+ name: "created_at";
238
+ tableName: "jobs";
239
+ dataType: "string";
240
+ columnType: "MySqlVarChar";
241
+ data: string;
242
+ driverParam: string | number;
243
+ notNull: true;
244
+ hasDefault: false;
245
+ isPrimaryKey: false;
246
+ isAutoincrement: false;
247
+ hasRuntimeDefault: false;
248
+ enumValues: [string, ...string[]];
249
+ baseColumn: never;
250
+ identity: undefined;
251
+ generated: undefined;
252
+ }, {}, {}>;
253
+ };
254
+ dialect: "mysql";
255
+ }>;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.jobs = void 0;
4
+ const mysql_core_1 = require("drizzle-orm/mysql-core");
5
+ // MySQL-specific schema choices (documented so they are deliberate, not
6
+ // accidental divergence from the Postgres/SQLite definitions):
7
+ //
8
+ // - **`varchar` on every indexed column.** MySQL cannot index a `TEXT`/`BLOB`
9
+ // column without a prefix length, so `id`, `name`, `status`, `unique_key`,
10
+ // and `available_at` are `varchar(n)`. 191 is the classic utf8mb4-safe
11
+ // single-column index width; the composite `(name, unique_key)` index at
12
+ // 255 + 191 utf8mb4 chars stays well under InnoDB's 3072-byte key limit.
13
+ // The ISO-8601 timestamp columns fit comfortably in `varchar(32)`;
14
+ // free-form `last_error` stays `text`.
15
+ // - **The SAME full unique index on `(name, unique_key)`** as the other
16
+ // dialects. MySQL has no partial indexes, but none are needed: a UNIQUE
17
+ // index over a nullable column permits multiple `NULL`s (SQL treats `NULL`
18
+ // as distinct), and terminal transitions clear `unique_key` to `NULL` — so
19
+ // "unique among ACTIVE jobs" holds with identical semantics everywhere.
20
+ // - **`json` payload.** MySQL's native JSON type; mysql2 returns it already
21
+ // parsed, so the row shape matches `JobRow`.
22
+ /**
23
+ * MySQL `jobs` table. Add it to your Drizzle schema and generate a migration
24
+ * with drizzle-kit. Timestamps are stored as ISO-8601 `varchar` so the row
25
+ * shape is identical across dialects (ISO-8601 compares lexicographically,
26
+ * which the claimer's `available_at` range query relies on).
27
+ */
28
+ exports.jobs = (0, mysql_core_1.mysqlTable)('jobs', {
29
+ id: (0, mysql_core_1.varchar)('id', { length: 191 }).primaryKey(),
30
+ name: (0, mysql_core_1.varchar)('name', { length: 255 }).notNull(),
31
+ payload: (0, mysql_core_1.json)('payload').$type().notNull(),
32
+ status: (0, mysql_core_1.varchar)('status', { length: 32 }).$type().notNull(),
33
+ attempts: (0, mysql_core_1.int)('attempts').notNull().default(0),
34
+ maxAttempts: (0, mysql_core_1.int)('max_attempts').notNull().default(10),
35
+ uniqueKey: (0, mysql_core_1.varchar)('unique_key', { length: 191 }),
36
+ priority: (0, mysql_core_1.int)('priority').notNull().default(0),
37
+ availableAt: (0, mysql_core_1.varchar)('available_at', { length: 32 }).notNull(),
38
+ claimedAt: (0, mysql_core_1.varchar)('claimed_at', { length: 32 }),
39
+ claimedBy: (0, mysql_core_1.varchar)('claimed_by', { length: 191 }),
40
+ processedAt: (0, mysql_core_1.varchar)('processed_at', { length: 32 }),
41
+ lastError: (0, mysql_core_1.text)('last_error'),
42
+ createdAt: (0, mysql_core_1.varchar)('created_at', { length: 32 }).notNull(),
43
+ }, (table) => [
44
+ (0, mysql_core_1.uniqueIndex)('jobs_name_unique_key_unique').on(table.name, table.uniqueKey),
45
+ (0, mysql_core_1.index)('jobs_status_available_idx').on(table.status, table.availableAt),
46
+ ]);
47
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../../dialects/mysql/schema.ts"],"names":[],"mappings":";;;AAAA,uDAQgC;AAGhC,wEAAwE;AACxE,+DAA+D;AAC/D,EAAE;AACF,8EAA8E;AAC9E,6EAA6E;AAC7E,yEAAyE;AACzE,2EAA2E;AAC3E,2EAA2E;AAC3E,qEAAqE;AACrE,yCAAyC;AACzC,wEAAwE;AACxE,0EAA0E;AAC1E,6EAA6E;AAC7E,6EAA6E;AAC7E,0EAA0E;AAC1E,4EAA4E;AAC5E,+CAA+C;AAE/C;;;;;GAKG;AACU,QAAA,IAAI,GAAG,IAAA,uBAAU,EAC5B,MAAM,EACN;IACE,EAAE,EAAE,IAAA,oBAAO,EAAC,IAAI,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,UAAU,EAAE;IAC/C,IAAI,EAAE,IAAA,oBAAO,EAAC,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,OAAO,EAAE;IAChD,OAAO,EAAE,IAAA,iBAAI,EAAC,SAAS,CAAC,CAAC,KAAK,EAA2B,CAAC,OAAO,EAAE;IACnE,MAAM,EAAE,IAAA,oBAAO,EAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,KAAK,EAAa,CAAC,OAAO,EAAE;IACtE,QAAQ,EAAE,IAAA,gBAAG,EAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,WAAW,EAAE,IAAA,gBAAG,EAAC,cAAc,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACtD,SAAS,EAAE,IAAA,oBAAO,EAAC,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACjD,QAAQ,EAAE,IAAA,gBAAG,EAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,WAAW,EAAE,IAAA,oBAAO,EAAC,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;IAC9D,SAAS,EAAE,IAAA,oBAAO,EAAC,YAAY,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IAChD,SAAS,EAAE,IAAA,oBAAO,EAAC,YAAY,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACjD,WAAW,EAAE,IAAA,oBAAO,EAAC,cAAc,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC;IACpD,SAAS,EAAE,IAAA,iBAAI,EAAC,YAAY,CAAC;IAC7B,SAAS,EAAE,IAAA,oBAAO,EAAC,YAAY,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE;CAC3D,EACD,CAAC,KAAK,EAAE,EAAE,CAAC;IACT,IAAA,wBAAW,EAAC,6BAA6B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,SAAS,CAAC;IAC1E,IAAA,kBAAK,EAAC,2BAA2B,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,WAAW,CAAC;CACvE,CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export * from './schema';
2
+ export * from './job-store';