prisma-pgmq 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Prisma PGMQ Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,402 @@
1
+ # Prisma PGMQ
2
+
3
+ A TypeScript library that provides type-safe methods for PostgreSQL Message Queue (PGMQ) operations in your Prisma-based applications.
4
+
5
+ ## Features
6
+
7
+ - 🔒 **Type-safe**: Full TypeScript support with proper type definitions
8
+ - 📦 **Easy to use**: Simple API with functional methods
9
+ - 🔌 **Prisma Integration**: Seamless integration with your existing Prisma setup
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install prisma-pgmq
15
+ # or
16
+ pnpm add prisma-pgmq
17
+ # or
18
+ yarn add prisma-pgmq
19
+ ```
20
+
21
+ ### Prerequisites
22
+
23
+ - PostgreSQL database with the PGMQ extension installed
24
+ - Prisma Client v5.0.0 or higher
25
+ - Node.js 16+
26
+
27
+ ## Quick Start
28
+
29
+ ### Functional API
30
+
31
+ ```typescript
32
+ import { PrismaClient } from '@prisma/client';
33
+ import { pgmq } from 'prisma-pgmq';
34
+
35
+ const prisma = new PrismaClient();
36
+
37
+ // Create a queue
38
+ await prisma.$transaction(async (tx) => {
39
+ await pgmq.createQueue(tx, 'my-work-queue');
40
+ });
41
+
42
+ // Send a message
43
+ await prisma.$transaction(async (tx) => {
44
+ const msgId = await pgmq.send(tx, 'my-work-queue', {
45
+ userId: 123,
46
+ action: 'send-email',
47
+ email: 'user@example.com'
48
+ });
49
+ console.log('Message sent with ID:', msgId);
50
+ });
51
+ ```
52
+
53
+ ## API Reference
54
+
55
+ ### Message Operations
56
+
57
+ #### `send(queueName, message, delay?)`
58
+ Send a single message to a queue.
59
+
60
+ ```typescript
61
+ // Send immediately
62
+ const msgId = await prisma.$pgmq.send('my-queue', { data: 'hello' });
63
+
64
+ // Send with delay (seconds)
65
+ const msgId = await prisma.$pgmq.send('my-queue', { data: 'hello' }, 30);
66
+
67
+ // Send with specific time
68
+ const msgId = await prisma.$pgmq.send('my-queue', { data: 'hello' }, new Date('2024-01-01T10:00:00Z'));
69
+ ```
70
+
71
+ #### `sendBatch(queueName, messages, delay?)`
72
+ Send multiple messages to a queue in a single operation.
73
+
74
+ ```typescript
75
+ const msgIds = await prisma.$pgmq.sendBatch('my-queue', [
76
+ { id: 1, data: 'message 1' },
77
+ { id: 2, data: 'message 2' },
78
+ { id: 3, data: 'message 3' }
79
+ ]);
80
+ ```
81
+
82
+ #### `read(queueName, vt, qty?, conditional?)`
83
+ Read messages from a queue with visibility timeout.
84
+
85
+ ```typescript
86
+ // Read up to 5 messages with 30 second visibility timeout
87
+ const messages = await prisma.$pgmq.read('my-queue', 30, 5);
88
+
89
+ // Read with conditional filtering
90
+ const messages = await prisma.$pgmq.read('my-queue', 30, 5, { priority: 'high' });
91
+ ```
92
+
93
+ #### `readWithPoll(queueName, vt, qty?, maxPollSeconds?, pollIntervalMs?, conditional?)`
94
+ Read messages with polling (wait for messages if none available).
95
+
96
+ ```typescript
97
+ // Poll for up to 10 seconds, checking every 500ms
98
+ const messages = await prisma.$pgmq.readWithPoll('my-queue', 30, 1, 10, 500);
99
+ ```
100
+
101
+ #### `pop(queueName)`
102
+ Read and immediately delete a message (atomic operation).
103
+
104
+ ```typescript
105
+ const messages = await prisma.$pgmq.pop('my-queue');
106
+ ```
107
+
108
+ ### Message Management
109
+
110
+ #### `deleteMessage(queueName, msgId)`
111
+ Delete a specific message.
112
+
113
+ ```typescript
114
+ const deleted = await prisma.$pgmq.deleteMessage('my-queue', 123);
115
+ ```
116
+
117
+ #### `deleteBatch(queueName, msgIds)`
118
+ Delete multiple messages.
119
+
120
+ ```typescript
121
+ const deletedIds = await prisma.$pgmq.deleteBatch('my-queue', [123, 124, 125]);
122
+ ```
123
+
124
+ #### `archive(queueName, msgId)`
125
+ Archive a message (move to archive table).
126
+
127
+ ```typescript
128
+ const archived = await prisma.$pgmq.archive('my-queue', 123);
129
+ ```
130
+
131
+ #### `archiveBatch(queueName, msgIds)`
132
+ Archive multiple messages.
133
+
134
+ ```typescript
135
+ const archivedIds = await prisma.$pgmq.archiveBatch('my-queue', [123, 124, 125]);
136
+ ```
137
+
138
+ ### Queue Management
139
+
140
+ #### `createQueue(queueName)`
141
+ Create a new queue.
142
+
143
+ ```typescript
144
+ await prisma.$pgmq.createQueue('my-new-queue');
145
+ ```
146
+
147
+ #### `createPartitionedQueue(queueName, partitionInterval?, retentionInterval?)`
148
+ Create a partitioned queue for high-throughput scenarios.
149
+
150
+ ```typescript
151
+ await prisma.$pgmq.createPartitionedQueue('high-volume-queue', '10000', '100000');
152
+ ```
153
+
154
+ #### `createUnloggedQueue(queueName)`
155
+ Create an unlogged queue (better performance, less durability).
156
+
157
+ ```typescript
158
+ await prisma.$pgmq.createUnloggedQueue('temp-queue');
159
+ ```
160
+
161
+ #### `dropQueue(queueName)`
162
+ Delete a queue and all its messages.
163
+
164
+ ```typescript
165
+ const dropped = await prisma.$pgmq.dropQueue('old-queue');
166
+ ```
167
+
168
+ #### `purgeQueue(queueName)`
169
+ Remove all messages from a queue.
170
+
171
+ ```typescript
172
+ const messageCount = await prisma.$pgmq.purgeQueue('my-queue');
173
+ ```
174
+
175
+ ### Utilities
176
+
177
+ #### `setVt(queueName, msgId, vtOffset)`
178
+ Set visibility timeout for a specific message.
179
+
180
+ ```typescript
181
+ const message = await prisma.$pgmq.setVt('my-queue', 123, 60); // 60 seconds
182
+ ```
183
+
184
+ #### `listQueues()`
185
+ Get information about all queues.
186
+
187
+ ```typescript
188
+ const queues = await prisma.$pgmq.listQueues();
189
+ console.log(queues); // [{ queue_name: 'my-queue', created_at: ..., is_partitioned: false }]
190
+ ```
191
+
192
+ #### `metrics(queueName)`
193
+ Get metrics for a specific queue.
194
+
195
+ ```typescript
196
+ const metrics = await prisma.$pgmq.metrics('my-queue');
197
+ console.log(metrics);
198
+ // {
199
+ // queue_name: 'my-queue',
200
+ // queue_length: 5n,
201
+ // newest_msg_age_sec: 10,
202
+ // oldest_msg_age_sec: 300,
203
+ // total_messages: 1000n,
204
+ // scrape_time: 2024-01-01T10:00:00.000Z
205
+ // }
206
+ ```
207
+
208
+ #### `metricsAll()`
209
+ Get metrics for all queues.
210
+
211
+ ```typescript
212
+ const allMetrics = await prisma.$pgmq.metricsAll();
213
+ ```
214
+
215
+ ## Type Definitions
216
+
217
+ ### `Task`
218
+ ```typescript
219
+ type Task = Record<string, unknown>;
220
+ ```
221
+
222
+ ### `MessageRecord`
223
+ ```typescript
224
+ interface MessageRecord {
225
+ msg_id: number;
226
+ read_ct: number;
227
+ enqueued_at: Date;
228
+ vt: Date;
229
+ message: Task;
230
+ }
231
+ ```
232
+
233
+ ### `QueueMetrics`
234
+ ```typescript
235
+ interface QueueMetrics {
236
+ queue_name: string;
237
+ queue_length: number;
238
+ newest_msg_age_sec: number | null;
239
+ oldest_msg_age_sec: number | null;
240
+ total_messages: number;
241
+ scrape_time: Date;
242
+ }
243
+ ```
244
+
245
+ ### `QueueInfo`
246
+ ```typescript
247
+ interface QueueInfo {
248
+ queue_name: string;
249
+ created_at: Date;
250
+ is_partitioned: boolean;
251
+ is_unlogged: boolean;
252
+ }
253
+ ```
254
+
255
+ ## Best Practices
256
+
257
+ ### 1. Use Appropriate Visibility Timeouts
258
+ Choose visibility timeouts based on your message processing time:
259
+
260
+ ```typescript
261
+ // For quick operations (30 seconds)
262
+ const messages = await prisma.$pgmq.read('quick-tasks', 30);
263
+
264
+ // For longer operations (5 minutes)
265
+ const messages = await prisma.$pgmq.read('heavy-tasks', 300);
266
+ ```
267
+
268
+ ### 2. Handle Message Processing Failures
269
+ Always delete or archive messages after successful processing:
270
+
271
+ ```typescript
272
+ const messages = await prisma.$pgmq.read('my-queue', 30, 10);
273
+
274
+ for (const message of messages) {
275
+ try {
276
+ await processMessage(message.message);
277
+ await prisma.$pgmq.deleteMessage('my-queue', message.msg_id);
278
+ } catch (error) {
279
+ // Handle error - message will become visible again after timeout
280
+ console.error('Failed to process message:', error);
281
+ // Optionally archive failed messages
282
+ await prisma.$pgmq.archive('my-queue', message.msg_id);
283
+ }
284
+ }
285
+ ```
286
+
287
+ ## Examples
288
+
289
+ ### Basic Worker Pattern
290
+
291
+ ```typescript
292
+ import { PrismaClient } from '@prisma/client';
293
+ import { pgmq } from 'prisma-pgmq';
294
+
295
+ const prisma = new PrismaClient();
296
+
297
+ // Producer
298
+ async function sendTask(taskData: any) {
299
+ await prisma.$transaction(async (tx) => {
300
+ await pgmq.send(tx, 'work-queue', {
301
+ type: 'process-user-data',
302
+ data: taskData,
303
+ timestamp: Date.now()
304
+ });
305
+ });
306
+ }
307
+
308
+ // Consumer
309
+ async function processMessages() {
310
+ while (true) {
311
+ await prisma.$transaction(async (tx) => {
312
+ const messages = await pgmq.readWithPoll(tx, 'work-queue', 30, 5, 10, 1000);
313
+ for (const message of messages) {
314
+ try {
315
+ // Process the message
316
+ await handleTask(message.message);
317
+ // Delete on success
318
+ await pgmq.deleteMessage(tx, 'work-queue', message.msg_id);
319
+ } catch (error) {
320
+ console.error('Task failed:', error);
321
+ // Archive failed messages for later analysis
322
+ await pgmq.archive(tx, 'work-queue', message.msg_id);
323
+ }
324
+ }
325
+ });
326
+ }
327
+ }
328
+
329
+ async function handleTask(task: any) {
330
+ // Your business logic here
331
+ console.log('Processing task:', task.type);
332
+ }
333
+ ```
334
+
335
+ ### Delayed Message Scheduling
336
+
337
+ ```typescript
338
+ // Schedule a message for later processing
339
+ const futureDate = new Date(Date.now() + 24 * 60 * 60 * 1000); // 24 hours
340
+
341
+ await prisma.$pgmq.send('scheduled-tasks', {
342
+ type: 'send-reminder',
343
+ userId: 123,
344
+ reminder: 'Your subscription expires tomorrow'
345
+ }, futureDate);
346
+ ```
347
+
348
+ ### Priority Queue Pattern
349
+
350
+ ```typescript
351
+ // Send high-priority message
352
+ await prisma.$pgmq.send('tasks', {
353
+ priority: 'high',
354
+ type: 'urgent-processing',
355
+ data: urgentData
356
+ });
357
+
358
+ // Read high-priority messages first
359
+ const highPriorityMessages = await prisma.$pgmq.read('tasks', 30, 10, { priority: 'high' });
360
+
361
+ if (highPriorityMessages.length === 0) {
362
+ // Fall back to normal priority
363
+ const normalMessages = await prisma.$pgmq.read('tasks', 30, 10, { priority: 'normal' });
364
+ }
365
+ ```
366
+
367
+ ## Contributing
368
+
369
+ 1. Fork the repository
370
+ 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
371
+ 3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
372
+ 4. Push to the branch (`git push origin feature/amazing-feature`)
373
+ 5. Open a Pull Request
374
+
375
+ ### Development Setup
376
+
377
+ ```bash
378
+ # Clone the repository
379
+ git clone https://github.com/your-username/prisma-pgmq.git
380
+ cd prisma-pgmq
381
+
382
+ # Install dependencies
383
+ pnpm install
384
+
385
+ # Run tests
386
+ pnpm test
387
+
388
+ # Build the library
389
+ pnpm build
390
+
391
+ # Watch for changes during development
392
+ pnpm dev
393
+ ```
394
+
395
+ ## License
396
+
397
+ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
398
+
399
+ ## Acknowledgments
400
+
401
+ - [PGMQ](https://github.com/pgmq/pgmq) - PostgreSQL Message Queue extension
402
+ - [Prisma](https://www.prisma.io/) - Next-generation ORM for TypeScript & Node.js
@@ -0,0 +1,72 @@
1
+ import { Prisma } from '@prisma/client/extension';
2
+
3
+ type Task = Record<string, unknown>;
4
+ interface MessageRecord {
5
+ msg_id: number;
6
+ read_ct: number;
7
+ enqueued_at: Date;
8
+ vt: Date;
9
+ message: Task;
10
+ }
11
+ interface QueueMetrics {
12
+ queue_name: string;
13
+ queue_length: number;
14
+ newest_msg_age_sec: number | null;
15
+ oldest_msg_age_sec: number | null;
16
+ total_messages: number;
17
+ scrape_time: Date;
18
+ }
19
+ interface QueueInfo {
20
+ queue_name: string;
21
+ created_at: Date;
22
+ is_partitioned: boolean;
23
+ is_unlogged: boolean;
24
+ }
25
+ declare function send(tx: Prisma.TransactionClient, queueName: string, msg: Task, delay?: number | Date): Promise<number>;
26
+ declare function sendBatch(tx: Prisma.TransactionClient, queueName: string, msgs: Task[], delay?: number | Date): Promise<number[]>;
27
+ declare function read(tx: Prisma.TransactionClient, queueName: string, vt: number, qty?: number, conditional?: Task): Promise<MessageRecord[]>;
28
+ declare function readWithPoll(tx: Prisma.TransactionClient, queueName: string, vt: number, qty?: number, maxPollSeconds?: number, pollIntervalMs?: number, conditional?: Task): Promise<MessageRecord[]>;
29
+ declare function pop(tx: Prisma.TransactionClient, queueName: string): Promise<MessageRecord[]>;
30
+ declare function deleteMessage(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean>;
31
+ declare function deleteBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]>;
32
+ declare function purgeQueue(tx: Prisma.TransactionClient, queueName: string): Promise<number>;
33
+ declare function archive(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean>;
34
+ declare function archiveBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]>;
35
+ declare function createQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void>;
36
+ declare function createPartitionedQueue(tx: Prisma.TransactionClient, queueName: string, partitionInterval?: string, retentionInterval?: string): Promise<void>;
37
+ declare function createUnloggedQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void>;
38
+ declare function detachArchive(tx: Prisma.TransactionClient, queueName: string): Promise<void>;
39
+ declare function dropQueue(tx: Prisma.TransactionClient, queueName: string): Promise<boolean>;
40
+ declare function setVt(tx: Prisma.TransactionClient, queueName: string, msgId: number, vtOffset: number): Promise<MessageRecord>;
41
+ declare function listQueues(tx: Prisma.TransactionClient): Promise<QueueInfo[]>;
42
+ declare function metrics(tx: Prisma.TransactionClient, queueName: string): Promise<QueueMetrics>;
43
+ declare function metricsAll(tx: Prisma.TransactionClient): Promise<QueueMetrics[]>;
44
+
45
+ type pgmq_MessageRecord = MessageRecord;
46
+ type pgmq_QueueInfo = QueueInfo;
47
+ type pgmq_QueueMetrics = QueueMetrics;
48
+ type pgmq_Task = Task;
49
+ declare const pgmq_archive: typeof archive;
50
+ declare const pgmq_archiveBatch: typeof archiveBatch;
51
+ declare const pgmq_createPartitionedQueue: typeof createPartitionedQueue;
52
+ declare const pgmq_createQueue: typeof createQueue;
53
+ declare const pgmq_createUnloggedQueue: typeof createUnloggedQueue;
54
+ declare const pgmq_deleteBatch: typeof deleteBatch;
55
+ declare const pgmq_deleteMessage: typeof deleteMessage;
56
+ declare const pgmq_detachArchive: typeof detachArchive;
57
+ declare const pgmq_dropQueue: typeof dropQueue;
58
+ declare const pgmq_listQueues: typeof listQueues;
59
+ declare const pgmq_metrics: typeof metrics;
60
+ declare const pgmq_metricsAll: typeof metricsAll;
61
+ declare const pgmq_pop: typeof pop;
62
+ declare const pgmq_purgeQueue: typeof purgeQueue;
63
+ declare const pgmq_read: typeof read;
64
+ declare const pgmq_readWithPoll: typeof readWithPoll;
65
+ declare const pgmq_send: typeof send;
66
+ declare const pgmq_sendBatch: typeof sendBatch;
67
+ declare const pgmq_setVt: typeof setVt;
68
+ declare namespace pgmq {
69
+ export { type pgmq_MessageRecord as MessageRecord, type pgmq_QueueInfo as QueueInfo, type pgmq_QueueMetrics as QueueMetrics, type pgmq_Task as Task, pgmq_archive as archive, pgmq_archiveBatch as archiveBatch, pgmq_createPartitionedQueue as createPartitionedQueue, pgmq_createQueue as createQueue, pgmq_createUnloggedQueue as createUnloggedQueue, pgmq_deleteBatch as deleteBatch, pgmq_deleteMessage as deleteMessage, pgmq_detachArchive as detachArchive, pgmq_dropQueue as dropQueue, pgmq_listQueues as listQueues, pgmq_metrics as metrics, pgmq_metricsAll as metricsAll, pgmq_pop as pop, pgmq_purgeQueue as purgeQueue, pgmq_read as read, pgmq_readWithPoll as readWithPoll, pgmq_send as send, pgmq_sendBatch as sendBatch, pgmq_setVt as setVt };
70
+ }
71
+
72
+ export { type MessageRecord, type QueueInfo, type QueueMetrics, type Task, pgmq };
@@ -0,0 +1,72 @@
1
+ import { Prisma } from '@prisma/client/extension';
2
+
3
+ type Task = Record<string, unknown>;
4
+ interface MessageRecord {
5
+ msg_id: number;
6
+ read_ct: number;
7
+ enqueued_at: Date;
8
+ vt: Date;
9
+ message: Task;
10
+ }
11
+ interface QueueMetrics {
12
+ queue_name: string;
13
+ queue_length: number;
14
+ newest_msg_age_sec: number | null;
15
+ oldest_msg_age_sec: number | null;
16
+ total_messages: number;
17
+ scrape_time: Date;
18
+ }
19
+ interface QueueInfo {
20
+ queue_name: string;
21
+ created_at: Date;
22
+ is_partitioned: boolean;
23
+ is_unlogged: boolean;
24
+ }
25
+ declare function send(tx: Prisma.TransactionClient, queueName: string, msg: Task, delay?: number | Date): Promise<number>;
26
+ declare function sendBatch(tx: Prisma.TransactionClient, queueName: string, msgs: Task[], delay?: number | Date): Promise<number[]>;
27
+ declare function read(tx: Prisma.TransactionClient, queueName: string, vt: number, qty?: number, conditional?: Task): Promise<MessageRecord[]>;
28
+ declare function readWithPoll(tx: Prisma.TransactionClient, queueName: string, vt: number, qty?: number, maxPollSeconds?: number, pollIntervalMs?: number, conditional?: Task): Promise<MessageRecord[]>;
29
+ declare function pop(tx: Prisma.TransactionClient, queueName: string): Promise<MessageRecord[]>;
30
+ declare function deleteMessage(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean>;
31
+ declare function deleteBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]>;
32
+ declare function purgeQueue(tx: Prisma.TransactionClient, queueName: string): Promise<number>;
33
+ declare function archive(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean>;
34
+ declare function archiveBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]>;
35
+ declare function createQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void>;
36
+ declare function createPartitionedQueue(tx: Prisma.TransactionClient, queueName: string, partitionInterval?: string, retentionInterval?: string): Promise<void>;
37
+ declare function createUnloggedQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void>;
38
+ declare function detachArchive(tx: Prisma.TransactionClient, queueName: string): Promise<void>;
39
+ declare function dropQueue(tx: Prisma.TransactionClient, queueName: string): Promise<boolean>;
40
+ declare function setVt(tx: Prisma.TransactionClient, queueName: string, msgId: number, vtOffset: number): Promise<MessageRecord>;
41
+ declare function listQueues(tx: Prisma.TransactionClient): Promise<QueueInfo[]>;
42
+ declare function metrics(tx: Prisma.TransactionClient, queueName: string): Promise<QueueMetrics>;
43
+ declare function metricsAll(tx: Prisma.TransactionClient): Promise<QueueMetrics[]>;
44
+
45
+ type pgmq_MessageRecord = MessageRecord;
46
+ type pgmq_QueueInfo = QueueInfo;
47
+ type pgmq_QueueMetrics = QueueMetrics;
48
+ type pgmq_Task = Task;
49
+ declare const pgmq_archive: typeof archive;
50
+ declare const pgmq_archiveBatch: typeof archiveBatch;
51
+ declare const pgmq_createPartitionedQueue: typeof createPartitionedQueue;
52
+ declare const pgmq_createQueue: typeof createQueue;
53
+ declare const pgmq_createUnloggedQueue: typeof createUnloggedQueue;
54
+ declare const pgmq_deleteBatch: typeof deleteBatch;
55
+ declare const pgmq_deleteMessage: typeof deleteMessage;
56
+ declare const pgmq_detachArchive: typeof detachArchive;
57
+ declare const pgmq_dropQueue: typeof dropQueue;
58
+ declare const pgmq_listQueues: typeof listQueues;
59
+ declare const pgmq_metrics: typeof metrics;
60
+ declare const pgmq_metricsAll: typeof metricsAll;
61
+ declare const pgmq_pop: typeof pop;
62
+ declare const pgmq_purgeQueue: typeof purgeQueue;
63
+ declare const pgmq_read: typeof read;
64
+ declare const pgmq_readWithPoll: typeof readWithPoll;
65
+ declare const pgmq_send: typeof send;
66
+ declare const pgmq_sendBatch: typeof sendBatch;
67
+ declare const pgmq_setVt: typeof setVt;
68
+ declare namespace pgmq {
69
+ export { type pgmq_MessageRecord as MessageRecord, type pgmq_QueueInfo as QueueInfo, type pgmq_QueueMetrics as QueueMetrics, type pgmq_Task as Task, pgmq_archive as archive, pgmq_archiveBatch as archiveBatch, pgmq_createPartitionedQueue as createPartitionedQueue, pgmq_createQueue as createQueue, pgmq_createUnloggedQueue as createUnloggedQueue, pgmq_deleteBatch as deleteBatch, pgmq_deleteMessage as deleteMessage, pgmq_detachArchive as detachArchive, pgmq_dropQueue as dropQueue, pgmq_listQueues as listQueues, pgmq_metrics as metrics, pgmq_metricsAll as metricsAll, pgmq_pop as pop, pgmq_purgeQueue as purgeQueue, pgmq_read as read, pgmq_readWithPoll as readWithPoll, pgmq_send as send, pgmq_sendBatch as sendBatch, pgmq_setVt as setVt };
70
+ }
71
+
72
+ export { type MessageRecord, type QueueInfo, type QueueMetrics, type Task, pgmq };
package/dist/index.js ADDED
@@ -0,0 +1,157 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ pgmq: () => pgmq_exports
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/pgmq.ts
28
+ var pgmq_exports = {};
29
+ __export(pgmq_exports, {
30
+ archive: () => archive,
31
+ archiveBatch: () => archiveBatch,
32
+ createPartitionedQueue: () => createPartitionedQueue,
33
+ createQueue: () => createQueue,
34
+ createUnloggedQueue: () => createUnloggedQueue,
35
+ deleteBatch: () => deleteBatch,
36
+ deleteMessage: () => deleteMessage,
37
+ detachArchive: () => detachArchive,
38
+ dropQueue: () => dropQueue,
39
+ listQueues: () => listQueues,
40
+ metrics: () => metrics,
41
+ metricsAll: () => metricsAll,
42
+ pop: () => pop,
43
+ purgeQueue: () => purgeQueue,
44
+ read: () => read,
45
+ readWithPoll: () => readWithPoll,
46
+ send: () => send,
47
+ sendBatch: () => sendBatch,
48
+ setVt: () => setVt
49
+ });
50
+ var import_extension = require("@prisma/client/extension");
51
+ var PrismaAny = import_extension.Prisma;
52
+ async function send(tx, queueName, msg, delay) {
53
+ const delayRepr = typeof delay === "number" ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;
54
+ const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;
55
+ const result = await tx.$queryRaw`SELECT pgmq.send(${queueName}, ${msg}${delaySql})`;
56
+ const firstResult = result[0];
57
+ if (!firstResult) {
58
+ throw new Error("No result returned from pgmq.send");
59
+ }
60
+ return firstResult.send;
61
+ }
62
+ async function sendBatch(tx, queueName, msgs, delay) {
63
+ const delayRepr = typeof delay === "number" ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;
64
+ const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;
65
+ const result = await tx.$queryRaw`SELECT pgmq.send_batch(${queueName}, ${msgs}${delaySql})`;
66
+ return result.map((a) => a.send_batch);
67
+ }
68
+ function read(tx, queueName, vt, qty = 1, conditional = {}) {
69
+ return tx.$queryRaw`SELECT * FROM pgmq.read(${queueName}, ${vt}::integer, ${qty}::integer, ${conditional})`;
70
+ }
71
+ function readWithPoll(tx, queueName, vt, qty = 1, maxPollSeconds = 5, pollIntervalMs = 100, conditional = {}) {
72
+ return tx.$queryRaw`SELECT * FROM pgmq.read_with_poll(${queueName}, ${vt}::integer, ${qty}::integer, ${maxPollSeconds}::integer, ${pollIntervalMs}::integer, ${conditional})`;
73
+ }
74
+ function pop(tx, queueName) {
75
+ return tx.$queryRaw`SELECT * FROM pgmq.pop(${queueName})`;
76
+ }
77
+ async function deleteMessage(tx, queueName, msgId) {
78
+ const result = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgId}::integer)`;
79
+ const firstResult = result[0];
80
+ if (!firstResult) {
81
+ throw new Error("No result returned from pgmq.delete");
82
+ }
83
+ return firstResult.delete;
84
+ }
85
+ async function deleteBatch(tx, queueName, msgIds) {
86
+ const result = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgIds}::integer[])`;
87
+ return result.map((a) => a.delete);
88
+ }
89
+ async function purgeQueue(tx, queueName) {
90
+ const result = await tx.$queryRaw`SELECT pgmq.purge_queue(${queueName})`;
91
+ const firstResult = result[0];
92
+ if (!firstResult) {
93
+ throw new Error("No result returned from pgmq.purge_queue");
94
+ }
95
+ return firstResult.purge_queue;
96
+ }
97
+ async function archive(tx, queueName, msgId) {
98
+ const result = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgId}::integer)`;
99
+ const firstResult = result[0];
100
+ if (!firstResult) {
101
+ throw new Error("No result returned from pgmq.archive");
102
+ }
103
+ return firstResult.archive;
104
+ }
105
+ async function archiveBatch(tx, queueName, msgIds) {
106
+ const result = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgIds}::integer[])`;
107
+ return result.map((a) => a.archive);
108
+ }
109
+ async function createQueue(tx, queueName) {
110
+ await tx.$executeRaw`SELECT pgmq.create(${queueName})`;
111
+ }
112
+ async function createPartitionedQueue(tx, queueName, partitionInterval = "10000", retentionInterval = "100000") {
113
+ await tx.$executeRaw`SELECT pgmq.create_partitioned(${queueName}, ${partitionInterval}, ${retentionInterval})`;
114
+ }
115
+ async function createUnloggedQueue(tx, queueName) {
116
+ await tx.$executeRaw`SELECT pgmq.create_unlogged(${queueName})`;
117
+ }
118
+ async function detachArchive(tx, queueName) {
119
+ await tx.$executeRaw`SELECT pgmq.detach_archive(${queueName})`;
120
+ }
121
+ async function dropQueue(tx, queueName) {
122
+ const result = await tx.$queryRaw`SELECT pgmq.drop_queue(${queueName})`;
123
+ const firstResult = result[0];
124
+ if (!firstResult) {
125
+ throw new Error("No result returned from pgmq.drop_queue");
126
+ }
127
+ return firstResult.drop_queue;
128
+ }
129
+ async function setVt(tx, queueName, msgId, vtOffset) {
130
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.set_vt(${queueName}, ${msgId}::integer, ${vtOffset}::integer)`;
131
+ const firstResult = result[0];
132
+ if (!firstResult) {
133
+ throw new Error("No result returned from pgmq.set_vt");
134
+ }
135
+ return firstResult;
136
+ }
137
+ async function listQueues(tx) {
138
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.list_queues()`;
139
+ return result;
140
+ }
141
+ async function metrics(tx, queueName) {
142
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.metrics(${queueName})`;
143
+ const firstResult = result[0];
144
+ if (!firstResult) {
145
+ throw new Error("No result returned from pgmq.metrics");
146
+ }
147
+ return firstResult;
148
+ }
149
+ async function metricsAll(tx) {
150
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.metrics_all()`;
151
+ return result;
152
+ }
153
+ // Annotate the CommonJS export names for ESM import in node:
154
+ 0 && (module.exports = {
155
+ pgmq
156
+ });
157
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/pgmq.ts"],"sourcesContent":["export { \n Task,\n MessageRecord,\n QueueInfo,\n QueueMetrics,\n } from './pgmq';\n \nexport * as pgmq from './pgmq';","import { Prisma } from '@prisma/client/extension';\n\nexport type Task = Record<string, unknown>;\n\n// Message record type based on PGMQ documentation\nexport interface MessageRecord {\n msg_id: number;\n read_ct: number;\n enqueued_at: Date;\n vt: Date;\n message: Task;\n}\n\n// Queue metrics type\nexport interface QueueMetrics {\n queue_name: string;\n queue_length: number;\n newest_msg_age_sec: number | null;\n oldest_msg_age_sec: number | null;\n total_messages: number;\n scrape_time: Date;\n}\n\n// Queue info type\nexport interface QueueInfo {\n queue_name: string;\n created_at: Date;\n is_partitioned: boolean;\n is_unlogged: boolean;\n}\n\n// I expect that Prisma has `sql` defined\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst PrismaAny = Prisma as any;\n\nexport async function send(tx: Prisma.TransactionClient, queueName: string, msg: Task, delay?: number | Date): Promise<number> {\n const delayRepr = typeof delay === 'number' ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;\n const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;\n const result: { send: number }[] = await tx.$queryRaw`SELECT pgmq.send(${queueName}, ${msg}${delaySql})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.send');\n }\n return firstResult.send;\n}\n\nexport async function sendBatch(tx: Prisma.TransactionClient, queueName: string, msgs: Task[], delay?: number | Date): Promise<number[]> {\n const delayRepr = typeof delay === 'number' ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;\n const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;\n const result: { send_batch: number }[] = await tx.$queryRaw`SELECT pgmq.send_batch(${queueName}, ${msgs}${delaySql})`;\n return result.map(a => a.send_batch);\n}\n\n// Reading Messages\n\nexport function read(\n tx: Prisma.TransactionClient, \n queueName: string, \n vt: number, \n qty: number = 1, \n conditional: Task = {}\n): Promise<MessageRecord[]> {\n return tx.$queryRaw`SELECT * FROM pgmq.read(${queueName}, ${vt}::integer, ${qty}::integer, ${conditional})` as Promise<MessageRecord[]>;\n}\n\nexport function readWithPoll(\n tx: Prisma.TransactionClient,\n queueName: string,\n vt: number,\n qty: number = 1,\n maxPollSeconds: number = 5,\n pollIntervalMs: number = 100,\n conditional: Task = {}\n): Promise<MessageRecord[]> {\n return tx.$queryRaw`SELECT * FROM pgmq.read_with_poll(${queueName}, ${vt}::integer, ${qty}::integer, ${maxPollSeconds}::integer, ${pollIntervalMs}::integer, ${conditional})` as Promise<MessageRecord[]>;\n}\n\nexport function pop(tx: Prisma.TransactionClient, queueName: string): Promise<MessageRecord[]> {\n return tx.$queryRaw`SELECT * FROM pgmq.pop(${queueName})` as Promise<MessageRecord[]>;\n}\n\n// Deleting/Archiving Messages\n\nexport async function deleteMessage(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean> {\n const result: { delete: boolean }[] = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgId}::integer)`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.delete');\n }\n return firstResult.delete;\n}\n\nexport async function deleteBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]> {\n const result: { delete: number }[] = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgIds}::integer[])`;\n return result.map(a => a.delete);\n}\n\nexport async function purgeQueue(tx: Prisma.TransactionClient, queueName: string): Promise<number> {\n const result: { purge_queue: number }[] = await tx.$queryRaw`SELECT pgmq.purge_queue(${queueName})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.purge_queue');\n }\n return firstResult.purge_queue;\n}\n\nexport async function archive(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean> {\n const result: { archive: boolean }[] = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgId}::integer)`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.archive');\n }\n return firstResult.archive;\n}\n\nexport async function archiveBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]> {\n const result: { archive: number }[] = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgIds}::integer[])`;\n return result.map(a => a.archive);\n}\n\n// Queue Management\n\nexport async function createQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.create(${queueName})`;\n}\n\nexport async function createPartitionedQueue(\n tx: Prisma.TransactionClient, \n queueName: string, \n partitionInterval: string = '10000', \n retentionInterval: string = '100000'\n): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.create_partitioned(${queueName}, ${partitionInterval}, ${retentionInterval})`;\n}\n\nexport async function createUnloggedQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.create_unlogged(${queueName})`;\n}\n\nexport async function detachArchive(tx: Prisma.TransactionClient, queueName: string): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.detach_archive(${queueName})`;\n}\n\nexport async function dropQueue(tx: Prisma.TransactionClient, queueName: string): Promise<boolean> {\n const result: { drop_queue: boolean }[] = await tx.$queryRaw`SELECT pgmq.drop_queue(${queueName})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.drop_queue');\n }\n return firstResult.drop_queue;\n}\n\n// Utilities\n\nexport async function setVt(\n tx: Prisma.TransactionClient, \n queueName: string, \n msgId: number, \n vtOffset: number\n): Promise<MessageRecord> {\n const result: MessageRecord[] = await tx.$queryRaw`SELECT * FROM pgmq.set_vt(${queueName}, ${msgId}::integer, ${vtOffset}::integer)`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.set_vt');\n }\n return firstResult;\n}\n\nexport async function listQueues(tx: Prisma.TransactionClient): Promise<QueueInfo[]> {\n const result: QueueInfo[] = await tx.$queryRaw`SELECT * FROM pgmq.list_queues()`;\n return result;\n}\n\nexport async function metrics(tx: Prisma.TransactionClient, queueName: string): Promise<QueueMetrics> {\n const result: QueueMetrics[] = await tx.$queryRaw`SELECT * FROM pgmq.metrics(${queueName})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.metrics');\n }\n return firstResult;\n}\n\nexport async function metricsAll(tx: Prisma.TransactionClient): Promise<QueueMetrics[]> {\n const result: QueueMetrics[] = await tx.$queryRaw`SELECT * FROM pgmq.metrics_all()`;\n return result;\n}"],"mappings":"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","names":[]}
package/dist/index.mjs ADDED
@@ -0,0 +1,136 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/pgmq.ts
8
+ var pgmq_exports = {};
9
+ __export(pgmq_exports, {
10
+ archive: () => archive,
11
+ archiveBatch: () => archiveBatch,
12
+ createPartitionedQueue: () => createPartitionedQueue,
13
+ createQueue: () => createQueue,
14
+ createUnloggedQueue: () => createUnloggedQueue,
15
+ deleteBatch: () => deleteBatch,
16
+ deleteMessage: () => deleteMessage,
17
+ detachArchive: () => detachArchive,
18
+ dropQueue: () => dropQueue,
19
+ listQueues: () => listQueues,
20
+ metrics: () => metrics,
21
+ metricsAll: () => metricsAll,
22
+ pop: () => pop,
23
+ purgeQueue: () => purgeQueue,
24
+ read: () => read,
25
+ readWithPoll: () => readWithPoll,
26
+ send: () => send,
27
+ sendBatch: () => sendBatch,
28
+ setVt: () => setVt
29
+ });
30
+ import { Prisma } from "@prisma/client/extension";
31
+ var PrismaAny = Prisma;
32
+ async function send(tx, queueName, msg, delay) {
33
+ const delayRepr = typeof delay === "number" ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;
34
+ const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;
35
+ const result = await tx.$queryRaw`SELECT pgmq.send(${queueName}, ${msg}${delaySql})`;
36
+ const firstResult = result[0];
37
+ if (!firstResult) {
38
+ throw new Error("No result returned from pgmq.send");
39
+ }
40
+ return firstResult.send;
41
+ }
42
+ async function sendBatch(tx, queueName, msgs, delay) {
43
+ const delayRepr = typeof delay === "number" ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;
44
+ const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;
45
+ const result = await tx.$queryRaw`SELECT pgmq.send_batch(${queueName}, ${msgs}${delaySql})`;
46
+ return result.map((a) => a.send_batch);
47
+ }
48
+ function read(tx, queueName, vt, qty = 1, conditional = {}) {
49
+ return tx.$queryRaw`SELECT * FROM pgmq.read(${queueName}, ${vt}::integer, ${qty}::integer, ${conditional})`;
50
+ }
51
+ function readWithPoll(tx, queueName, vt, qty = 1, maxPollSeconds = 5, pollIntervalMs = 100, conditional = {}) {
52
+ return tx.$queryRaw`SELECT * FROM pgmq.read_with_poll(${queueName}, ${vt}::integer, ${qty}::integer, ${maxPollSeconds}::integer, ${pollIntervalMs}::integer, ${conditional})`;
53
+ }
54
+ function pop(tx, queueName) {
55
+ return tx.$queryRaw`SELECT * FROM pgmq.pop(${queueName})`;
56
+ }
57
+ async function deleteMessage(tx, queueName, msgId) {
58
+ const result = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgId}::integer)`;
59
+ const firstResult = result[0];
60
+ if (!firstResult) {
61
+ throw new Error("No result returned from pgmq.delete");
62
+ }
63
+ return firstResult.delete;
64
+ }
65
+ async function deleteBatch(tx, queueName, msgIds) {
66
+ const result = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgIds}::integer[])`;
67
+ return result.map((a) => a.delete);
68
+ }
69
+ async function purgeQueue(tx, queueName) {
70
+ const result = await tx.$queryRaw`SELECT pgmq.purge_queue(${queueName})`;
71
+ const firstResult = result[0];
72
+ if (!firstResult) {
73
+ throw new Error("No result returned from pgmq.purge_queue");
74
+ }
75
+ return firstResult.purge_queue;
76
+ }
77
+ async function archive(tx, queueName, msgId) {
78
+ const result = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgId}::integer)`;
79
+ const firstResult = result[0];
80
+ if (!firstResult) {
81
+ throw new Error("No result returned from pgmq.archive");
82
+ }
83
+ return firstResult.archive;
84
+ }
85
+ async function archiveBatch(tx, queueName, msgIds) {
86
+ const result = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgIds}::integer[])`;
87
+ return result.map((a) => a.archive);
88
+ }
89
+ async function createQueue(tx, queueName) {
90
+ await tx.$executeRaw`SELECT pgmq.create(${queueName})`;
91
+ }
92
+ async function createPartitionedQueue(tx, queueName, partitionInterval = "10000", retentionInterval = "100000") {
93
+ await tx.$executeRaw`SELECT pgmq.create_partitioned(${queueName}, ${partitionInterval}, ${retentionInterval})`;
94
+ }
95
+ async function createUnloggedQueue(tx, queueName) {
96
+ await tx.$executeRaw`SELECT pgmq.create_unlogged(${queueName})`;
97
+ }
98
+ async function detachArchive(tx, queueName) {
99
+ await tx.$executeRaw`SELECT pgmq.detach_archive(${queueName})`;
100
+ }
101
+ async function dropQueue(tx, queueName) {
102
+ const result = await tx.$queryRaw`SELECT pgmq.drop_queue(${queueName})`;
103
+ const firstResult = result[0];
104
+ if (!firstResult) {
105
+ throw new Error("No result returned from pgmq.drop_queue");
106
+ }
107
+ return firstResult.drop_queue;
108
+ }
109
+ async function setVt(tx, queueName, msgId, vtOffset) {
110
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.set_vt(${queueName}, ${msgId}::integer, ${vtOffset}::integer)`;
111
+ const firstResult = result[0];
112
+ if (!firstResult) {
113
+ throw new Error("No result returned from pgmq.set_vt");
114
+ }
115
+ return firstResult;
116
+ }
117
+ async function listQueues(tx) {
118
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.list_queues()`;
119
+ return result;
120
+ }
121
+ async function metrics(tx, queueName) {
122
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.metrics(${queueName})`;
123
+ const firstResult = result[0];
124
+ if (!firstResult) {
125
+ throw new Error("No result returned from pgmq.metrics");
126
+ }
127
+ return firstResult;
128
+ }
129
+ async function metricsAll(tx) {
130
+ const result = await tx.$queryRaw`SELECT * FROM pgmq.metrics_all()`;
131
+ return result;
132
+ }
133
+ export {
134
+ pgmq_exports as pgmq
135
+ };
136
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/pgmq.ts"],"sourcesContent":["import { Prisma } from '@prisma/client/extension';\n\nexport type Task = Record<string, unknown>;\n\n// Message record type based on PGMQ documentation\nexport interface MessageRecord {\n msg_id: number;\n read_ct: number;\n enqueued_at: Date;\n vt: Date;\n message: Task;\n}\n\n// Queue metrics type\nexport interface QueueMetrics {\n queue_name: string;\n queue_length: number;\n newest_msg_age_sec: number | null;\n oldest_msg_age_sec: number | null;\n total_messages: number;\n scrape_time: Date;\n}\n\n// Queue info type\nexport interface QueueInfo {\n queue_name: string;\n created_at: Date;\n is_partitioned: boolean;\n is_unlogged: boolean;\n}\n\n// I expect that Prisma has `sql` defined\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst PrismaAny = Prisma as any;\n\nexport async function send(tx: Prisma.TransactionClient, queueName: string, msg: Task, delay?: number | Date): Promise<number> {\n const delayRepr = typeof delay === 'number' ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;\n const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;\n const result: { send: number }[] = await tx.$queryRaw`SELECT pgmq.send(${queueName}, ${msg}${delaySql})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.send');\n }\n return firstResult.send;\n}\n\nexport async function sendBatch(tx: Prisma.TransactionClient, queueName: string, msgs: Task[], delay?: number | Date): Promise<number[]> {\n const delayRepr = typeof delay === 'number' ? PrismaAny.sql`${delay}::integer` : PrismaAny.sql`${delay}`;\n const delaySql = delay ? PrismaAny.sql`, ${delayRepr}` : PrismaAny.sql``;\n const result: { send_batch: number }[] = await tx.$queryRaw`SELECT pgmq.send_batch(${queueName}, ${msgs}${delaySql})`;\n return result.map(a => a.send_batch);\n}\n\n// Reading Messages\n\nexport function read(\n tx: Prisma.TransactionClient, \n queueName: string, \n vt: number, \n qty: number = 1, \n conditional: Task = {}\n): Promise<MessageRecord[]> {\n return tx.$queryRaw`SELECT * FROM pgmq.read(${queueName}, ${vt}::integer, ${qty}::integer, ${conditional})` as Promise<MessageRecord[]>;\n}\n\nexport function readWithPoll(\n tx: Prisma.TransactionClient,\n queueName: string,\n vt: number,\n qty: number = 1,\n maxPollSeconds: number = 5,\n pollIntervalMs: number = 100,\n conditional: Task = {}\n): Promise<MessageRecord[]> {\n return tx.$queryRaw`SELECT * FROM pgmq.read_with_poll(${queueName}, ${vt}::integer, ${qty}::integer, ${maxPollSeconds}::integer, ${pollIntervalMs}::integer, ${conditional})` as Promise<MessageRecord[]>;\n}\n\nexport function pop(tx: Prisma.TransactionClient, queueName: string): Promise<MessageRecord[]> {\n return tx.$queryRaw`SELECT * FROM pgmq.pop(${queueName})` as Promise<MessageRecord[]>;\n}\n\n// Deleting/Archiving Messages\n\nexport async function deleteMessage(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean> {\n const result: { delete: boolean }[] = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgId}::integer)`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.delete');\n }\n return firstResult.delete;\n}\n\nexport async function deleteBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]> {\n const result: { delete: number }[] = await tx.$queryRaw`SELECT pgmq.delete(${queueName}, ${msgIds}::integer[])`;\n return result.map(a => a.delete);\n}\n\nexport async function purgeQueue(tx: Prisma.TransactionClient, queueName: string): Promise<number> {\n const result: { purge_queue: number }[] = await tx.$queryRaw`SELECT pgmq.purge_queue(${queueName})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.purge_queue');\n }\n return firstResult.purge_queue;\n}\n\nexport async function archive(tx: Prisma.TransactionClient, queueName: string, msgId: number): Promise<boolean> {\n const result: { archive: boolean }[] = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgId}::integer)`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.archive');\n }\n return firstResult.archive;\n}\n\nexport async function archiveBatch(tx: Prisma.TransactionClient, queueName: string, msgIds: number[]): Promise<number[]> {\n const result: { archive: number }[] = await tx.$queryRaw`SELECT pgmq.archive(${queueName}, ${msgIds}::integer[])`;\n return result.map(a => a.archive);\n}\n\n// Queue Management\n\nexport async function createQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.create(${queueName})`;\n}\n\nexport async function createPartitionedQueue(\n tx: Prisma.TransactionClient, \n queueName: string, \n partitionInterval: string = '10000', \n retentionInterval: string = '100000'\n): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.create_partitioned(${queueName}, ${partitionInterval}, ${retentionInterval})`;\n}\n\nexport async function createUnloggedQueue(tx: Prisma.TransactionClient, queueName: string): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.create_unlogged(${queueName})`;\n}\n\nexport async function detachArchive(tx: Prisma.TransactionClient, queueName: string): Promise<void> {\n await tx.$executeRaw`SELECT pgmq.detach_archive(${queueName})`;\n}\n\nexport async function dropQueue(tx: Prisma.TransactionClient, queueName: string): Promise<boolean> {\n const result: { drop_queue: boolean }[] = await tx.$queryRaw`SELECT pgmq.drop_queue(${queueName})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.drop_queue');\n }\n return firstResult.drop_queue;\n}\n\n// Utilities\n\nexport async function setVt(\n tx: Prisma.TransactionClient, \n queueName: string, \n msgId: number, \n vtOffset: number\n): Promise<MessageRecord> {\n const result: MessageRecord[] = await tx.$queryRaw`SELECT * FROM pgmq.set_vt(${queueName}, ${msgId}::integer, ${vtOffset}::integer)`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.set_vt');\n }\n return firstResult;\n}\n\nexport async function listQueues(tx: Prisma.TransactionClient): Promise<QueueInfo[]> {\n const result: QueueInfo[] = await tx.$queryRaw`SELECT * FROM pgmq.list_queues()`;\n return result;\n}\n\nexport async function metrics(tx: Prisma.TransactionClient, queueName: string): Promise<QueueMetrics> {\n const result: QueueMetrics[] = await tx.$queryRaw`SELECT * FROM pgmq.metrics(${queueName})`;\n const firstResult = result[0];\n if (!firstResult) {\n throw new Error('No result returned from pgmq.metrics');\n }\n return firstResult;\n}\n\nexport async function metricsAll(tx: Prisma.TransactionClient): Promise<QueueMetrics[]> {\n const result: QueueMetrics[] = await tx.$queryRaw`SELECT * FROM pgmq.metrics_all()`;\n return result;\n}"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "prisma-pgmq",
3
+ "version": "0.1.0",
4
+ "description": "A Prisma PGMQ implementation providing type-safe message queue operations",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "files": [
9
+ "dist",
10
+ "README.md",
11
+ "LICENSE"
12
+ ],
13
+ "keywords": [
14
+ "prisma",
15
+ "postgresql",
16
+ "message-queue",
17
+ "pgmq",
18
+ "queue",
19
+ "background-jobs",
20
+ "database",
21
+ "typescript"
22
+ ],
23
+ "author": "Dan Volkov <volkv.dan@gmail.com>",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/dvlkv/prisma-pgmq.git"
28
+ },
29
+ "bugs": {
30
+ "url": "https://github.com/dvlkv/prisma-pgmq/issues"
31
+ },
32
+ "homepage": "https://github.com/dvlkv/prisma-pgmq#readme",
33
+ "peerDependencies": {
34
+ "@prisma/client": ">=5.0.0"
35
+ },
36
+ "devDependencies": {
37
+ "@eslint/js": "^9.29.0",
38
+ "@prisma/client": "^5.0.0",
39
+ "@types/node": "^24.0.4",
40
+ "@typescript-eslint/eslint-plugin": "^8.35.0",
41
+ "@typescript-eslint/parser": "^8.35.0",
42
+ "eslint": "^9.29.0",
43
+ "prisma": "^5.0.0",
44
+ "rimraf": "^6.0.1",
45
+ "tsup": "^8.5.0",
46
+ "typescript": "^5.8.3",
47
+ "typescript-eslint": "^8.35.0"
48
+ },
49
+ "engines": {
50
+ "node": ">=16.0.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsup",
54
+ "build:watch": "tsup --watch",
55
+ "lint": "eslint --ext .ts,.tsx",
56
+ "lint:fix": "eslint --ext .ts,.tsx --fix",
57
+ "typecheck": "tsc --noEmit",
58
+ "dev": "pnpm build:watch",
59
+ "clean": "rimraf dist"
60
+ }
61
+ }