Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/datatypes/quantity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ export class Quantity {
}
return new Quantity(resultValue, resultUnit);
}

round(precision?: number) {
return new Quantity(this.value.round(precision), this.unit);
}
}

export function parseQuantity(str: string) {
Expand Down
3 changes: 3 additions & 0 deletions src/elm/arithmetic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,9 @@ export class Round extends Expression {
}

const dec = this.precision != null ? await this.precision.execute(ctx) : 0;
if (arg instanceof Quantity) {
return arg.round(dec);
}
return Decimal.from(arg).round(dec);
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/elm/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,26 @@ export class Matches extends Expression {
return null;
}

// "The Matches operator returns true if the given string matches the given regular expression pattern.
// Regular expressions should [...] use partial matching, use single line mode, and allow Unicode characters.
// The start/end of line markers ^ and $ can be used to match the entire string."
return new RegExp(pattern).test(string);
}
}

export class MatchesFull extends Expression {
constructor(json: any) {
super(json);
}

async exec(ctx: Context) {
const [string, pattern] = await this.execArgs(ctx);
if (string == null || pattern == null) {
return null;
}

// "The MatchesFull operator returns true when the value completely matches the given regular expression
// (implying that the start/end of line markers ^, $ are always surrounding the regex expression provided)."
return new RegExp('^' + pattern + '$').test(string);
}
}
Expand Down
15 changes: 15 additions & 0 deletions test/datatypes/quantity-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,21 @@ describe('Quantity', () => {
should(quantity1.dividedBy(quantity2)).be.null();
});

it('should allow rounding', () => {
const quantity = new Quantity(3.456, 'mg');
let result = quantity.round();
result.unit.should.equal('mg');
result.value.should.equalDecimal(3);

result = quantity.round(0);
result.unit.should.equal('mg');
result.value.should.equalDecimal(3);

result = quantity.round(1);
result.unit.should.equal('mg');
result.value.should.equalDecimal(3.5);
});

it('should convert units when possible to perform arithmetic', () => {
const divide = new Quantity(8, 'm').dividedBy(new Quantity(50, 'cm'));
divide.equals(new Quantity(16, '1')).should.be.true();
Expand Down
11 changes: 11 additions & 0 deletions test/elm/arithmetic/arithmetic-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,17 @@ describe('Round', () => {
(await this.roundNegativeHalfNullPrecision.exec(this.ctx)).should.equalDecimal(-2.0);
(await this.roundNegativeHalfZeroPrecision.exec(this.ctx)).should.equalDecimal(-2.0);
});

it('should support rounding Quantity values', async function () {
const quantityRound = await this.quantityRound.exec(this.ctx); // Round(2.54 'cm') --> 3 'cm'
validateQuantity(quantityRound, 3, 'cm');

const quantityRoundZero = await this.quantityRoundZero.exec(this.ctx); // Round(2.54 'cm', 0) --> 3 'cm'
validateQuantity(quantityRoundZero, 3, 'cm');

const quantityRoundOne = await this.quantityRoundOne.exec(this.ctx); // Round(2.54 'cm', 1) --> 2.5 'cm'
validateQuantity(quantityRoundOne, 2.5, 'cm');
});
});

