Skip to content

Commit 9cbceb5

Browse files
committed
Allow omitting the recipient list when creating a notification to pull a dynamic list from DB defined in strategy
1 parent 60215db commit 9cbceb5

File tree

5 files changed

+33
-14
lines changed

5 files changed

+33
-14
lines changed

src/components/notification-system/system-notification.resolver.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
ObjectType,
77
Resolver,
88
} from '@nestjs/graphql';
9-
import { ID, LoggedInSession, Session, UnauthorizedException } from '~/common';
9+
import { LoggedInSession, Session, UnauthorizedException } from '~/common';
1010
import { MarkdownScalar } from '~/common/markdown.scalar';
1111
import { isAdmin } from '~/common/session';
1212
import { NotificationService } from '../notifications';
@@ -34,13 +34,7 @@ export class SystemNotificationResolver {
3434
throw new UnauthorizedException();
3535
}
3636

37-
// @ts-expect-error this is just for testing
38-
const allUsers = await this.notifications.repo.db
39-
.query<{ id: ID }>('match (u:User) return u.id as id')
40-
.map('id')
41-
.run();
42-
43-
return await this.notifications.create(SystemNotification, allUsers, {
37+
return await this.notifications.create(SystemNotification, null, {
4438
message,
4539
});
4640
}
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
1+
import { node, Query } from 'cypher-query-builder';
12
import { INotificationStrategy, NotificationStrategy } from '../notifications';
23
import { SystemNotification } from './system-notification.dto';
34

45
@NotificationStrategy(SystemNotification)
5-
export class SystemNotificationStrategy extends INotificationStrategy<SystemNotification> {}
6+
export class SystemNotificationStrategy extends INotificationStrategy<SystemNotification> {
7+
recipientsForNeo4j() {
8+
return (query: Query) =>
9+
query.match(node('recipient', 'User')).return('recipient');
10+
}
11+
}

src/components/notifications/notification.repository.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { forwardRef, Inject, Injectable } from '@nestjs/common';
2+
import { Nil } from '@seedcompany/common';
23
import { inArray, node, Query, relation } from 'cypher-query-builder';
34
import { omit } from 'lodash';
45
import { DateTime } from 'luxon';
@@ -39,7 +40,7 @@ export class NotificationRepository extends CommonRepository {
3940
}
4041

4142
async create(
42-
recipients: ReadonlyArray<ID<'User'>>,
43+
recipients: ReadonlyArray<ID<'User'>> | Nil,
4344
type: ResourceShape<any>,
4445
input: Record<string, any>,
4546
session: Session,
@@ -65,8 +66,15 @@ export class NotificationRepository extends CommonRepository {
6566
)
6667
.subQuery(['node', 'requestingUser'], (sub) =>
6768
sub
68-
.match(node('recipient', 'User'))
69-
.where({ 'recipient.id': inArray(recipients) })
69+
.apply((q) =>
70+
recipients == null
71+
? q.subQuery(
72+
this.service.getStrategy(type).recipientsForNeo4j(input),
73+
)
74+
: q
75+
.match(node('recipient', 'User'))
76+
.where({ 'recipient.id': inArray(recipients) }),
77+
)
7078
.create([
7179
node('node'),
7280
relation('out', '', 'recipient', { unread: variable('true') }),

src/components/notifications/notification.service.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { DiscoveryService } from '@golevelup/nestjs-discovery';
22
import { forwardRef, Inject, Injectable, OnModuleInit } from '@nestjs/common';
3-
import { mapEntries } from '@seedcompany/common';
3+
import { mapEntries, Nil } from '@seedcompany/common';
44
import {
55
ID,
66
ResourceShape,
@@ -30,9 +30,12 @@ export abstract class NotificationService {
3030
@Inject(GqlContextHost)
3131
protected readonly gqlContextHost: GqlContextHost;
3232

33+
/**
34+
* If the recipient list is given (not nil), it will override the strategy's recipient resolution.
35+
*/
3336
async create<T extends ResourceShape<Notification>>(
3437
type: T,
35-
recipients: ReadonlyArray<ID<'User'>>,
38+
recipients: ReadonlyArray<ID<'User'>> | Nil,
3639
input: T extends { Input: infer Input } ? Input : InputOf<T['prototype']>,
3740
) {
3841
const session = sessionFromContext(this.gqlContextHost.context);

src/components/notifications/notification.strategy.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ export abstract class INotificationStrategy<
2121
TNotification extends Notification,
2222
TInput = InputOf<TNotification>,
2323
> {
24+
/**
25+
* Expected to return rows with a user as `recipient`
26+
*/
27+
// eslint-disable-next-line @seedcompany/no-unused-vars
28+
recipientsForNeo4j(input: TInput) {
29+
return (query: Query) => query.unwind([], 'recipient').return('recipient');
30+
}
31+
2432
saveForNeo4j(input: TInput) {
2533
return (query: Query) => query.setValues({ node: input }, true);
2634
}

0 commit comments

Comments
 (0)