Skip to content

Commit

Permalink
fix-3807 rectify fhirpath exists and empty (medplum#3808)
Browse files Browse the repository at this point in the history
* fix-3807 rectify fhirpath exists and empty

* remove unnecessary/erroneous type assertion

* simplify isFhirCriteriaMet

* unit test exists and empty

* prettier
  • Loading branch information
dillonstreator committed Feb 7, 2024
1 parent c34ad9a commit 7c9ce41
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 3 deletions.
3 changes: 3 additions & 0 deletions packages/core/src/fhirpath/functions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const TYPED_Y = toTypedValue('y');
const TYPED_Z = toTypedValue('z');
const TYPED_APPLE = toTypedValue('apple');
const TYPED_XYZ = toTypedValue('xyz');
const TYPED_EMPTY = toTypedValue({});

const LITERAL_TRUE = new LiteralAtom(TYPED_TRUE);
const LITERAL_FALSE = new LiteralAtom(TYPED_FALSE);
Expand All @@ -40,6 +41,7 @@ describe('FHIRPath functions', () => {

test('empty', () => {
expect(functions.empty(context, [])).toEqual([TYPED_TRUE]);
expect(functions.empty(context, [TYPED_EMPTY])).toEqual([TYPED_TRUE]);
expect(functions.empty(context, [TYPED_1])).toEqual([TYPED_FALSE]);
expect(functions.empty(context, [TYPED_1, TYPED_2])).toEqual([TYPED_FALSE]);
});
Expand All @@ -52,6 +54,7 @@ describe('FHIRPath functions', () => {

test('exists', () => {
expect(functions.exists(context, [])).toEqual([TYPED_FALSE]);
expect(functions.exists(context, [TYPED_EMPTY])).toEqual([TYPED_FALSE]);
expect(functions.exists(context, [TYPED_1])).toEqual([TYPED_TRUE]);
expect(functions.exists(context, [TYPED_1, TYPED_2])).toEqual([TYPED_TRUE]);
expect(functions.exists(context, [], isEven)).toEqual([TYPED_FALSE]);
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/fhirpath/functions.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Reference } from '@medplum/fhirtypes';
import { Atom, AtomContext } from '../fhirlexer/parse';
import { PropertyType, TypedValue, isResource } from '../types';
import { calculateAge } from '../utils';
import { calculateAge, isEmpty } from '../utils';
import { DotAtom, SymbolAtom } from './atoms';
import { parseDateString } from './date';
import { booleanToTypedValue, fhirPathIs, isQuantity, removeDuplicates, toJsBoolean, toTypedValue } from './utils';
Expand Down Expand Up @@ -34,7 +34,7 @@ export const functions: Record<string, FhirPathFunction> = {
* @returns True if the input collection is empty ({ }) and false otherwise.
*/
empty: (_context: AtomContext, input: TypedValue[]): TypedValue[] => {
return booleanToTypedValue(input.length === 0);
return booleanToTypedValue(input.length === 0 || input.every((e) => isEmpty(e.value)));
},

/**
Expand Down Expand Up @@ -67,7 +67,7 @@ export const functions: Record<string, FhirPathFunction> = {
if (criteria) {
return booleanToTypedValue(input.filter((e) => toJsBoolean(criteria.eval(context, [e]))).length > 0);
} else {
return booleanToTypedValue(input.length > 0);
return booleanToTypedValue(input.length > 0 && input.every((e) => !isEmpty(e.value)));
}
},

Expand Down
30 changes: 30 additions & 0 deletions packages/core/src/fhirpath/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,36 @@ describe('FHIRPath parser', () => {
]);
});

test('%previous.empty() returns true for an empty %previous value', () => {
const patient: Patient = {
resourceType: 'Patient',
};
const result = evalFhirPathTyped('%previous.empty()', [toTypedValue(patient)], { '%previous': toTypedValue({}) });

expect(result).toEqual([
{
type: PropertyType.boolean,
value: true,
},
]);
});

test('%previous.exists().not() returns true for an empty %previous value', () => {
const patient: Patient = {
resourceType: 'Patient',
};
const result = evalFhirPathTyped('%previous.exists().not()', [toTypedValue(patient)], {
'%previous': toTypedValue({}),
});

expect(result).toEqual([
{
type: PropertyType.boolean,
value: true,
},
]);
});

test('Context type comparison false', () => {
const patient: Patient = {
resourceType: 'Patient',
Expand Down

0 comments on commit 7c9ce41

Please sign in to comment.