Skip to content

Commit

Permalink
Remove age range from mongoose types; fix model tests #2670
Browse files Browse the repository at this point in the history
Controller tests still fail at this point.
  • Loading branch information
iamleeg committed May 6, 2022
1 parent 985e8f4 commit 4ec7356
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 122 deletions.
22 changes: 5 additions & 17 deletions data-serving/data-service/src/controllers/case.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
Case,
caseAgeRange,
CaseDocument,
CaseDTO,
caseWithDenormalisedConfirmationDate,
Expand Down Expand Up @@ -67,26 +68,13 @@ const caseFromDTO = async (receivedCase: CaseDTO) => {

const dtoFromCase = async (storedCase: LeanDocument<CaseDocument>) => {
let dto = (storedCase as unknown) as CaseDTO;
if (
storedCase.demographics &&
storedCase.demographics.ageBuckets &&
storedCase.demographics.ageBuckets.length > 0
) {
const ageBuckets = await Promise.all(
storedCase.demographics.ageBuckets.map((bucketId) => {
return AgeBucket.findById(bucketId).lean();
}),
);
const minimumAge = Math.min(...ageBuckets.map((b) => b!.start));
const maximumAge = Math.max(...ageBuckets.map((b) => b!.end));
const ageRange = await caseAgeRange(storedCase);
if (ageRange) {
dto = {
...dto,
demographics: {
...dto.demographics!,
ageRange: {
start: minimumAge,
end: maximumAge,
},
ageRange,
},
};
// although the type system can't see it, there's an ageBuckets property on the demographics DTO now
Expand Down Expand Up @@ -265,7 +253,7 @@ export class CasesController {
while (doc != null) {
delete doc.restrictedNotes;
delete doc.notes;
const normalizedDoc = denormalizeFields(doc);
const normalizedDoc = await denormalizeFields(doc);
if (!doc.hasOwnProperty('SGTF')) {
normalizedDoc.SGTF = 'NA';
}
Expand Down
6 changes: 5 additions & 1 deletion data-serving/data-service/src/model/case.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CaseReferenceDocument, caseReferenceSchema } from './case-reference';
import { DemographicsDocument, DemographicsDTO, demographicsSchema } from './demographics';
import { demographicsAgeRange, DemographicsDocument, DemographicsDTO, demographicsSchema } from './demographics';
import { EventDocument, eventSchema } from './event';
import {
GenomeSequenceDocument,
Expand Down Expand Up @@ -204,3 +204,7 @@ export const RestrictedCase = mongoose.model<CaseDocument>(
'RestrictedCase',
caseSchema,
);

export const caseAgeRange = async (aCase: LeanDocument<CaseDocument>) => {
return await demographicsAgeRange(aCase.demographics);
};
47 changes: 30 additions & 17 deletions data-serving/data-service/src/model/demographics.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Range } from './range';
import mongoose from 'mongoose';
import mongoose, { LeanDocument } from 'mongoose';
import { ObjectId } from 'mongodb';
import { AgeBucket } from './age-bucket';

/*
* There are separate types for demographics for data storage (the mongoose document) and
Expand All @@ -23,19 +24,6 @@ export const demographicsSchema = new mongoose.Schema(
* than one of the buckets we use.
*/
ageBuckets: [{ type: mongoose.Schema.Types.ObjectId, ref: 'ageBuckets' }],
ageRange: {
start: {
type: Number,
min: 0,
max: 120,
},
end: {
type: Number,
min: 0,
max: 120,
},
_id: false,
},
gender: String,
occupation: String,
nationalities: [String],
Expand All @@ -44,19 +32,44 @@ export const demographicsSchema = new mongoose.Schema(
{ _id: false },
);

export type DemographicsDTO = {
ageRange?: Range<number>;
type DemographicsCommonFields = {
gender: string;
occupation: string;
nationalities: [string];
ethnicity: string;
};

export type DemographicsDTO = DemographicsCommonFields & {
ageRange?: Range<number>;
}

export type DemographicsDocument = mongoose.Document & DemographicsDTO & {
export type DemographicsDocument = mongoose.Document & DemographicsCommonFields & {
ageBuckets: ObjectId[];
};

export const Demographics = mongoose.model<DemographicsDocument>(
'Demographics',
demographicsSchema,
);

export const demographicsAgeRange = async (demographics: LeanDocument<DemographicsDocument>) => {
if (
demographics &&
demographics.ageBuckets &&
demographics.ageBuckets.length > 0
) {
const ageBuckets = await Promise.all(
demographics.ageBuckets.map((bucketId) => {
return AgeBucket.findById(bucketId).lean();
}),
);
const minimumAge = Math.min(...ageBuckets.map((b) => b!.start));
const maximumAge = Math.max(...ageBuckets.map((b) => b!.end));
return {
start: minimumAge,
end: maximumAge,
};
} else {
return undefined;
}
};
15 changes: 8 additions & 7 deletions data-serving/data-service/src/util/case.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { CaseDocument, CaseDTO } from '../model/case';
import { CaseReferenceDocument } from '../model/case-reference';
import { DemographicsDocument } from '../model/demographics';
import { demographicsAgeRange, DemographicsDocument } from '../model/demographics';
import { EventDocument } from '../model/event';
import { LocationDocument } from '../model/location';
import { PathogenDocument } from '../model/pathogen';
Expand Down Expand Up @@ -170,11 +170,11 @@ export const removeBlankHeader = (headers: string[]): string[] => {
return headers;
};

export const denormalizeFields = (doc: CaseDocument): Partial<CaseDocument> => {
export const denormalizeFields = async (doc: CaseDocument): Promise<Partial<CaseDocument>> => {
const caseReferenceFields = denormalizeCaseReferenceFields(
doc.caseReference,
);
const demographicsFields = denormalizeDemographicsFields(doc.demographics);
const demographicsFields = await denormalizeDemographicsFields(doc.demographics);
const eventFields = denormalizeEventsFields(doc.events);
const locationFields = denormalizeLocationFields(doc.location);
const pathogenFields = denormalizePathogenFields(doc.pathogens);
Expand Down Expand Up @@ -259,12 +259,13 @@ function denormalizeCaseReferenceFields(
return denormalizedData;
}

function denormalizeDemographicsFields(
async function denormalizeDemographicsFields(
doc: DemographicsDocument,
): Record<string, string | number> {
): Promise<Record<string, string | number>> {
const denormalizedData: Record<string, string | number> = {};
denormalizedData['demographics.ageRange.end'] = doc.ageRange?.end || '';
denormalizedData['demographics.ageRange.start'] = doc.ageRange?.start || '';
const ageRange = await demographicsAgeRange(doc);
denormalizedData['demographics.ageRange.end'] = ageRange?.end || '';
denormalizedData['demographics.ageRange.start'] = ageRange?.start || '';
denormalizedData['demographics.ethnicity'] = doc.ethnicity || '';
denormalizedData['demographics.gender'] = doc.gender || '';
const nationalities =
Expand Down
48 changes: 0 additions & 48 deletions data-serving/data-service/test/model/demographics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import {
demographicsSchema,
} from '../../src/model/demographics';

import { Error } from 'mongoose';
import fullModel from './data/demographics.full.json';
import minimalModel from './data/demographics.minimal.json';
import mongoose from 'mongoose';
Expand All @@ -14,53 +13,6 @@ const Demographics = mongoose.model<DemographicsDocument>(
);

describe('validate', () => {
it('a start age under 0 is invalid', async () => {
return new Demographics({
...fullModel,
...{ ageRange: { start: -0.1 } },
}).validate((e) => {
expect(e).not.toBeNull();
if (e) expect(e.name).toBe(Error.ValidationError.name);
});
});

it('a start age over 120 is invalid', async () => {
return new Demographics({
...fullModel,
...{ ageRange: { start: 121 } },
}).validate((e) => {
expect(e).not.toBeNull();
if (e) expect(e.name).toBe(Error.ValidationError.name);
});
});

it('an end age under 0 is invalid', async () => {
return new Demographics({
...fullModel,
...{ ageRange: { end: -2 } },
}).validate((e) => {
expect(e).not.toBeNull();
if (e) expect(e.name).toBe(Error.ValidationError.name);
});
});

it('a start age without end is valid', async () => {
return new Demographics({
...fullModel,
...{ ageRange: { start: 85 } },
}).validate();
});

it('an end age over 120 is invalid', async () => {
return new Demographics({
...fullModel,
...{ ageRange: { end: 120.1 } },
}).validate((e) => {
expect(e).not.toBeNull();
if (e) expect(e.name).toBe(Error.ValidationError.name);
});
});

it('a minimal demographics document is valid', async () => {
return new Demographics(minimalModel).validate();
});
Expand Down
Loading

0 comments on commit 4ec7356

Please sign in to comment.