Skip to content

Commit b765ed3

Browse files
committed
add kysely adapter
1 parent 7b75263 commit b765ed3

17 files changed

+1880
-11
lines changed

packages/adapter-kysely/README.md

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# @vorsteh-queue/adapter-drizzle
2+
3+
Drizzle ORM adapter for Vorsteh Queue supporting PostgreSQL databases.
4+
5+
## Features
6+
7+
- **PostgreSQL Support**: Full PostgreSQL compatibility with PGlite, node-postgres, and postgres.js
8+
- **Type Safety**: Full TypeScript support with Drizzle ORM
9+
- **SKIP LOCKED**: Concurrent job processing without lock contention
10+
- **JSON Payloads**: Complex data structures with proper serialization
11+
- **UTC-First**: All timestamps stored as UTC for reliable timezone handling
12+
13+
## Requirements
14+
15+
- **Node.js 20+**
16+
- **PostgreSQL 12+** (for SKIP LOCKED support)
17+
- **ESM only** - This package is ESM-only and cannot be imported with `require()`
18+
19+
## Installation
20+
21+
```bash
22+
npm install @vorsteh-queue/adapter-drizzle drizzle-orm
23+
# or
24+
pnpm add @vorsteh-queue/adapter-drizzle drizzle-orm
25+
```
26+
27+
> **Note**: Make sure your project has `"type": "module"` in package.json or use `.mjs` file extensions.
28+
29+
## Usage
30+
31+
```typescript
32+
import { drizzle } from "drizzle-orm/node-postgres"
33+
import { Pool } from "pg"
34+
35+
import { PostgresQueueAdapter } from "@vorsteh-queue/adapter-drizzle"
36+
import { Queue } from "@vorsteh-queue/core"
37+
38+
// Setup PostgreSQL connection
39+
const pool = new Pool({
40+
connectionString: "postgresql://user:password@localhost:5432/database",
41+
})
42+
const db = drizzle(pool)
43+
44+
interface EmailPayload {
45+
to: string
46+
subject: string
47+
body: string
48+
}
49+
50+
interface EmailResult {
51+
messageId: string
52+
sent: boolean
53+
}
54+
55+
// Create adapter and queue
56+
const adapter = new PostgresQueueAdapter(db)
57+
const queue = new Queue(adapter, { name: "my-queue" })
58+
59+
// Register job handlers
60+
queue.register<EmailPayload, EmailResult>("send-email", async (job) => {
61+
console.log(`Sending email to ${job.payload.to}`)
62+
63+
// Send email logic here
64+
await sendEmail(job.payload)
65+
66+
return {
67+
messageId: "msg_123",
68+
sent: true,
69+
}
70+
})
71+
72+
// Add jobs
73+
await queue.add("send-email", {
74+
75+
subject: "Welcome!",
76+
body: "Welcome to our service!",
77+
})
78+
79+
// Start processing
80+
queue.start()
81+
```
82+
83+
## Schema Setup
84+
85+
### Using Drizzle Schemas (Recommended)
86+
87+
```typescript
88+
import { drizzle } from "drizzle-orm/node-postgres"
89+
90+
import { postgresSchema } from "@vorsteh-queue/adapter-drizzle"
91+
92+
const db = drizzle(pool, { schema: postgresSchema })
93+
```
94+
95+
### Using Drizzle Kit Migrations
96+
97+
```typescript
98+
// src/schema/index.ts - Your application schema
99+
import { pgTable, serial, varchar } from "drizzle-orm/pg-core"
100+
101+
import { postgresSchema } from "@vorsteh-queue/adapter-drizzle"
102+
103+
// Your existing tables
104+
export const users = pgTable("users", {
105+
id: serial("id").primaryKey(),
106+
name: varchar("name", { length: 255 }),
107+
})
108+
109+
// Export queue schema alongside your schema
110+
export const queueJobs = postgresSchema.queueJobs
111+
```
112+
113+
```bash
114+
# Generate and run migrations
115+
npx drizzle-kit generate
116+
npx drizzle-kit migrate
117+
```
118+
119+
## Supported PostgreSQL Drivers
120+
121+
- **node-postgres** (`pg`)
122+
- **postgres.js** (`postgres`)
123+
- **PGlite** (for embedded/testing)
124+
125+
## Testing
126+
127+
```bash
128+
pnpm test
129+
```
130+
131+
## License
132+
133+
MIT License - see LICENSE file for details.
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import baseConfig from "@vorsteh-queue/eslint-config/base"
2+
3+
export default [...baseConfig]
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
{
2+
"name": "@vorsteh-queue/adapter-kysely",
3+
"version": "0.0.0",
4+
"description": "Kysely adapter for Vorsteh Queue with PostgreSQL support",
5+
"keywords": [
6+
"queue",
7+
"job-queue",
8+
"drizzle",
9+
"drizzle-orm",
10+
"postgresql",
11+
"postgres",
12+
"database",
13+
"adapter",
14+
"typescript",
15+
"background-jobs",
16+
"task-queue",
17+
"worker",
18+
"pg",
19+
"pglite",
20+
"postgres-js",
21+
"node-postgres",
22+
"sql",
23+
"orm"
24+
],
25+
"homepage": "https://vorsteh-queue.dev",
26+
"bugs": "https://github.com/noxify/vorsteh-queue/issues",
27+
"repository": {
28+
"type": "git",
29+
"url": "https://github.com/noxify/vorsteh-queue",
30+
"directory": "packages/adapter-kysely"
31+
},
32+
"license": "MIT",
33+
"type": "module",
34+
"exports": {
35+
".": {
36+
"types": "./dist/index.d.ts",
37+
"default": "./dist/index.js"
38+
},
39+
"./postgres-adapter": {
40+
"types": "./dist/postgres-adapter.d.ts",
41+
"default": "./dist/postgres-adapter.js"
42+
},
43+
"./postgres-schema": {
44+
"types": "./dist/postgres-schema.d.ts",
45+
"default": "./dist/postgres-schema.js"
46+
}
47+
},
48+
"main": "./dist/index.js",
49+
"types": "./dist/index.d.ts",
50+
"files": [
51+
"dist"
52+
],
53+
"scripts": {
54+
"build": "rolldown -c rolldown.config.ts && tsc -p tsconfig.build.json",
55+
"clean": "git clean -xdf .cache .turbo dist node_modules",
56+
"clean:cache": "git clean -xdf .cache",
57+
"db:generate": "drizzle-kit generate",
58+
"dev": "rolldown -c rolldown.config.ts --watch & tsc -p tsconfig.build.json --watch",
59+
"format": "prettier --check . --ignore-path ../../.gitignore --ignore-path ../../.prettierignore",
60+
"lint": "eslint .",
61+
"test": "vitest",
62+
"test:watch": "vitest --watch",
63+
"typecheck": "tsc --noEmit"
64+
},
65+
"prettier": "@vorsteh-queue/prettier-config",
66+
"dependencies": {
67+
"@vorsteh-queue/core": "workspace:*"
68+
},
69+
"devDependencies": {
70+
"@electric-sql/pglite": "^0.3.6",
71+
"@vorsteh-queue/eslint-config": "workspace:*",
72+
"@vorsteh-queue/prettier-config": "workspace:*",
73+
"@vorsteh-queue/tsconfig": "workspace:*",
74+
"eslint": "^9.32.0",
75+
"kysely": "^0.28.3",
76+
"kysely-pglite-dialect": "^1.1.1",
77+
"kysely-postgres-js": "^2.0.0",
78+
"postgres": "^3.4.7",
79+
"prettier": "^3.6.2",
80+
"rolldown": "1.0.0-beta.30",
81+
"rollup-plugin-delete": "^3.0.1",
82+
"typescript": "^5.8.3",
83+
"vitest": "^3.2.4"
84+
},
85+
"peerDependencies": {
86+
"kysely": ">=0.28.0"
87+
},
88+
"peerDependenciesMeta": {
89+
"@types/pg": {
90+
"optional": true
91+
},
92+
"pg": {
93+
"optional": true
94+
},
95+
"postgres": {
96+
"optional": true
97+
}
98+
}
99+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { defineConfig } from "rolldown"
2+
import del from "rollup-plugin-delete"
3+
4+
export default defineConfig({
5+
input: {
6+
index: "src/index.ts",
7+
"postgres-adapter": "src/postgres-adapter.ts",
8+
"postgres-schema": "src/postgres-schema.ts",
9+
},
10+
output: {
11+
dir: "dist",
12+
format: "esm",
13+
entryFileNames: "[name].js",
14+
},
15+
plugins: [del({ targets: "dist/*" })],
16+
external: [
17+
"@vorsteh-queue/core",
18+
"drizzle-orm",
19+
"drizzle-orm/mysql2",
20+
"drizzle-orm/node-postgres",
21+
"drizzle-orm/pglite",
22+
"drizzle-orm/postgres-js",
23+
],
24+
})
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// PostgreSQL adapter
2+
export { PostgresQueueAdapter } from "./postgres-adapter"
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import { sql } from "kysely"
2+
3+
/**
4+
* @param {import('kysely').Kysely<unknown} db
5+
*/
6+
export async function up(db) {
7+
await db.schema
8+
.createTable("queue_jobs")
9+
.addColumn("id", "uuid", (col) => col.defaultTo(sql`gen_random_uuid()`).notNull())
10+
.addColumn("queue_name", "varchar(255)", (col) => col.notNull())
11+
.addColumn("name", "varchar(255)", (col) => col.notNull())
12+
.addColumn("payload", "jsonb", (col) => col.notNull())
13+
.addColumn("status", "varchar(50)", (col) => col.notNull())
14+
.addColumn("priority", "int4", (col) => col.notNull())
15+
.addColumn("attempts", "int4", (col) => col.defaultTo(0).notNull())
16+
.addColumn("max_attempts", "int4", (col) => col.notNull())
17+
.addColumn("cron", "varchar(255)")
18+
.addColumn("created_at", "timestamptz", (col) =>
19+
col.defaultTo(sql`timezone('utc'::text, now())`).notNull(),
20+
)
21+
.addColumn("process_at", "timestamptz", (col) => col.notNull())
22+
.addColumn("processed_at", "timestamptz")
23+
.addColumn("completed_at", "timestamptz")
24+
.addColumn("failed_at", "timestamptz")
25+
.addColumn("error", "jsonb")
26+
.addColumn("result", "jsonb")
27+
.addColumn("progress", "int4")
28+
.addColumn("repeat_every", "int4")
29+
.addColumn("repeat_limit", "int4")
30+
.addColumn("repeat_count", "int4")
31+
.execute()
32+
33+
await db.schema
34+
.createIndex("idx_queue_jobs_status_priority")
35+
.on("queue_jobs")
36+
37+
.columns(["queue_name", "status", "priority", "created_at"])
38+
.execute()
39+
40+
await db.schema
41+
.createIndex("idx_queue_jobs_process_at")
42+
.on("queue_jobs")
43+
44+
.column("process_at")
45+
.execute()
46+
}
47+
48+
/**
49+
* @param {import('kysely').Kysely<unknown} db
50+
*/
51+
export async function down(db) {
52+
await db.schema.dropTable("queue_jobs").execute()
53+
}

0 commit comments

Comments
 (0)