Skip to content

Commit 7e86b76

Browse files
committed
feat: add totalCount to results
1 parent 2ebd8af commit 7e86b76

File tree

7 files changed

+95
-60
lines changed

7 files changed

+95
-60
lines changed
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { Notification } from './Notification'
2+
3+
export interface NotificationSubset {
4+
notifications: Notification[]
5+
totalNotificationCount: number
6+
}

src/notifications/domain/repositories/INotificationsRepository.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
import { Notification } from '../models/Notification'
1+
import { NotificationSubset } from '../models/NotificationSubset'
22

33
export interface INotificationsRepository {
44
getAllNotificationsByUser(
55
inAppNotificationFormat?: boolean,
66
onlyUnread?: boolean,
77
limit?: number,
88
offset?: number
9-
): Promise<Notification[]>
9+
): Promise<NotificationSubset>
1010
deleteNotification(notificationId: number): Promise<void>
1111
getUnreadNotificationsCount(): Promise<number>
1212
markNotificationAsRead(notificationId: number): Promise<void>
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { UseCase } from '../../../core/domain/useCases/UseCase'
2-
import { Notification } from '../models/Notification'
32
import { INotificationsRepository } from '../repositories/INotificationsRepository'
3+
import { NotificationSubset } from '../models/NotificationSubset'
44

5-
export class GetAllNotificationsByUser implements UseCase<Notification[]> {
5+
export class GetAllNotificationsByUser implements UseCase<NotificationSubset> {
66
constructor(private readonly notificationsRepository: INotificationsRepository) {}
77

88
/**
@@ -12,19 +12,19 @@ export class GetAllNotificationsByUser implements UseCase<Notification[]> {
1212
* @param onlyUnread - Optional parameter to filter only unread notifications
1313
* @param limit - Optional parameter to limit the number of notifications returned
1414
* @param offset - Optional parameter to skip a number of notifications (for pagination)
15-
* @returns {Promise<Notification[]>} - A promise that resolves to an array of Notification instances.
15+
* @returns {Promise<NotificationSubset>} - A promise that resolves to an array of Notification instances.
1616
*/
1717
async execute(
1818
inAppNotificationFormat?: boolean,
1919
onlyUnread?: boolean,
2020
limit?: number,
2121
offset?: number
22-
): Promise<Notification[]> {
22+
): Promise<NotificationSubset> {
2323
return (await this.notificationsRepository.getAllNotificationsByUser(
2424
inAppNotificationFormat,
2525
onlyUnread,
2626
limit,
2727
offset
28-
)) as Notification[]
28+
)) as NotificationSubset
2929
}
3030
}

src/notifications/infra/repositories/NotificationsRepository.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ApiRepository } from '../../../core/infra/repositories/ApiRepository'
22
import { INotificationsRepository } from '../../domain/repositories/INotificationsRepository'
33
import { Notification } from '../../domain/models/Notification'
44
import { NotificationPayload } from '../transformers/NotificationPayload'
5+
import { NotificationSubset } from '../../domain/models/NotificationSubset'
56