describe('Successor', () => {
Expand Down
3 changes: 3 additions & 0 deletions test/elm/arithmetic/data.cql
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,9 @@ define RoundPositiveHalfZeroPrecision: Round(1.5, 0)
define RoundNegativeHalfOmittedPrecision: Round(-1.5)
define RoundNegativeHalfNullPrecision: Round(-1.5, null as Integer)
define RoundNegativeHalfZeroPrecision: Round(-1.5, 0)
define QuantityRound: Round(2.54 'cm') // 3 'cm'
define QuantityRoundZero: Round(2.54 'cm', 0) // 3 'cm'
define QuantityRoundOne: Round(2.54 'cm', 1) // 2.5 'cm'

// @Test: Ln
define ln: Ln(4)
Expand Down
148 changes: 147 additions & 1 deletion test/elm/arithmetic/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -13328,6 +13328,9 @@ define RoundPositiveHalfZeroPrecision: Round(1.5, 0)
define RoundNegativeHalfOmittedPrecision: Round(-1.5)
define RoundNegativeHalfNullPrecision: Round(-1.5, null as Integer)
define RoundNegativeHalfZeroPrecision: Round(-1.5, 0)
define QuantityRound: Round(2.54 'cm') // 3 'cm'
define QuantityRoundZero: Round(2.54 'cm', 0) // 3 'cm'
define QuantityRoundOne: Round(2.54 'cm', 1) // 2.5 'cm'
*/

module.exports['Round'] = {
Expand All @@ -13342,7 +13345,7 @@ module.exports['Round'] = {
"type" : "Annotation",
"t" : [ ],
"s" : {
"r" : "340",
"r" : "375",
"s" : [ {
"value" : [ "", "library TestSnippet version '1'" ]
} ]
Expand Down Expand Up @@ -14144,6 +14147,149 @@ module.exports['Round'] = {
"annotation" : [ ]
}
}
}, {
"localId" : "354",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Decimal",
"name" : "QuantityRound",
"context" : "Patient",
"accessLevel" : "Public",
"annotation" : [ {
"type" : "Annotation",
"t" : [ ],
"s" : {
"r" : "354",
"s" : [ {
"value" : [ "", "define ", "QuantityRound", ": " ]
}, {
"r" : "359",
"s" : [ {
"r" : "355",
"value" : [ "Round", "(", "2.54", ")" ]
} ]
} ]
}
} ],
"expression" : {
"type" : "Round",
"localId" : "359",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Quantity",
"annotation" : [ ],
"signature" : [ {
"type" : "NamedTypeSpecifier",
"localId" : "360",
"name" : "{urn:hl7-org:elm-types:r1}Quantity",
"annotation" : [ ]
} ],
"operand" : {
"type": "Quantity",
"value": 2.54,
"unit": "cm"
}
}
}, {
"localId" : "363",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Quantity",
"name" : "QuantityRoundZero",
"context" : "Patient",
"accessLevel" : "Public",
"annotation" : [ {
"type" : "Annotation",
"t" : [ ],
"s" : {
"r" : "363",
"s" : [ {
"value" : [ "// 3 'cm'\n", "define ", "QuantityRoundZero", ": " ]
}, {
"r" : "370",
"s" : [ {
"r" : "364",
"value" : [ "Round", "(", "2.54", ", ", "0", ")" ]
} ]
} ]
}
} ],
"expression" : {
"type" : "Round",
"localId" : "370",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Quantity",
"annotation" : [ ],
"signature" : [ {
"type" : "NamedTypeSpecifier",
"localId" : "371",
"name" : "{urn:hl7-org:elm-types:r1}Quantity",
"annotation" : [ ]
}, {
"type" : "NamedTypeSpecifier",
"localId" : "372",
"name" : "{urn:hl7-org:elm-types:r1}Integer",
"annotation" : [ ]
} ],
"operand" : {
"type": "Quantity",
"value": 2.54,
"unit": "cm"
},
"precision" : {
"type" : "Literal",
"localId" : "365",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Integer",
"valueType" : "{urn:hl7-org:elm-types:r1}Integer",
"value" : "0",
"annotation" : [ ]
}
}
}, {
"localId" : "375",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Quantity",
"name" : "QuantityRoundOne",
"context" : "Patient",
"accessLevel" : "Public",
"annotation" : [ {
"type" : "Annotation",
"t" : [ ],
"s" : {
"r" : "375",
"s" : [ {
"value" : [ "// 3 'cm'\n", "define ", "QuantityRoundOne", ": " ]
}, {
"r" : "382",
"s" : [ {
"r" : "376",
"value" : [ "Round", "(", "2.54", " , ", "1", ")" ]
} ]
} ]
}
} ],
"expression" : {
"type" : "Round",
"localId" : "382",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Quantity",
"annotation" : [ ],
"signature" : [ {
"type" : "NamedTypeSpecifier",
"localId" : "383",
"name" : "{urn:hl7-org:elm-types:r1}Quantity",
"annotation" : [ ]
}, {
"type" : "NamedTypeSpecifier",
"localId" : "384",
"name" : "{urn:hl7-org:elm-types:r1}Integer",
"annotation" : [ ]
} ],
"operand" : {
"type": "Quantity",
"value": 2.54,
"unit": "cm"
},
"precision" : {
"type" : "Literal",
"localId" : "377",
"resultTypeName" : "{urn:hl7-org:elm-types:r1}Integer",
"valueType" : "{urn:hl7-org:elm-types:r1}Integer",
"value" : "1",
"annotation" : [ ]
}
}
} ]
}
}
Expand Down
9 changes: 9 additions & 0 deletions test/elm/string/data.cql
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,19 @@ define NullIndex: 'HelloWorld'[null]
// @Test: Matches
define MatchesTrue: Matches('1,2three', '\\d,\\d\\w+')
define MatchesFalse: Matches('three', '\\d')
define MatchesPartial: Matches('12three', '\\d')
define MatchesIsNullFirst: Matches(null, '\\w+')
define MatchesIsNullSecond: Matches('12three', null)
define MatchesAllNull: Matches(null, null)

// @Test: MatchesFull
define MatchesTrue: MatchesFull('1,2three', '\\d,\\d\\w+')
define MatchesFalse: MatchesFull('three', '\\d')
define MatchesPartial: MatchesFull('12three', '\\d')
define MatchesIsNullFirst: MatchesFull(null, '\\w+')
define MatchesIsNullSecond: MatchesFull('12three', null)
define MatchesAllNull: MatchesFull(null, null)

// @Test: PositionOf
define Found: PositionOf('cde', 'abcdefg')
define NotFound: PositionOf('fgh', 'abcdefg')
Expand Down
Loading
Loading