From db0b1a010896d71d0ad4c9e9d6d66bf200cc1948 Mon Sep 17 00:00:00 2001 From: sedinkinya Date: Fri, 9 Oct 2020 18:17:02 -0400 Subject: [PATCH 1/3] Comparison of dates indicated with different level of precision LF-1490 --- CHANGELOG.md | 4 ++++ package-lock.json | 2 +- package.json | 2 +- src/equality.js | 40 ++++++++++++++++++++------------- src/types.js | 16 ++++++++----- test/cases/6.2_comparision.yaml | 12 +++++----- test/cases/6.6_math.yaml | 2 +- test/cases/fhir-r4.yaml | 18 --------------- 8 files changed, 47 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 975e4fd..b6e1620 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,10 @@ This log documents significant changes for each release. This project follows [Semantic Versioning](http://semver.org/). +## [2.6.2] - 2020-10-09 +### Fixed +- Comparison of dates indicated with different level of precision + ## [2.6.1] - 2020-09-22 ### Fixed - Module not found errors with TypeScript when importing json files diff --git a/package-lock.json b/package-lock.json index 4d7f753..8489d7e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "fhirpath", - "version": "2.6.1", + "version": "2.6.2", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 1638e26..f162466 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fhirpath", - "version": "2.6.1", + "version": "2.6.2", "description": "A FHIRPath engine", "main": "src/fhirpath.js", "dependencies": { diff --git a/src/equality.js b/src/equality.js index a10f1fb..8695ba5 100644 --- a/src/equality.js +++ b/src/equality.js @@ -80,34 +80,42 @@ function typecheck(a, b){ engine.lt = function(a, b){ if (!a.length || !b.length) return []; - var vals = typecheck(a,b); - var a0 = vals[0]; - var b0 = vals[1]; - return a0 instanceof FP_Type ? a0.compare(b0) == -1 : a0 < b0; + const [a0, b0] = typecheck(a,b); + if (a0 instanceof FP_Type) { + const compare = a0.compare(b0); + return compare === null ? [] : compare < 0; + } + return a0 < b0; }; engine.gt = function(a, b){ if (!a.length || !b.length) return []; - var vals = typecheck(a,b); - var a0 = vals[0]; - var b0 = vals[1]; - return a0 instanceof FP_Type ? a0.compare(b0) == 1 : a0 > b0; + const [a0, b0] = typecheck(a,b); + if (a0 instanceof FP_Type) { + const compare = a0.compare(b0); + return compare === null ? [] : compare > 0; + } + return a0 > b0; }; engine.lte = function(a, b){ if (!a.length || !b.length) return []; - var vals = typecheck(a,b); - var a0 = vals[0]; - var b0 = vals[1]; - return a0 instanceof FP_Type ? a0.compare(b0) <= 0 : a0 <= b0; + const [a0, b0] = typecheck(a,b); + if (a0 instanceof FP_Type) { + const compare = a0.compare(b0); + return compare === null ? [] : compare <= 0; + } + return a0 <= b0; }; engine.gte = function(a, b){ if (!a.length || !b.length) return []; - var vals = typecheck(a,b); - var a0 = vals[0]; - var b0 = vals[1]; - return a0 instanceof FP_Type ? a0.compare(b0) >= 0 : a0 >= b0; + const [a0, b0] = typecheck(a,b); + if (a0 instanceof FP_Type) { + const compare = a0.compare(b0); + return compare === null ? [] : compare >= 0; + } + return a0 >= b0; }; diff --git a/src/types.js b/src/types.js index 371d3f1..6beec77 100644 --- a/src/types.js +++ b/src/types.js @@ -472,8 +472,10 @@ class FP_TimeBase extends FP_Type { this._getDateObj().getTime(): this._dateAtPrecision(otherPrecision).getTime(); var otherTimeInt = otherPrecision <= thisPrecision ? otherTime._getDateObj().getTime(): otherTime._dateAtPrecision(thisPrecision).getTime(); - return thisTimeInt < otherTimeInt ? - -1 : thisTimeInt === otherTimeInt ? 0 : 1; + if (thisPrecision !== otherPrecision && thisTimeInt === otherTimeInt) { + return null; + } + return thisTimeInt - otherTimeInt; } @@ -640,7 +642,7 @@ class FP_DateTime extends FP_TimeBase { * Also sets this.precision. */ _getMatchData() { - return super._getMatchData(dateTimeRE, 6); + return super._getMatchData(dateTimeRE, 5); } /** @@ -696,7 +698,8 @@ class FP_DateTime extends FP_TimeBase { var hour = thisPrecision > 2 ? parseInt(timeParts[3]) : 0; var minutes = thisPrecision > 3 ? parseInt(timeParts[4].slice(1)): 0; var seconds = thisPrecision > 4 ? parseInt(timeParts[5].slice(1)): 0; - var ms = thisPrecision > 5 ? parseInt(timeParts[6].slice(1)): 0; + var ms = thisPrecision > 4 && timeParts.length > 6 ? + parseInt(timeParts[6].slice(1)): 0; var d = this._createDate(year, month, day, hour, minutes, seconds, ms, timezoneOffset); if (precision < this._getPrecision()) { @@ -792,7 +795,8 @@ class FP_Time extends FP_TimeBase { var hour = parseInt(timeParts[0]); var minutes = thisPrecision > 0 ? parseInt(timeParts[1].slice(1)): 0; var seconds = thisPrecision > 1 ? parseInt(timeParts[2].slice(1)): 0; - var ms = thisPrecision > 2 ? parseInt(timeParts[3].slice(1)): 0; + var ms = thisPrecision > 1 && timeParts.length > 3 ? + parseInt(timeParts[3].slice(1)): 0; var d = this._createDate(year, month, day, hour, minutes, seconds, ms, timezoneOffset); if (timezoneOffset) { @@ -819,7 +823,7 @@ class FP_Time extends FP_TimeBase { * Also sets this.precision. */ _getMatchData() { - return super._getMatchData(timeRE, 3); + return super._getMatchData(timeRE, 2); } /** diff --git a/test/cases/6.2_comparision.yaml b/test/cases/6.2_comparision.yaml index 299d351..015f0c9 100644 --- a/test/cases/6.2_comparision.yaml +++ b/test/cases/6.2_comparision.yaml @@ -106,7 +106,7 @@ tests: error: true - desc: Comparison based on the lesser precision (1) expression: '@2018-12-31 > @2018' - result: [false] + result: [] - desc: Comparison based on the lesser precision (2) expression: '@2018 > @2017-01' result: [true] @@ -170,7 +170,7 @@ tests: result: [false] - desc: Comparison with differnet precision (1) expression: '@2018-12-20T12 > @2018-12-20T12:01' - result: [false] + result: [] - desc: Comparison with differnet precision (2) expression: '@2018-12-20T12 > @2018-12-20T11:01' result: [true] @@ -190,9 +190,9 @@ tests: expression: '@2018-12-21T12:02+02:00 > dateTime' result: [false] - expression: '@2020-08-04T12:34-04:00 < @2020T-04:00' - result: [false] + result: [] - expression: '@2020-08-04T12:34 < @2020' - result: [false] + result: [] - 'group: Time': - desc: Time comparison; GT (1) expression: '@T12:03 > @T12:01' @@ -205,7 +205,7 @@ tests: result: [true] - desc: Time comparison with based on lesser precision (1) expression: '@T12:01 > @T12' - result: [false] + result: [] - desc: Time comparison with based on lesser precision (2) expression: '@T12:02:34.324 > @T12:01' result: [true] @@ -214,7 +214,7 @@ tests: result: [true] - desc: Time comparison with based on lesser precision (4) expression: '@T12:02:34.324+05:00 > @T12+05:00' - result: [false] + result: [] - desc: Comparison with later time in resource (1) expression: '@T17:00-05:00 < timeWithT' result: [true] diff --git a/test/cases/6.6_math.yaml b/test/cases/6.6_math.yaml index 860436b..4adb7c2 100644 --- a/test/cases/6.6_math.yaml +++ b/test/cases/6.6_math.yaml @@ -164,7 +164,7 @@ tests: - expression: "@T09:45:23 + 2 years" error: true - expression: "@T09:45:23Z + 2 minutes = @T04:47:23.000-05:00" - result: [] + result: [true] - expression: "@T23:59:23Z + 2 minutes = @T00:01:23Z" result: [true] - expression: "@T23:59:23-05:00 + 2 minutes = @T00:01:23-05:00" diff --git a/test/cases/fhir-r4.yaml b/test/cases/fhir-r4.yaml index f994322..91d565a 100644 --- a/test/cases/fhir-r4.yaml +++ b/test/cases/fhir-r4.yaml @@ -1850,13 +1850,11 @@ tests: expression: '@2012-04-15T15:30:31 = @2012-04-15T15:30:31.0' result: - true - disable: true - desc: '** testEquality22' inputfile: patient-example.json expression: '@2012-04-15T15:30:31 = @2012-04-15T15:30:31.1' result: - false - disable: true - desc: '** testEquality23' inputfile: patient-example.json expression: '@2012-04-15T15:00:00Z = @2012-04-15T10:00:00' @@ -1962,13 +1960,11 @@ tests: expression: '@2012-04-15T15:30:31 != @2012-04-15T15:30:31.0' result: - false - disable: true - desc: '** testNEquality16' inputfile: patient-example.json expression: '@2012-04-15T15:30:31 != @2012-04-15T15:30:31.1' result: - true - disable: true - desc: '** testNEquality17' inputfile: patient-example.json expression: '@2012-04-15T15:00:00Z != @2012-04-15T10:00:00' @@ -2097,7 +2093,6 @@ tests: expression: '@2012-04-15T15:30:31 ~ @2012-04-15T15:30:31.0' result: - true - disable: true - desc: '** testEquivalent18' inputfile: patient-example.json expression: '@2012-04-15T15:30:31 ~ @2012-04-15T15:30:31.1' @@ -2216,7 +2211,6 @@ tests: expression: '@2012-04-15T15:30:31 !~ @2012-04-15T15:30:31.0' result: - false - disable: true - desc: '** testNotEquivalent18' inputfile: patient-example.json expression: '@2012-04-15T15:30:31 !~ @2012-04-15T15:30:31.1' @@ -2365,17 +2359,14 @@ tests: inputfile: patient-example.json expression: '@2018-03 < @2018-03-01' result: [] - disable: true - desc: '** testLessThan24' inputfile: patient-example.json expression: '@2018-03-01T10 < @2018-03-01T10:30' result: [] - disable: true - desc: '** testLessThan25' inputfile: patient-example.json expression: '@T10 < @T10:30' result: [] - disable: true - desc: '** testLessThan26' inputfile: patient-example.json expression: '@2018-03-01T10:30:00 < @2018-03-01T10:30:00.0' @@ -2502,17 +2493,14 @@ tests: inputfile: patient-example.json expression: '@2018-03 <= @2018-03-01' result: [] - disable: true - desc: '** testLessOrEqual24' inputfile: patient-example.json expression: '@2018-03-01T10 <= @2018-03-01T10:30' result: [] - disable: true - desc: '** testLessOrEqual25' inputfile: patient-example.json expression: '@T10 <= @T10:30' result: [] - disable: true - desc: '** testLessOrEqual26' inputfile: patient-example.json expression: '@2018-03-01T10:30:00 <= @2018-03-01T10:30:00.0' @@ -2639,17 +2627,14 @@ tests: inputfile: patient-example.json expression: '@2018-03 >= @2018-03-01' result: [] - disable: true - desc: '** testGreatorOrEqual24' inputfile: patient-example.json expression: '@2018-03-01T10 >= @2018-03-01T10:30' result: [] - disable: true - desc: '** testGreatorOrEqual25' inputfile: patient-example.json expression: '@T10 >= @T10:30' result: [] - disable: true - desc: '** testGreatorOrEqual26' inputfile: patient-example.json expression: '@2018-03-01T10:30:00 >= @2018-03-01T10:30:00.0' @@ -2776,17 +2761,14 @@ tests: inputfile: patient-example.json expression: '@2018-03 > @2018-03-01' result: [] - disable: true - desc: '** testGreaterThan24' inputfile: patient-example.json expression: '@2018-03-01T10 > @2018-03-01T10:30' result: [] - disable: true - desc: '** testGreaterThan25' inputfile: patient-example.json expression: '@T10 > @T10:30' result: [] - disable: true - desc: '** testGreaterThan26' inputfile: patient-example.json expression: '@2018-03-01T10:30:00 > @2018-03-01T10:30:00.0' From 7af824dd583b95da7c87fc80552195d2312c3633 Mon Sep 17 00:00:00 2001 From: sedinkinya Date: Fri, 16 Oct 2020 15:02:21 -0400 Subject: [PATCH 2/3] Refactoring of comparison of dates indicated with different level of precision LF-1490 --- src/types.js | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/src/types.js b/src/types.js index 6beec77..7a92dda 100644 --- a/src/types.js +++ b/src/types.js @@ -461,9 +461,11 @@ class FP_TimeBase extends FP_Type { /** - * Returns -1, 0, or 1 if this (date) time is less then, equal to, or greater - * than otherTime. Comparisons are made at the lesser of the two time - * precisions. + * Returns a number less than 0, equal to 0 or greater than 0 + * if this (date) time is less than, equal to, or greater than otherTime. + * Comparisons are made at the lesser of the two time precisions. + * @param {FP_TimeBase} otherTime + * @return {number} */ compare(otherTime) { var thisPrecision = this._getPrecision(); @@ -483,7 +485,9 @@ class FP_TimeBase extends FP_Type { * Returns a number representing the precision of the time string given to * the constructor. (Higher means more precise). The number is the number * of components of the time string (ignoring the time zone) produced by - * matching against the time regular expression. + * matching against the time regular expression, except that milliseconds + * and seconds are counted together as a single of level of precision. + * @return {number} */ _getPrecision() { if (this.precision === undefined) @@ -698,20 +702,19 @@ class FP_DateTime extends FP_TimeBase { var hour = thisPrecision > 2 ? parseInt(timeParts[3]) : 0; var minutes = thisPrecision > 3 ? parseInt(timeParts[4].slice(1)): 0; var seconds = thisPrecision > 4 ? parseInt(timeParts[5].slice(1)): 0; - var ms = thisPrecision > 4 && timeParts.length > 6 ? - parseInt(timeParts[6].slice(1)): 0; + var ms = timeParts.length > 6 ? parseInt(timeParts[6].slice(1)): 0; var d = this._createDate(year, month, day, hour, minutes, seconds, ms, timezoneOffset); - if (precision < this._getPrecision()) { + if (precision < thisPrecision) { // Adjust the precision year = d.getFullYear(); month = precision > 0 ? d.getMonth() : 0; day = precision > 1 ? d.getDate() : 1; hour = precision > 2 ? d.getHours() : 0; minutes = precision > 3 ? d.getMinutes(): 0; - seconds = precision > 4 ? d.getSeconds(): 0; - ms = precision > 5 ? d.getMilliseconds(): 0; - d = new Date(year, month, day, hour, minutes, seconds, ms); + // Here the precision will always be less than the maximum + // due to the condition in the if statement: "precision < thisPrecision" + d = new Date(year, month, day, hour, minutes); } return d; } @@ -795,8 +798,7 @@ class FP_Time extends FP_TimeBase { var hour = parseInt(timeParts[0]); var minutes = thisPrecision > 0 ? parseInt(timeParts[1].slice(1)): 0; var seconds = thisPrecision > 1 ? parseInt(timeParts[2].slice(1)): 0; - var ms = thisPrecision > 1 && timeParts.length > 3 ? - parseInt(timeParts[3].slice(1)): 0; + var ms = timeParts.length > 3 ? parseInt(timeParts[3].slice(1)): 0; var d = this._createDate(year, month, day, hour, minutes, seconds, ms, timezoneOffset); if (timezoneOffset) { @@ -806,13 +808,13 @@ class FP_Time extends FP_TimeBase { d.setMonth(month); d.setDate(day); } - if (precision < this._getPrecision()) { + if (precision < thisPrecision) { // Adjust the precision hour = d.getHours(); minutes = precision > 0 ? d.getMinutes(): 0; - seconds = precision > 1 ? d.getSeconds(): 0; - ms = precision > 2 ? d.getMilliseconds(): 0; - d = new Date(year, month, day, hour, minutes, seconds, ms); + // Here the precision will always be less than the maximum + // due to the condition in the if statement: "precision < thisPrecision" + d = new Date(year, month, day, hour, minutes); } return d; } From 0694c11e1cf26b5c363beb981b6014926808e742 Mon Sep 17 00:00:00 2001 From: sedinkinya Date: Mon, 19 Oct 2020 13:05:38 -0400 Subject: [PATCH 3/3] npm audit fix --- demo/package-lock.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/demo/package-lock.json b/demo/package-lock.json index a40c413..5b025e5 100644 --- a/demo/package-lock.json +++ b/demo/package-lock.json @@ -4665,9 +4665,9 @@ } }, "node-forge": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.9.0.tgz", - "integrity": "sha512-7ASaDa3pD+lJ3WvXFsxekJQelBKRpne+GOVbLbtHYdd7pFspyeuJHnWfLplGf3SwKGbfs/aYl5V/JCIaHVUKKQ==", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", "dev": true }, "node-libs-browser": { @@ -5977,12 +5977,12 @@ "dev": true }, "selfsigned": { - "version": "1.10.7", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.7.tgz", - "integrity": "sha512-8M3wBCzeWIJnQfl43IKwOmC4H/RAp50S8DF60znzjW5GVqTcSe2vWclt7hmYVPkKPlHWOu5EaWOMZ2Y6W8ZXTA==", + "version": "1.10.8", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.8.tgz", + "integrity": "sha512-2P4PtieJeEwVgTU9QEcwIRDQ/mXJLX8/+I3ur+Pg16nS8oNbrGxEso9NyYWy8NAmXiNl4dlAp5MwoNeCWzON4w==", "dev": true, "requires": { - "node-forge": "0.9.0" + "node-forge": "^0.10.0" } }, "semver": {