Skip to content

Commit 12712f0

Browse files
authored
feat(pg-pubsub): add option to immediately get a result on listen (#812)
1 parent 6e87476 commit 12712f0

2 files changed

Lines changed: 51 additions & 3 deletions

File tree

packages/pg-pubsub/__tests__/__snapshots__/subs.test.ts.snap

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1366,7 +1366,13 @@ type Query implements Node {
13661366
The root subscription type: contains realtime events you can subscribe to with the \`subscription\` operation.
13671367
"""
13681368
type Subscription {
1369-
listen(topic: String!): ListenPayload!
1369+
listen(
1370+
"""
1371+
If true, this subscription will trigger an event as soon as it initiates.
1372+
"""
1373+
initialEvent: Boolean! = false
1374+
topic: String!
1375+
): ListenPayload!
13701376
}
13711377
13721378
"""All input for the \`updateBarById\` mutation."""

packages/pg-pubsub/src/PgGenericSubscriptionPlugin.ts

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import debugFactory from "debug";
22
import { Plugin } from "graphile-build";
3-
import { GraphQLFieldConfig } from "graphql";
3+
import { GraphQLBoolean, GraphQLFieldConfig } from "graphql";
44
import { PubSub } from "graphql-subscriptions";
55

66
const debug = debugFactory("pg-pubsub");
@@ -12,6 +12,38 @@ function isPubSub(pubsub: any): pubsub is PubSub {
1212
return !!pubsub;
1313
}
1414

15+
const withInitialValue = <T>(
16+
initialVal: T,
17+
asyncIterator: AsyncIterator<T>
18+
): AsyncIterable<T> => {
19+
return {
20+
[Symbol.asyncIterator]: async function* (): AsyncIterator<T> {
21+
yield initialVal;
22+
23+
/* TODO: when we can upgrade to Node 10.3+ we can replace the below with simply:
24+
for await (const val of asyncIterator) {
25+
yield val;
26+
}
27+
*/
28+
try {
29+
while (true) {
30+
const next = await asyncIterator.next();
31+
if (next.done) {
32+
return next.value;
33+
} else {
34+
yield next.value;
35+
}
36+
}
37+
} finally {
38+
// Terminate the previous iterator
39+
if (typeof asyncIterator.return === "function") {
40+
asyncIterator.return();
41+
}
42+
}
43+
},
44+
};
45+
};
46+
1547
const PgGenericSubscriptionPlugin: Plugin = function (
1648
builder,
1749
{
@@ -142,6 +174,12 @@ const PgGenericSubscriptionPlugin: Plugin = function (
142174
topic: {
143175
type: new GraphQLNonNull(GraphQLString),
144176
},
177+
initialEvent: {
178+
defaultValue: false,
179+
type: new GraphQLNonNull(GraphQLBoolean),
180+
description:
181+
"If true, this subscription will trigger an event as soon as it initiates.",
182+
},
145183
},
146184
subscribe: async (_parent, args, _context, _resolveInfo) => {
147185
const { pgClient } = _context;
@@ -188,7 +226,11 @@ const PgGenericSubscriptionPlugin: Plugin = function (
188226
}
189227
});
190228
}
191-
return asyncIterator;
229+
if (args.initialEvent) {
230+
return withInitialValue(null, asyncIterator);
231+
} else {
232+
return asyncIterator;
233+
}
192234
},
193235
resolve: async (payload, _args, _context, _resolveInfo) => {
194236
const result = { ...payload };

0 commit comments

Comments
 (0)