Skip to content

Commit aede88d

Browse files
committed
Creating new mask field 'genderAndSex' which masks all related fields
1 parent a60a067 commit aede88d

File tree

2 files changed

+38
-26
lines changed

2 files changed

+38
-26
lines changed

src/helpers/patientUtils.js

Lines changed: 36 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ function getPatientName(name) {
7878
* dataAbsentReason extension with value 'masked'
7979
* @param {Object} bundle a FHIR bundle with a Patient resource
8080
* @param {Array} mask an array of fields to mask. Values can be:
81-
* 'gender','mrn','name','address','birthDate','language','ethnicity','birthsex',
81+
* 'genderAndSex','mrn','name','address','birthDate','language','ethnicity',
8282
* 'race', 'telecom', 'multipleBirth', 'photo', 'contact', 'generalPractitioner',
8383
* 'managingOrganization', and 'link'
8484
* @param {Boolean} maskAll indicates that all supported fields should be masked, defaults to false
@@ -91,14 +91,13 @@ function maskPatientData(bundle, mask, maskAll = false) {
9191
)[0];
9292

9393
const validFields = [
94-
'gender',
94+
'genderAndSex',
9595
'mrn',
9696
'name',
9797
'address',
9898
'birthDate',
9999
'language',
100100
'ethnicity',
101-
'birthsex',
102101
'race',
103102
'telecom',
104103
'multipleBirth',
@@ -117,13 +116,40 @@ function maskPatientData(bundle, mask, maskAll = false) {
117116
throw Error(`'${field}' is not a field that can be masked. Patient will only be extracted if all mask fields are valid. Valid fields include: Valid fields include: ${validFields.join(', ')}`);
118117
}
119118
// must check if the field exists in the patient resource, so we don't add unnecessary dataAbsent extensions
120-
if (field === 'gender' && 'gender' in patient) {
121-
delete patient.gender;
122-
// an underscore is added when a primitive type is being replaced by an object (extension)
123-
patient._gender = masked;
124-
} else if (field === 'gender' && '_gender' in patient) {
125-
delete patient._gender; // gender may have a dataAbsentReason on it for 'unknown' data, but we'll still want to mask it
126-
patient._gender = masked;
119+
if (field === 'genderAndSex') {
120+
if ('gender' in patient) {
121+
delete patient.gender;
122+
// an underscore is added when a primitive type is being replaced by an object (extension)
123+
patient._gender = masked;
124+
} else if ('_gender' in patient) {
125+
delete patient._gender; // gender may have a dataAbsentReason on it for 'unknown' data, but we'll still want to mask it
126+
patient._gender = masked;
127+
}
128+
// fields that are extensions need to be differentiated by URL using fhirpath
129+
const birthsex = fhirpath.evaluate(
130+
patient,
131+
'Patient.extension.where(url=\'http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex\')',
132+
);
133+
// fhirpath.evaluate will return [] if there is no extension with the given URL
134+
// so checking if the result is an array with anything in it checks if the field exists to be masked
135+
if (birthsex.length > 0) {
136+
delete birthsex[0].valueCode;
137+
birthsex[0]._valueCode = masked;
138+
}
139+
const legalsex = fhirpath.evaluate(
140+
patient,
141+
'Patient.extension.where(url=\'http://open.epic.com/FHIR/StructureDefinition/extension/legal-sex\')',
142+
);
143+
if (legalsex.length > 0) {
144+
legalsex[0].valueCodeableConcept = masked;
145+
}
146+
const clinicaluse = fhirpath.evaluate(
147+
patient,
148+
'Patient.extension.where(url=\'http://open.epic.com/FHIR/StructureDefinition/extension/sex-for-clinical-use\')',
149+
);
150+
if (clinicaluse.length > 0) {
151+
clinicaluse[0].valueCodeableConcept = masked;
152+
}
127153
} else if (field === 'mrn' && 'identifier' in patient) {
128154
// id and fullURL still need valid values, so we use a hashed version of MRN instead of dataAbsentReason
129155
const hash = crypto.createHash('sha256');
@@ -147,18 +173,6 @@ function maskPatientData(bundle, mask, maskAll = false) {
147173
if ('communication' in patient && 'language' in patient.communication[0]) {
148174
patient.communication[0].language = masked;
149175
}
150-
} else if (field === 'birthsex') {
151-
// fields that are extensions need to be differentiated by URL using fhirpath
152-
const birthsex = fhirpath.evaluate(
153-
patient,
154-
'Patient.extension.where(url=\'http://hl7.org/fhir/us/core/StructureDefinition/us-core-birthsex\')',
155-
);
156-
// fhirpath.evaluate will return [] if there is no extension with the given URL
157-
// so checking if the result is an array with anything in it checks if the field exists to be masked
158-
if (birthsex.length > 0) {
159-
delete birthsex[0].valueCode;
160-
birthsex[0]._valueCode = masked;
161-
}
162176
} else if (field === 'race') {
163177
const race = fhirpath.evaluate(
164178
patient,

test/helpers/patientUtils.test.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -93,14 +93,13 @@ describe('PatientUtils', () => {
9393
test('bundle should be modified to have dataAbsentReason for all fields specified in mask', () => {
9494
const bundle = _.cloneDeep(examplePatient);
9595
maskPatientData(bundle, [
96-
'gender',
96+
'genderAndSex',
9797
'mrn',
9898
'name',
9999
'address',
100100
'birthDate',
101101
'language',
102102
'ethnicity',
103-
'birthsex',
104103
'race',
105104
'telecom',
106105
'multipleBirth',
@@ -132,14 +131,13 @@ describe('PatientUtils', () => {
132131
],
133132
};
134133
maskPatientData(bundle, [
135-
'gender',
134+
'genderAndSex',
136135
'mrn',
137136
'name',
138137
'address',
139138
'birthDate',
140139
'language',
141140
'ethnicity',
142-
'birthsex',
143141
'race',
144142
'telecom',
145143
'multipleBirth',

0 commit comments

Comments
 (0)