67
export class NotificationsRepository extends ApiRepository implements INotificationsRepository {
78
private readonly notificationsResourceName: string = 'notifications'
@@ -11,29 +12,33 @@ export class NotificationsRepository extends ApiRepository implements INotificat
1112
onlyUnread?: boolean,
1213
limit?: number,
1314
offset?: number
14-
): Promise<Notification[]> {
15-
const queryParams: Record<string, string | number> = {}
16-
17-
if (inAppNotificationFormat) queryParams.inAppNotificationFormat = 'true'
18-
if (onlyUnread) queryParams.onlyUnread = 'true'
19-
if (limit !== undefined) queryParams.limit = limit
20-
if (offset !== undefined) queryParams.offset = offset
15+
): Promise<NotificationSubset> {
16+
const queryParams = new URLSearchParams()
2117

18+
if (inAppNotificationFormat) queryParams.set('inAppNotificationFormat', 'true')
19+
if (onlyUnread) queryParams.set('onlyUnread', 'true')
20+
if (limit !== undefined) queryParams.set('limit', limit.toString())
21+
if (offset !== undefined) queryParams.set('offset', offset.toString())
22+
console.log('Fetching notifications with params:', queryParams.toString())
23+
console.log('keys:', Array.from(queryParams.keys()))
24+
console.log('length:', Object.keys(queryParams).length)
2225
return this.doGet(
2326
this.buildApiEndpoint(this.notificationsResourceName, 'all'),
2427
true,
25-
Object.keys(queryParams).length ? queryParams : undefined
28+
queryParams
2629
)
2730
.then((response) => {
28-
const notifications = response.data.data.notifications
29-
return notifications.map((notification: NotificationPayload) => {
31+
console.log('Notifications API response:', response.data)
32+
const notifications = response.data.data.map((notification: NotificationPayload) => {
3033
const { dataverseDisplayName, dataverseAlias, ...restNotification } = notification
3134
return {
3235
...restNotification,
3336
...(dataverseDisplayName && { collectionDisplayName: dataverseDisplayName }),
3437
...(dataverseAlias && { collectionAlias: dataverseAlias })
3538
}
3639
}) as Notification[]
40+
const totalNotificationCount = response.data.totalCount
41+
return { notifications, totalNotificationCount }
3742
})
3843
.catch((error) => {
3944
throw error

test/functional/notifications/DeleteNotification.test.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@ describe('execute', () => {
1212
})
1313

1414
test('should successfully delete a notification for authenticated user', async () => {
15-
const notifications = await getAllNotificationsByUser.execute()
15+
const notificationSubset = await getAllNotificationsByUser.execute()
16+
const notifications = notificationSubset.notifications
1617
const notificationId = notifications[notifications.length - 1].id
1718

1819
await deleteNotification.execute(notificationId)
1920

20-
const notificationsAfterDelete = await getAllNotificationsByUser.execute()
21+
const notificationsAfterDeleteSubset = await getAllNotificationsByUser.execute()
22+
const notificationsAfterDelete = notificationsAfterDeleteSubset.notifications
2123
expect(notificationsAfterDelete.length).toBe(notifications.length - 1)
2224
})
2325

test/functional/notifications/GetAllNotificationsByUser.test.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { ApiConfig, getAllNotificationsByUser, Notification } from '../../../src'
1+
import { ApiConfig, getAllNotificationsByUser } from '../../../src'
22
import { TestConstants } from '../../testHelpers/TestConstants'
33
import { DataverseApiAuthMechanism } from '../../../src/core/infra/repositories/ApiConfig'
4-
4+
import { NotificationSubset } from '../../../src/notifications/domain/models/NotificationSubset'
55
describe('execute', () => {
66
beforeEach(async () => {
77
ApiConfig.init(
@@ -12,30 +12,35 @@ describe('execute', () => {
1212
})
1313

1414
test('should successfully return notifications for authenticated user', async () => {
15-
const notifications: Notification[] = await getAllNotificationsByUser.execute()
15+
const result: NotificationSubset = await getAllNotificationsByUser.execute()
16+
const notifications = result.notifications
1617

1718
expect(notifications).not.toBeNull()
1819
expect(Array.isArray(notifications)).toBe(true)
1920
})
2021

2122
test('should have correct notification properties if notifications exist', async () => {
22-
const notifications = await getAllNotificationsByUser.execute()
23+
const result: NotificationSubset = await getAllNotificationsByUser.execute()
24+
const notifications = result.notifications
2325

2426
expect(notifications[0]).toHaveProperty('id')
2527
expect(notifications[0]).toHaveProperty('type')
2628
expect(notifications[0]).toHaveProperty('sentTimestamp')
2729
})
2830

2931
test('should have correct in-app notification properties when inAppNotificationFormat is true', async () => {
30-
const notifications = await getAllNotificationsByUser.execute(true)
32+
const result: NotificationSubset = await getAllNotificationsByUser.execute(true)
33+
const notifications = result.notifications
3134

3235
expect(notifications[0]).toHaveProperty('id')
3336
expect(notifications[0]).toHaveProperty('type')
3437
expect(notifications[0]).toHaveProperty('sentTimestamp')
3538
expect(notifications[0]).toHaveProperty('displayAsRead')
3639
})
40+
3741
test('should have correct in-app notification properties when filter and paging params are set', async () => {
38-
const notifications = await getAllNotificationsByUser.execute(true, true, 1, 0)
42+
const result: NotificationSubset = await getAllNotificationsByUser.execute(true, true, 1, 0)
43+
const notifications = result.notifications
3944

4045
expect(notifications[0]).toHaveProperty('id')
4146
expect(notifications[0]).toHaveProperty('type')

test/integration/notifications/NotificationsRepository.test.ts

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import {
1616
createCollectionDTO,
1717
deleteCollectionViaApi
1818
} from '../../testHelpers/collections/collectionHelper'
19+
import { NotificationSubset } from '../../../src/notifications/domain/models/NotificationSubset'
1920

2021
describe('NotificationsRepository', () => {
2122
const sut: NotificationsRepository = new NotificationsRepository()
@@ -36,12 +37,12 @@ describe('NotificationsRepository', () => {
3637
await publishDatasetViaApi(testDatasetIds.numericId)
3738
await waitForNoLocks(testDatasetIds.numericId, 10)
3839

39-
const notifications: Notification[] = await sut.getAllNotificationsByUser()
40+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser()
4041

41-
expect(Array.isArray(notifications)).toBe(true)
42-
expect(notifications.length).toBeGreaterThan(0)
42+
expect(Array.isArray(notificationSubset.notifications)).toBe(true)
43+
expect(notificationSubset.notifications.length).toBeGreaterThan(0)
4344

44-
const publishedNotification = notifications.find(
45+
const publishedNotification = notificationSubset.notifications.find(
4546
(n) => n.type === NotificationType.PUBLISHEDDS
4647
) as Notification
4748

@@ -62,14 +63,14 @@ describe('NotificationsRepository', () => {
6263
})
6364

6465
test('should delete a notification by ID', async () => {
65-
const notifications: Notification[] = await sut.getAllNotificationsByUser()
66+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser()
6667

67-
const notificationToDelete = notifications[0]
68+
const notificationToDelete = notificationSubset.notifications[0]
6869

6970
await sut.deleteNotification(notificationToDelete.id)
7071

71-
const notificationsAfterDelete: Notification[] = await sut.getAllNotificationsByUser()
72-
const deletedNotification = notificationsAfterDelete.find(
72+
const notificationsAfterDelete: NotificationSubset = await sut.getAllNotificationsByUser()
73+
const deletedNotification = notificationsAfterDelete.notifications.find(
7374
(n) => n.id === notificationToDelete.id
7475
)
7576
expect(deletedNotification).toBeUndefined()
@@ -86,27 +87,26 @@ describe('NotificationsRepository', () => {
8687
})
8788

8889
test('should return notifications with basic properties when inAppNotificationFormat is true', async () => {
89-
const notifications: Notification[] = await sut.getAllNotificationsByUser(true)
90+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser(true)
9091

91-
const notification = notifications[0]
92+
const notification = notificationSubset.notifications[0]
9293
expect(notification).toHaveProperty('id')
9394
expect(notification).toHaveProperty('type')
9495
expect(notification).toHaveProperty('sentTimestamp')
9596
expect(notification).toHaveProperty('displayAsRead')
9697
})
9798

9899
test('should find notification with ASSIGNROLE type that has not been deleted', async () => {
99-
const notifications: Notification[] = await sut.getAllNotificationsByUser(true)
100+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser(true)
100101

101-
const assignRoleNotification = notifications.find(
102+
const assignRoleNotification = notificationSubset.notifications.find(
102103
(n) => n.type === NotificationType.ASSIGNROLE && !n.objectDeleted
103104
)
104105

105106
expect(assignRoleNotification).toBeDefined()
106107
expect(assignRoleNotification?.type).toBe(NotificationType.ASSIGNROLE)
107108
expect(assignRoleNotification?.sentTimestamp).toBeDefined()
108109
expect(assignRoleNotification?.displayAsRead).toBeDefined()
109-
expect(assignRoleNotification?.collectionDisplayName).toBeDefined()
110110

111111
expect(assignRoleNotification?.roleAssignments).toBeDefined()
112112
expect(assignRoleNotification?.roleAssignments?.length).toBeGreaterThan(0)
@@ -125,11 +125,11 @@ describe('NotificationsRepository', () => {
125125
expect(createdCollectionId).toBeDefined()
126126
expect(createdCollectionId).toBeGreaterThan(0)
127127

128-
const notifications: Notification[] = await sut.getAllNotificationsByUser(true)
129-
expect(Array.isArray(notifications)).toBe(true)
130-
expect(notifications.length).toBeGreaterThan(0)
128+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser(true, true)
129+
expect(Array.isArray(notificationSubset.notifications)).toBe(true)
130+
expect(notificationSubset.notifications.length).toBeGreaterThan(0)
131131

132-
const createdvNotification = notifications.find(
132+
const createdvNotification = notificationSubset.notifications.find(
133133
(n) => n.collectionAlias === testCollectionAlias
134134
)
135135

@@ -145,9 +145,9 @@ describe('NotificationsRepository', () => {
145145
})
146146

147147
test('should return array when inAppNotificationFormat is false', async () => {
148-
const notifications: Notification[] = await sut.getAllNotificationsByUser(false)
148+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser(false)
149149

150-
expect(Array.isArray(notifications)).toBe(true)
150+
expect(Array.isArray(notificationSubset.notifications)).toBe(true)
151151
})
152152

153153
test('should return unread count', async () => {
@@ -158,16 +158,18 @@ describe('NotificationsRepository', () => {
158158
})
159159

160160
test('should mark notification as read successfully', async () => {
161-
const notifications: Notification[] = await sut.getAllNotificationsByUser()
161+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser()
162162

163-
expect(notifications.length).toBeGreaterThan(0)
163+
expect(notificationSubset.notifications.length).toBeGreaterThan(0)
164164

165-
const unreadNotification = notifications[0]
165+
const unreadNotification = notificationSubset.notifications[0]
166166

167167
await expect(sut.markNotificationAsRead(unreadNotification.id)).resolves.toBeUndefined()
168168

169-
const updatedNotifications: Notification[] = await sut.getAllNotificationsByUser()
170-
const updatedNotification = updatedNotifications.find((n) => n.id === unreadNotification.id)
169+
const updatedNotificationSubset: NotificationSubset = await sut.getAllNotificationsByUser()
170+
const updatedNotification = updatedNotificationSubset.notifications.find(
171+
(n) => n.id === unreadNotification.id
172+
)
171173

172174
expect(updatedNotification?.displayAsRead).toBe(true)
173175
})
@@ -184,25 +186,40 @@ describe('NotificationsRepository', () => {
184186
)
185187
})
186188
test('should only return unread notifications when onlyUnread is true', async () => {
187-
const notifications: Notification[] = await sut.getAllNotificationsByUser(true, true)
189+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser(true, true)
188190

189-
expect(Array.isArray(notifications)).toBe(true)
190-
const originalUnreadCount = notifications.length
191-
expect(notifications.length).toBeGreaterThanOrEqual(0)
191+
expect(Array.isArray(notificationSubset.notifications)).toBe(true)
192+
const originalUnreadCount = notificationSubset.totalNotificationCount
193+
expect(notificationSubset.notifications.length).toBeGreaterThanOrEqual(0)
192194

193-
await expect(sut.markNotificationAsRead(notifications[0].id)).resolves.toBeUndefined()
195+
await expect(
196+
sut.markNotificationAsRead(notificationSubset.notifications[0].id)
197+
).resolves.toBeUndefined()
194198

195-
const updatedNotifications: Notification[] = await sut.getAllNotificationsByUser(true, true)
196-
expect(updatedNotifications.length).toBe(originalUnreadCount - 1)
199+
const updatedNotifications: NotificationSubset = await sut.getAllNotificationsByUser(
200+
true,
201+
true,
202+
10,
203+
0
204+
)
205+
expect(updatedNotifications.totalNotificationCount).toBe(originalUnreadCount - 1)
197206

198-
const hasReadNotifications = notifications.some((n) => n.displayAsRead === true)
207+
const hasReadNotifications = notificationSubset.notifications.some(
208+
(n) => n.displayAsRead === true
209+
)
199210
expect(hasReadNotifications).toBe(false)
200211
})
201212
test('should return limited number of notifications when limit is set', async () => {
202213
const limit = 1
203-
const notifications: Notification[] = await sut.getAllNotificationsByUser(true, false, limit, 0)
214+
const notificationSubset: NotificationSubset = await sut.getAllNotificationsByUser(
215+
true,
216+
false,
217+
limit,
218+
0
219+
)
204220

205-
expect(Array.isArray(notifications)).toBe(true)
206-
expect(notifications.length).toBeLessThanOrEqual(limit)
221+
expect(Array.isArray(notificationSubset.notifications)).toBe(true)
222+
expect(notificationSubset.notifications.length).toBeLessThanOrEqual(limit)
223+
expect(notificationSubset.totalNotificationCount).toBeGreaterThanOrEqual(limit)
207224
})
208225
})

0 commit comments

Comments
 (0)