Skip to content

Commit 096041b

Browse files
authored
feat: Add generic typing for queues (#174)
2 parents 796e12f + ae7c395 commit 096041b

File tree

3 files changed

+63
-76
lines changed

3 files changed

+63
-76
lines changed

src/api/queues/v0/queues.ts

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@
1313
// limitations under the License.
1414
import { QueueServiceClient } from '@nitric/api/proto/queue/v1/queue_grpc_pb';
1515
import {
16-
NitricTask,
16+
NitricTask as NitricTaskPb,
1717
QueueSendRequest,
1818
QueueSendBatchRequest,
1919
QueueReceiveRequest,
2020
QueueCompleteRequest,
2121
} from '@nitric/api/proto/queue/v1/queue_pb';
2222
import { SERVICE_BIND } from '../../../constants';
2323
import * as grpc from '@grpc/grpc-js';
24-
import type { Task } from '../../../types';
24+
import { NitricTask } from '../../../types';
2525
import { Struct } from 'google-protobuf/google/protobuf/struct_pb';
2626
import {
2727
fromGrpcError,
@@ -32,8 +32,8 @@ import {
3232
/**
3333
* A message that has failed to be enqueued
3434
*/
35-
interface FailedMessage {
36-
task: Task;
35+
interface FailedMessage<T> {
36+
task: NitricTask<T>;
3737
message: string;
3838
}
3939

@@ -44,8 +44,8 @@ interface FailedMessage {
4444
* @param task to convert
4545
* @returns the wire representation of the task
4646
*/
47-
function taskToWire(task: Task) {
48-
const wireTask = new NitricTask();
47+
function taskToWire(task: NitricTask) {
48+
const wireTask = new NitricTaskPb();
4949

5050
wireTask.setId(task.id);
5151
wireTask.setPayloadType(task.payloadType);
@@ -76,16 +76,16 @@ export class Queueing {
7676
this.QueueServiceClient = newQueueServiceClient();
7777
}
7878

79-
queue = (name: string): Queue => {
79+
queue = <T>(name: string): Queue<T> => {
8080
if (!name) {
8181
throw new InvalidArgumentError('A queue name is needed to use a Queue.');
8282
}
8383

84-
return new Queue(this, name);
84+
return new Queue<T>(this, name);
8585
};
8686
}
8787

88-
export class Queue {
88+
export class Queue<T extends Record<string, any> = Record<string, any>> {
8989
queueing: Queueing;
9090
name: string;
9191

@@ -120,17 +120,21 @@ export class Queue {
120120
* };
121121
* });
122122
*/
123-
public async send(tasks: Task[]): Promise<FailedMessage[]>;
124-
public async send(tasks: Task): Promise<void>;
125-
public async send(tasks: Task | Task[]): Promise<void | FailedMessage[]> {
123+
public async send(tasks: T[] | NitricTask<T>[]): Promise<FailedMessage<T>[]>;
124+
public async send(tasks: T | NitricTask<T>): Promise<void>;
125+
public async send(
126+
tasks: T[] | T | NitricTask<T> | NitricTask<T>[]
127+
): Promise<void | FailedMessage<T>[]> {
126128
return new Promise((resolve, reject) => {
127129
const request = new QueueSendBatchRequest();
128130

129-
request.setTasksList(
130-
Array.isArray(tasks)
131-
? tasks.map((task) => taskToWire(task))
132-
: [taskToWire(tasks)]
131+
// Convert to NitricTask if not specified
132+
const tasksArray = Array.isArray(tasks) ? tasks : [tasks];
133+
const nitricTasksArray = tasksArray.map((t) =>
134+
t instanceof NitricTask ? t : new NitricTask({ payload: t })
133135
);
136+
137+
request.setTasksList(nitricTasksArray.map(taskToWire));
134138
request.setQueue(this.name);
135139

136140
this.queueing.QueueServiceClient.sendBatch(request, (error, response) => {
@@ -139,11 +143,11 @@ export class Queue {
139143
return;
140144
}
141145
const failedTasks = response.getFailedtasksList().map((m) => ({
142-
task: {
146+
task: new NitricTask<T>({
143147
id: m.getTask().getId(),
144-
payload: m.getTask().getPayload().toJavaScript(),
145148
payloadType: m.getTask().getPayloadType(),
146-
},
149+
payload: m.getTask().getPayload().toJavaScript() as T,
150+
}),
147151
message: m.getMessage(),
148152
}));
149153
if (!Array.isArray(tasks)) {
@@ -181,7 +185,7 @@ export class Queue {
181185
* // do something with task
182186
* ```
183187
*/
184-
public async receive(depth?: number): Promise<ReceivedTask[]> {
188+
public async receive(depth?: number): Promise<ReceivedTask<T>[]> {
185189
return new Promise((resolve, reject) => {
186190
const request = new QueueReceiveRequest();
187191

@@ -201,7 +205,7 @@ export class Queue {
201205
response.getTasksList().map((m) => {
202206
return new ReceivedTask({
203207
id: m.getId(),
204-
payload: m.getPayload().toJavaScript(),
208+
payload: m.getPayload().toJavaScript() as T,
205209
payloadType: m.getPayloadType(),
206210
leaseId: m.getLeaseId(),
207211
queue: this,
@@ -214,11 +218,10 @@ export class Queue {
214218
}
215219
}
216220

217-
export class ReceivedTask implements Task {
218-
id: string;
221+
export class ReceivedTask<
222+
T extends Record<string, any> = Record<string, any>
223+
> extends NitricTask<T> {
219224
leaseId: string;
220-
payloadType?: string;
221-
payload?: Record<string, any>;
222225
queue: Queue;
223226

224227
constructor({
@@ -227,11 +230,15 @@ export class ReceivedTask implements Task {
227230
payload,
228231
payloadType,
229232
queue,
230-
}: Task & { id: string; leaseId: string; queue: Queue }) {
231-
this.id = id;
233+
}: {
234+
id: string;
235+
payload: T;
236+
payloadType: string;
237+
leaseId: string;
238+
queue: Queue;
239+
}) {
240+
super({ id, payloadType, payload });
232241
this.leaseId = leaseId;
233-
this.payloadType = payloadType;
234-
this.payload = payload;
235242
this.queue = queue;
236243
}
237244

src/resources/queue.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ export type QueuePermission = 'sending' | 'receiving';
2929
/**
3030
* Queue resource for async send/receive messaging
3131
*/
32-
export class QueueResource extends SecureResource<QueuePermission> {
32+
export class QueueResource<
33+
T extends Record<string, any> = Record<string, any>
34+
> extends SecureResource<QueuePermission> {
3335
/**
3436
* Register this queue as a required resource for the calling function/container.
3537
*
@@ -91,11 +93,15 @@ export class QueueResource extends SecureResource<QueuePermission> {
9193
* @param perms the access that the currently scoped function is requesting to this resource.
9294
* @returns a useable queue.
9395
*/
94-
public for(...perms: QueuePermission[]): Queue {
96+
public for(...perms: QueuePermission[]): Queue<T> {
9597
this.registerPolicy(...perms);
9698

9799
return queues().queue(this.name);
98100
}
99101
}
100102

101-
export const queue = make(QueueResource);
103+
export const queue = make(QueueResource) as <
104+
T extends Record<string, any> = Record<string, any>
105+
>(
106+
name: string
107+
) => QueueResource<T>;

src/types.ts

Lines changed: 18 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,6 @@
1111
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
14-
// export interface NitricEvent<
15-
// T extends Record<string, any> = Record<string, any>
16-
// > {
17-
// /**
18-
// * Uniquely identifies the event.
19-
// *
20-
// * Within your app you must ensure the ID is unique.
21-
// * Subscribers can assume events with the same ID are duplicates and avoid reprocessing them
22-
// */
23-
// id?: string;
24-
// /**
25-
// * An optional description of the event type.
26-
// *
27-
// * Can be useful for de-serialization, routing or observability. The format of this value is determined by the producer.
28-
// */
29-
// payloadType?: string;
30-
// /**
31-
// * The event's payload data, with details of the event.
32-
// */
33-
// payload: T;
34-
// }
3514

3615
export class NitricEvent<T extends Record<string, any> = Record<string, any>> {
3716
public readonly payload: T;
@@ -45,29 +24,24 @@ export class NitricEvent<T extends Record<string, any> = Record<string, any>> {
4524
}
4625
}
4726

48-
export interface Task<T extends Record<string, any> = Record<string, any>> {
49-
/**
50-
* Uniquely identifies the task.
51-
*
52-
* Within your app you must ensure the ID is unique.
53-
*/
54-
id?: string;
55-
/**
56-
* The ID for the current lease of this task.
57-
*
58-
* A task may be leased multiple times, resulting in new lease IDs.
59-
*/
60-
leaseId?: string;
61-
/**
62-
* An optional description of the task type.
63-
*
64-
* Can be useful for de-serialization, routing or observability. The format of this value is determined by the producer.
65-
*/
66-
payloadType?: string;
67-
/**
68-
* The task's payload data, with details of the task or work to be done.
69-
*/
70-
payload?: Record<string, any>;
27+
export class NitricTask<T extends Record<string, any> = Record<string, any>> {
28+
public readonly id: string | undefined;
29+
public readonly payloadType: string;
30+
public readonly payload: T;
31+
32+
constructor({
33+
id = undefined,
34+
payload,
35+
payloadType = 'none',
36+
}: {
37+
id?: string;
38+
payloadType?: string;
39+
payload: T;
40+
}) {
41+
this.id = id;
42+
this.payload = payload;
43+
this.payloadType = payloadType;
44+
}
7145
}
7246

7347
export type WhereQueryOperator =

0 commit comments

Comments
 (0)