Skip to content

Commit 2ce3ed9

Browse files
Merge pull request #106 from cqframework/claude/cql-arithmetic-valuestring-support-yw8iqs
Support Long results returned as valueString in FHIR R4
2 parents 39d289e + a0ae4f3 commit 2ce3ed9

2 files changed

Lines changed: 53 additions & 0 deletions

File tree

src/shared/results-utils.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
1+
/**
2+
* Compares an expected CQL Long (parsed to a BigInt by cvl) against the actual value.
3+
* FHIR R4 has no integer64 type, so a Long result is returned as valueString and the
4+
* extracted actual is a string.
5+
*/
6+
function longEquals(expected: bigint, actual: any): boolean {
7+
if (typeof actual === 'bigint') {
8+
return expected === actual;
9+
}
10+
if (typeof actual === 'string') {
11+
// BigInt('') is 0n and BigInt trims whitespace, so require an integer literal.
12+
if (!/^[+-]?\d+$/.test(actual)) {
13+
return false;
14+
}
15+
return BigInt(actual) === expected;
16+
}
17+
return false;
18+
}
19+
120
/**
221
* Compares two results for equality, handling nested objects and numbers
322
*/
@@ -14,6 +33,10 @@ export function resultsEqual(expected: any, actual: any): boolean {
1433
return Math.abs(actual - expected) < 0.00000001;
1534
}
1635

36+
if (typeof expected === 'bigint') {
37+
return longEquals(expected, actual);
38+
}
39+
1740
if (expected === actual) {
1841
return true;
1942
}

test/results-utils.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,33 @@ test('equal lists (order-insensitive)', () => {
1717
test('nested structures compared key-wise', () => {
1818
expect(resultsEqual({ x: 1 }, { x: 1 })).toBe(true);
1919
});
20+
21+
test('expected Long matches FHIR R4 valueString encoding', () => {
22+
expect(resultsEqual(1n, '1')).toBe(true);
23+
expect(resultsEqual(-1n, '-1')).toBe(true);
24+
expect(resultsEqual(0n, '0')).toBe(true);
25+
expect(resultsEqual(9223372036854775807n, '9223372036854775807')).toBe(true);
26+
expect(resultsEqual(1n, '2')).toBe(false);
27+
});
28+
29+
test('expected Long matches bigint actuals but not numbers (valueInteger is not allowed)', () => {
30+
expect(resultsEqual(1n, 1n)).toBe(true);
31+
expect(resultsEqual(1n, 2n)).toBe(false);
32+
expect(resultsEqual(1n, 1)).toBe(false);
33+
expect(resultsEqual(1n, 1.5)).toBe(false);
34+
});
35+
36+
test('expected Long rejects non-integer strings', () => {
37+
expect(resultsEqual(1n, 'abc')).toBe(false);
38+
expect(resultsEqual(1n, '1.5')).toBe(false);
39+
expect(resultsEqual(0n, '')).toBe(false);
40+
expect(resultsEqual(0n, ' 0 ')).toBe(false);
41+
expect(resultsEqual(1n, null)).toBe(false);
42+
expect(resultsEqual(1n, undefined)).toBe(false);
43+
});
44+
45+
test('Long values compare inside lists and structures', () => {
46+
expect(resultsEqual([1n, 2n], ['1', '2'])).toBe(true);
47+
expect(resultsEqual({ x: 1n }, { x: '1' })).toBe(true);
48+
expect(resultsEqual([1n, 2n], ['1', '3'])).toBe(false);
49+
});

0 commit comments

Comments
 (0)