Skip to content

Commit 6fd716c

Browse files
committed
Release vintasend-medplum@0.8.2
1 parent 73becae commit 6fd716c

File tree

3 files changed

+85
-2
lines changed

3 files changed

+85
-2
lines changed

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "vintasend-medplum",
3-
"version": "0.8.1",
3+
"version": "0.8.2",
44
"description": "",
55
"main": "dist/index.js",
66
"scripts": {
@@ -25,7 +25,7 @@
2525
"@medplum/fhirtypes": "^5.0.10",
2626
"pdfmake": "^0.2.23",
2727
"pug": "^3.0.3",
28-
"vintasend": "^0.8.1"
28+
"vintasend": "^0.8.2"
2929
},
3030
"devDependencies": {
3131
"@medplum/definitions": "^5.0.10",

src/__tests__/medplum-backend.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,47 @@ describe('MedplumNotificationBackend', () => {
811811
'contextName lookup with caseSensitive=false is not supported by MedplumNotificationBackend. Only case-sensitive exact matching is supported.',
812812
);
813813
});
814+
815+
it('should map supported orderBy fields and directions to FHIR _sort', async () => {
816+
const searchResourcesSpy = jest
817+
.spyOn(medplumClient, 'searchResources')
818+
.mockResolvedValue([] as any);
819+
820+
const testCases = [
821+
{ orderBy: { field: 'sendAfter', direction: 'asc' } as const, expectedSort: 'sent' },
822+
{ orderBy: { field: 'sendAfter', direction: 'desc' } as const, expectedSort: '-sent' },
823+
{ orderBy: { field: 'sentAt', direction: 'asc' } as const, expectedSort: 'sent' },
824+
{ orderBy: { field: 'sentAt', direction: 'desc' } as const, expectedSort: '-sent' },
825+
{ orderBy: { field: 'createdAt', direction: 'asc' } as const, expectedSort: '_lastUpdated' },
826+
{ orderBy: { field: 'createdAt', direction: 'desc' } as const, expectedSort: '-_lastUpdated' },
827+
{ orderBy: { field: 'updatedAt', direction: 'asc' } as const, expectedSort: '_lastUpdated' },
828+
{ orderBy: { field: 'updatedAt', direction: 'desc' } as const, expectedSort: '-_lastUpdated' },
829+
];
830+
831+
for (const testCase of testCases) {
832+
searchResourcesSpy.mockClear();
833+
await backend.filterNotifications({}, 0, 10, testCase.orderBy);
834+
835+
expect(searchResourcesSpy).toHaveBeenCalledWith('Communication', [
836+
['_count', '10'],
837+
['_offset', '0'],
838+
['_sort', testCase.expectedSort],
839+
['_tag', 'notification'],
840+
]);
841+
}
842+
});
843+
844+
it('should throw for unsupported orderBy.readAt', async () => {
845+
const searchResourcesSpy = jest
846+
.spyOn(medplumClient, 'searchResources')
847+
.mockResolvedValue([] as any);
848+
849+
await expect(
850+
backend.filterNotifications({}, 0, 10, { field: 'readAt', direction: 'asc' }),
851+
).rejects.toThrow("orderBy field 'readAt' is not supported by MedplumNotificationBackend.");
852+
853+
expect(searchResourcesSpy).not.toHaveBeenCalled();
854+
});
814855
});
815856

816857
describe('getFilterCapabilities', () => {
@@ -877,5 +918,18 @@ describe('MedplumNotificationBackend', () => {
877918
expect(capabilities['stringLookups.includes']).toBe(false);
878919
expect(capabilities['stringLookups.caseInsensitive']).toBe(false);
879920
});
921+
922+
it('should mark orderBy.readAt as unsupported', () => {
923+
const capabilities = backend.getFilterCapabilities();
924+
expect(capabilities['orderBy.readAt']).toBe(false);
925+
});
926+
927+
it('should mark supported orderBy fields as supported', () => {
928+
const capabilities = backend.getFilterCapabilities();
929+
expect(capabilities['orderBy.sendAfter']).toBe(true);
930+
expect(capabilities['orderBy.sentAt']).toBe(true);
931+
expect(capabilities['orderBy.createdAt']).toBe(true);
932+
expect(capabilities['orderBy.updatedAt']).toBe(true);
933+
});
880934
});
881935
});

src/medplum-backend.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type {
66
BaseNotificationBackend,
77
NotificationFilter,
88
NotificationFilterFields,
9+
NotificationOrderBy,
910
} from 'vintasend/dist/services/notification-backends/base-notification-backend';
1011
import { isFieldFilter } from 'vintasend/dist/services/notification-backends/base-notification-backend';
1112
import type {
@@ -112,9 +113,33 @@ export class MedplumNotificationBackend<Config extends BaseNotificationTypeConfi
112113
'stringLookups.endsWith': false,
113114
'stringLookups.includes': false,
114115
'stringLookups.caseInsensitive': false,
116+
'orderBy.sendAfter': true,
117+
'orderBy.sentAt': true,
118+
'orderBy.readAt': false,
119+
'orderBy.createdAt': true,
120+
'orderBy.updatedAt': true,
115121
};
116122
}
117123

124+
private convertNotificationOrderByToFhirSort(orderBy: NotificationOrderBy): string {
125+
const fieldMap: Record<NotificationOrderBy['field'], string> = {
126+
sendAfter: 'sent',
127+
sentAt: 'sent',
128+
createdAt: '_lastUpdated',
129+
updatedAt: '_lastUpdated',
130+
readAt: '',
131+
};
132+
133+
if (orderBy.field === 'readAt') {
134+
throw new Error(
135+
"orderBy field 'readAt' is not supported by MedplumNotificationBackend.",
136+
);
137+
}
138+
139+
const mappedField = fieldMap[orderBy.field];
140+
return orderBy.direction === 'desc' ? `-${mappedField}` : mappedField;
141+
}
142+
118143
private resolveStringFieldForFhir(fieldName: string, value: StringFieldFilter): string {
119144
if (!isStringFilterLookup(value)) {
120145
return value;
@@ -885,6 +910,7 @@ export class MedplumNotificationBackend<Config extends BaseNotificationTypeConfi
885910
filter: NotificationFilter<Config>,
886911
page: number,
887912
pageSize: number,
913+
orderBy?: NotificationOrderBy,
888914
): Promise<AnyDatabaseNotification<Config>[]> {
889915
if ('or' in filter) {
890916
throw new Error(
@@ -895,6 +921,9 @@ export class MedplumNotificationBackend<Config extends BaseNotificationTypeConfi
895921
const searchParams = this.buildFhirSearchParams(filter);
896922
searchParams._count = pageSize.toString();
897923
searchParams._offset = (page * pageSize).toString();
924+
if (orderBy) {
925+
searchParams._sort = this.convertNotificationOrderByToFhirSort(orderBy);
926+
}
898927

899928
// Convert to string[][] so that _tag values become repeated AND parameters
900929
// (comma-separated _tag in a single param means OR in FHIR, which is wrong here)

0 commit comments

Comments
 (0)