Repository navigation
Implement Modulo for Quantity arguments - #393
Conversation
Add Quantity.modulo, used by Modulo when either operand is a Quantity. Compatible units are converted first; a null or zero divisor, or units that can't be matched, give null. Re-enable the ModuloQuantity and Modulo10By3Quantity spec tests. Fixes cqframework#386
| // The remainder only makes sense when both sides end up in the same unit | ||
| if (unit1 !== unit2) { | ||
| return null; | ||
| } |
There was a problem hiding this comment.
One case this doesn't handle yet: a unitless divisor. 10.0 'g' mod 3 returns null, because the 3 becomes 3 '1' and 'g' and '1' don't normalize to the same unit.
FHIR-59659 (div and mod result units) says the remainder has "the same units as its operands after converting to common units in the same way as for division". A '1' divisor has no dimension to convert, and division keeps the dividend's unit (10.0 'g' / 3 is 3.33 'g'), so the remainder should be 1.0 'g'. The Java engine already returns that. The test is Modulo10GBy3Quantity in cqframework/cql-tests#167, which also updates the mixed-unit Modulo tests to expect 10.0 'cm' and 100.0 'g'. Those already pass with this PR, since normalizeUnitsWhenPossible converts to the smaller unit.
Suggested change in src/datatypes/quantity.ts:
| // The remainder only makes sense when both sides end up in the same unit | |
| if (unit1 !== unit2) { | |
| return null; | |
| } | |
| // The remainder only makes sense when both sides end up in the same unit, except that a | |
| // unitless divisor has no dimension to convert, so the remainder keeps the dividend's unit | |
| // (10 'g' mod 3 is 1 'g', as 10 'g' / 3 is 3.33 'g') | |
| if (unit1 !== unit2 && unit2 !== '1') { | |
| return null; | |
| } |
And a test for test/datatypes/quantity-test.ts:
it('should keep the unit of the dividend for modulo by a unitless value', () => {
const result = new Quantity(10.0, 'g').modulo(3);
result.unit.should.equal('g');
result.value.should.equalDecimal(1);
new Quantity(10.0, 'g')
.modulo(new Quantity(3, '1'))
.equals(new Quantity(1, 'g'))
.should.be.true();
});With both on top of this branch, npm test gives 5457 passing and 97 pending, one more passing than the branch alone. npm run lint, npm run prettier and tsc --noEmit are clean.
There was a problem hiding this comment.
Applied your change so a unitless divisor keeps the dividend's unit, and added the 10.0 'g' mod 3 test. Suite is green, 5457 passing.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #393 +/- ##
==========================================
- Coverage 89.19% 89.17% -0.03%
==========================================
Files 60 60
Lines 5064 5080 +16
Branches 1446 1453 +7
==========================================
+ Hits 4517 4530 +13
- Misses 315 317 +2
- Partials 232 233 +1 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Fixes #386.
The CQL spec defines mod for Quantity values (3.5 'cm' mod 3 'cm' is 0.5 'cm'), but cql-execution only handled Integer, Long and Decimal, so a Quantity mod returned a wrong value. The two spec tests for it (ModuloQuantity and Modulo10By3Quantity) were on the skip list as "Modulo not implemented for Quantity".
What I changed:
This follows the approach suggested in the issue.
Local results:
Pull requests into cql-execution require the following.
Submitter and reviewer should ✔ when done.
For items that are not-applicable, mark "N/A" and ✔.
Submitter:
npm run checkto run tests, lint, and prettier)Reviewer:
Name: