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
354 changes: 182 additions & 172 deletions examples/browser/cql4browsers.js

Large diffs are not rendered by default.

66 changes: 60 additions & 6 deletions src/datatypes/interval.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,20 +78,23 @@ export class Interval {
newHigh = this.high.copy();
}

return new Interval(newLow, newHigh, this.lowClosed, this.highClosed);
return new Interval(newLow, newHigh, this.lowClosed, this.highClosed, this.defaultPointType);
}

contains(item: any, precision?: any) {
// These first two checks ensure correct handling of edge case where an item equals the closed boundary
if (item != null && item.isInterval) {
throw new Error('Argument to contains must be a point');
}
if (this.isBoundlessInterval) {
return true;
}
// Ensure correct handling of edge case where an item equals the closed boundary
if (this.lowClosed && this.low != null && cmp.equals(this.low, item)) {
return true;
}
if (this.highClosed && this.high != null && cmp.equals(this.high, item)) {
return true;
}
if (item != null && item.isInterval) {
throw new Error('Argument to contains must be a point');
}
let lowFn;
if (this.lowClosed && this.low == null) {
lowFn = () => true;
Expand Down Expand Up @@ -125,6 +128,11 @@ export class Interval {
}

includes(other: any, precision?: any) {
if (this.isBoundlessInterval) {
return true;
} else if (other?.isBoundlessInterval) {
return this.isUnknownInterval ? null : false;
}
if (other == null || !other.isInterval) {
return this.contains(other, precision);
}
Expand Down Expand Up @@ -204,6 +212,11 @@ export class Interval {
if (other == null || !other.isInterval) {
throw new Error('Argument to union must be an interval');
}
if (this.isBoundlessInterval) {
return this.copy();
} else if (other.isBoundlessInterval) {
return other.copy();
}
// Note that interval union is only defined if the arguments overlap or meet.
if (this.overlaps(other) || this.meets(other)) {
const [a, b] = [this.toClosed(), other.toClosed()];
Expand Down Expand Up @@ -243,7 +256,12 @@ export class Interval {
if (other == null || !other.isInterval) {
throw new Error('Argument to union must be an interval');
}
// Note that interval union is only defined if the arguments overlap.
if (this.isBoundlessInterval) {
return other.copy();
} else if (other.isBoundlessInterval) {
return this.copy();
}
// Note that interval intersect is only defined if the arguments overlap.
if (this.overlaps(other)) {
const [a, b] = [this.toClosed(), other.toClosed()];
let l, lc;
Expand Down Expand Up @@ -385,6 +403,9 @@ export class Interval {
}

sameOrBefore(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't wrap my head around this one. This returns true if both intervals are boundless. SameOrBefore says true if the ending point of the first interval is less than or equal to the starting point of the second interval, which would not be true for both intervals boundless.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct. I think that in my head I was thinking "the intervals are the same, therefore same or before is true". But you're right, the intent is that the end of interval 1 is the same as the start of interval 2, not that the two intervals themselves are the same. Thanks for catching this.

return this.equals(other);
}
if (this.end() == null || other == null || other.start() == null) {
return null;
} else {
Expand All @@ -393,6 +414,9 @@ export class Interval {
}

sameOrAfter(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup. Good catch.

return this.equals(other);
}
if (this.start() == null || other == null || other.end() == null) {
return null;
} else {
Expand All @@ -402,6 +426,11 @@ export class Interval {

equals(other: any) {
if (other != null && other.isInterval) {
if (this.isBoundlessInterval) {
return other.isBoundlessInterval ? true : other.isUnknownInterval ? null : false;
} else if (other.isBoundlessInterval) {
return this.isUnknownInterval ? null : false;
}
const [a, b] = [this.toClosed(), other.toClosed()];
return ThreeValuedLogic.and(cmp.equals(a.low, b.low), cmp.equals(a.high, b.high));
} else {
Expand All @@ -410,6 +439,9 @@ export class Interval {
}

after(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {
return false;
}
const closed = this.toClosed();
// Meets spec, but not 100% correct (e.g., (null, 5] after [6, 10] --> null)
// Simple way to fix it: and w/ not overlaps
Expand All @@ -421,6 +453,9 @@ export class Interval {
}

before(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {
return false;
}
const closed = this.toClosed();
// Meets spec, but not 100% correct (e.g., (null, 5] after [6, 10] --> null)
// Simple way to fix it: and w/ not overlaps
Expand All @@ -432,13 +467,19 @@ export class Interval {
}

meets(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {
return false;
}
return ThreeValuedLogic.or(
this.meetsBefore(other, precision),
this.meetsAfter(other, precision)
);
}

meetsAfter(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {
return false;
}
try {
if (precision != null && this.low != null && this.low.isDateTime) {
return this.toClosed().low.sameAs(
Expand All @@ -454,6 +495,9 @@ export class Interval {
}

meetsBefore(other: any, precision?: any) {
if (this.isBoundlessInterval || other?.isBoundlessInterval) {
return false;
}
try {
if (precision != null && this.high != null && this.high.isDateTime) {
return this.toClosed().high.sameAs(
Expand Down Expand Up @@ -491,6 +535,11 @@ export class Interval {
}

starts(other: any, precision?: any) {
if (this.isBoundlessInterval) {
return other.isBoundlessInterval ? true : other.isUnknownInterval ? null : false;
} else if (other?.isBoundlessInterval) {
return this.isUnknownInterval ? null : false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should return true if the starting point of the first is equal to the starting point of the second interval and the ending point of the first interval is less than or equal to the ending point of the second interval. If other is boundless, then I believe we should return true if this interval starts at minimumValue (e.g. Interval[null, 0] or Interval[minValue, 0] ).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are correct.

}
let startEqual;
if (precision != null && this.low != null && this.low.isDateTime) {
startEqual = this.low.sameAs(other.low, precision);
Expand All @@ -502,6 +551,11 @@ export class Interval {
}

ends(other: any, precision?: any) {
if (this.isBoundlessInterval) {
return other.isBoundlessInterval ? true : other.isUnknownInterval ? null : false;
} else if (other?.isBoundlessInterval) {
return this.isUnknownInterval ? null : false;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, if other is boundless, the I believe we should return true is this interval ends at the maximum value (e.g. Interval[0,null] or Interval[0, maxValue] ).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think I missed this one too.

}
let endEqual;
const startGreaterThanOrEqual = cmp.greaterThanOrEquals(this.low, other.low, precision);
if (precision != null && (this.low != null ? this.low.isDateTime : undefined)) {
Expand Down
Loading
Loading