Skip to content

Commit 9c8e408

Browse files
committed
CCM-11602: letters schema
1 parent 1464338 commit 9c8e408

File tree

4 files changed

+67
-24
lines changed

4 files changed

+67
-24
lines changed

internal/datastore/src/letter-repository.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
UpdateCommand,
77
UpdateCommandOutput
88
} from '@aws-sdk/lib-dynamodb';
9-
import { Letter, LetterSchema } from './types';
9+
import { Letter, LetterSchema, LettersSchema } from './types';
1010
import { Logger } from 'pino';
1111

1212
export type PagingOptions = Partial<{
@@ -130,15 +130,16 @@ export class LetterRepository {
130130
return LetterSchema.parse(result.Attributes);
131131
}
132132

133-
async getLetterIdsBySupplier(supplierId: string): Promise<string[]> {
133+
async getLettersBySupplier(supplierId: string, status: string, size: number, cursor?: string): Promise<Letter[]> {
134134
const result = await this.ddbClient.send(new QueryCommand({
135135
TableName: this.config.lettersTableName,
136-
KeyConditionExpression: 'supplierId = :supplierId',
136+
IndexName: 'supplierStatus-index',
137+
KeyConditionExpression: 'supplierStatus = :supplierStatus',
138+
Limit: size,
137139
ExpressionAttributeValues: {
138-
':supplierId': supplierId
139-
},
140-
ProjectionExpression: 'id'
140+
':supplierStatus': `${supplierId}#${status}`
141+
}
141142
}));
142-
return (result.Items ?? []).map(item => item.id);
143+
return LettersSchema.parse(result.Items);
143144
}
144145
}

internal/datastore/src/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const LetterStatus = z.enum([
1919

2020
export const LetterSchema = z.object({
2121
id: z.string(),
22-
supplierId: idRef(SupplierSchema),
22+
supplierId: z.string(),
2323
specificationId: z.string(),
2424
groupId: z.string(),
2525
url: z.url(),
@@ -30,6 +30,8 @@ export const LetterSchema = z.object({
3030
ttl: z.int()
3131
}).describe('Letter');
3232

33+
export const LettersSchema = z.array(LetterSchema);
34+
3335
/**
3436
* Letter is the type used for storing letters in the database.
3537
* The supplierStatus is a composite key combining supplierId and status.

lambdas/api-handler/src/handlers/get-letters.ts

Lines changed: 54 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,43 @@
11
import { APIGatewayProxyHandler } from 'aws-lambda';
22
import { getLetterIdsForSupplier } from '../services/letter-operations';
33
import { createLetterRepository } from '../infrastructure/letter-repo-factory';
4+
import { Letter } from '../../../../internal/datastore/src';
45

56
const letterRepo = createLetterRepository();
67

78
export const getLetters: APIGatewayProxyHandler = async (event) => {
89

910
if (event.path === '/letters') {
1011

11-
// default to supplier1 for now
12-
const supplierId = event.headers['nhsd-apim-apikey'];
12+
const supplierId = event.headers['nhsd-supplier-id'];
1313

14-
const letterIds = await getLetterIdsForSupplier(supplierId, letterRepo);
14+
if (!supplierId) {
15+
return {
16+
statusCode: 400,
17+
body: "Bad Request: Missing supplier ID"
18+
};
19+
}
1520

16-
const response = createGetLettersResponse(event.path, letterIds);
21+
const status = event.queryStringParameters?.status;
22+
23+
if (!status) {
24+
return {
25+
statusCode: 400,
26+
body: "Bad Request: Missing required query parameter 'status'",
27+
};
28+
}
29+
30+
let size = event.queryStringParameters?.size;
31+
32+
if (!size) {
33+
size = '10';
34+
}
35+
36+
const cursor = event.queryStringParameters?.cursor;
37+
38+
const letters = await getLetterIdsForSupplier(supplierId, status, Number(size), letterRepo, cursor);
39+
40+
const response = createGetLettersResponse(event.path, letters, supplierId);
1741

1842
return {
1943
statusCode: 200,
@@ -35,19 +59,24 @@ interface GetLettersLinks {
3559
prev?: string;
3660
}
3761

38-
interface Resource {
39-
type: string;
40-
id: string;
41-
}
62+
type LetterResponse = Omit<Letter, "supplierId" | "supplierStatus" | "ttl">;
63+
4264

4365
interface GetLettersResponse {
4466
links: GetLettersLinks;
45-
data: Resource[];
67+
data: {
68+
type: 'Letters';
69+
supplierId: string;
70+
attributes: {
71+
letters: Array<LetterResponse>;
72+
}
73+
};
4674
}
4775

4876
function createGetLettersResponse(
4977
baseUrl: string,
50-
letters: string[]
78+
letters: Letter[],
79+
supplierId: string,
5180
): GetLettersResponse {
5281
return {
5382
links: {
@@ -57,9 +86,20 @@ function createGetLettersResponse(
5786
next: `${baseUrl}?page=1`,
5887
prev: `${baseUrl}?page=1`
5988
},
60-
data: letters.map((letterId) => ({
61-
type: "letter",
62-
id: letterId,
63-
})),
89+
data: {
90+
type: 'Letters',
91+
supplierId,
92+
attributes: {
93+
letters: letters.map((letter) => ({
94+
id: letter.id,
95+
specificationId: letter.specificationId,
96+
groupId: letter.groupId,
97+
url: letter.url,
98+
status: letter.status,
99+
createdAt: letter.createdAt,
100+
updatedAt: letter.updatedAt,
101+
})),
102+
}
103+
}
64104
};
65105
}

lambdas/api-handler/src/services/letter-operations.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { LetterApiResource, LetterApiDocument } from '../contracts/letter-api';
44
import { toApiLetter } from '../mappers/letter-mapper';
55

66

7-
export const getLetterIdsForSupplier = async (supplierId: string, letterRepo: LetterRepository): Promise<string[]> => {
7+
export const getLettersForSupplier = async (supplierId: string, status: string, size: number, letterRepo: LetterRepository, cursor?: string): Promise<string[]> => {
88

9-
return await letterRepo.getLetterIdsBySupplier(supplierId);
9+
return await letterRepo.getLettersBySupplier(supplierId, status, size, cursor);
1010
}
1111

1212
export const patchLetterStatus = async (letterToUpdate: LetterApiResource, letterId: string, supplierId: string, letterRepo: LetterRepository): Promise<LetterApiDocument> => {

0 commit comments

Comments
 (0)