Skip to content

Commit e8dddb1

Browse files
authored
Implement Interval PointFrom operator (#371)
* Implements Interval PointFrom operator * Skips incorrect TestPointFromNull cql-test
1 parent 64cfe9b commit e8dddb1

11 files changed

Lines changed: 1328 additions & 46 deletions

File tree

examples/browser/cql4browsers.js

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2412,6 +2412,13 @@ class Interval {
24122412
return new Interval(this.low, this.high, lowClosed, highClosed);
24132413
}
24142414
}
2415+
pointFrom() {
2416+
const start = this.start();
2417+
if (cmp.equals(start, this.end())) {
2418+
return start;
2419+
}
2420+
throw new Error('PointFrom operator may only be used on an interval containing a single point.');
2421+
}
24152422
toString() {
24162423
const start = this.lowClosed ? '[' : '(';
24172424
const end = this.highClosed ? ']' : ')';
@@ -5085,7 +5092,7 @@ var __importStar = (this && this.__importStar) || (function () {
50855092
};
50865093
})();
50875094
Object.defineProperty(exports, "__esModule", { value: true });
5088-
exports.Collapse = exports.Expand = exports.Ends = exports.Starts = exports.End = exports.Start = exports.Size = exports.Width = exports.OverlapsBefore = exports.OverlapsAfter = exports.Overlaps = exports.MeetsBefore = exports.MeetsAfter = exports.Meets = exports.Interval = void 0;
5095+
exports.Collapse = exports.Expand = exports.Ends = exports.Starts = exports.End = exports.Start = exports.Size = exports.Width = exports.PointFrom = exports.OverlapsBefore = exports.OverlapsAfter = exports.Overlaps = exports.MeetsBefore = exports.MeetsAfter = exports.Meets = exports.Interval = void 0;
50895096
exports.doContains = doContains;
50905097
exports.doProperContains = doProperContains;
50915098
exports.doIncludes = doIncludes;
@@ -5263,6 +5270,19 @@ class OverlapsBefore extends expression_1.Expression {
52635270
}
52645271
}
52655272
exports.OverlapsBefore = OverlapsBefore;
5273+
class PointFrom extends expression_1.Expression {
5274+
constructor(json) {
5275+
super(json);
5276+
}
5277+
async exec(ctx) {
5278+
const interval = await this.arg?.execute(ctx);
5279+
if (interval == null) {
5280+
return null;
5281+
}
5282+
return interval.pointFrom();
5283+
}
5284+
}
5285+
exports.PointFrom = PointFrom;
52665286
// Delegated to by overloaded#Union
52675287
function doUnion(a, b) {
52685288
return a.union(b);

src/datatypes/interval.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,17 @@ export class Interval {
647647
}
648648
}
649649

650+
pointFrom() {
651+
const start = this.start();
652+
if (cmp.equals(start, this.end())) {
653+
return start;
654+
}
655+
656+
throw new Error(
657+
'PointFrom operator may only be used on an interval containing a single point.'
658+
);
659+
}
660+
650661
toString() {
651662
const start = this.lowClosed ? '[' : '(';
652663
const end = this.highClosed ? ']' : ')';

src/elm/interval.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,20 @@ export class OverlapsBefore extends Expression {
200200
}
201201
}
202202

203+
export class PointFrom extends Expression {
204+
constructor(json: any) {
205+
super(json);
206+
}
207+
208+
async exec(ctx: Context) {
209+
const interval = await this.arg?.execute(ctx);
210+
if (interval == null) {
211+
return null;
212+
}
213+
return interval.pointFrom();
214+
}
215+
}
216+
203217
// Delegated to by overloaded#Union
204218
export function doUnion(a: any, b: any) {
205219
return a.union(b);

test/datatypes/interval-data.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,10 @@ export default () => {
8989
DateTime.parse('2012-01-01T00:00:00.0'),
9090
DateTime.parse('2012-07-01T00:00:00.0')
9191
);
92+
data['unitIvl'] = new TestInterval(
93+
DateTime.parse('2012-01-01T00:00:00.0'),
94+
DateTime.parse('2012-01-01T00:00:00.0')
95+
);
9296
data['bef2012'] = TestDateTime.parse('2011-06-01T00:00:00.0');
9397
data['beg2012'] = TestDateTime.parse('2012-01-01T00:00:00.0');
9498
data['mid2012'] = TestDateTime.parse('2012-06-01T00:00:00.0');

test/datatypes/interval-test.ts

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1933,6 +1933,83 @@ describe('DateTimeInterval', () => {
19331933
x.toYear.meetsBefore(y.closed).should.be.false();
19341934
});
19351935
});
1936+
1937+
describe('pointFrom', () => {
1938+
it('should return the point value for a unit interval', () => {
1939+
const point = DateTime.parse('2012-01-01T00:00:00.0+00');
1940+
const ivl = new Interval(point, point);
1941+
1942+
ivl.pointFrom().should.eql(point);
1943+
});
1944+
1945+
it('should throw on pointFrom call if not a unit interval', () => {
1946+
const ivl = new Interval(
1947+
DateTime.parse('2012-01-01T00:00:00.0+00'),
1948+
DateTime.parse('2025-01-01T00:00:00.0+00')
1949+
);
1950+
should(() => ivl.pointFrom()).throw(Error);
1951+
});
1952+
1953+
it('should return the point value for a unit interval with open low bound', () => {
1954+
const point = DateTime.parse('2012-01-01T00:00:00.0+00');
1955+
const ivl = new Interval(point.predecessor(), point, false, true);
1956+
1957+
ivl.pointFrom().should.eql(point);
1958+
});
1959+
1960+
it('should return the point value for a unit interval with open high bound', () => {
1961+
const point = DateTime.parse('2012-01-01T00:00:00.0+00');
1962+
const ivl = new Interval(point, point.successor(), true, false);
1963+
1964+
ivl.pointFrom().should.eql(point);
1965+
});
1966+
1967+
it('should throw for a non-unit interval with closed high bound', () => {
1968+
const point = DateTime.parse('2012-01-01T00:00:00.0+00');
1969+
const ivl = new Interval(point, point.successor(), true, true);
1970+
1971+
should(() => ivl.pointFrom()).throw(Error);
1972+
});
1973+
1974+
it('should return the value for a unit interval with null (max) high bound', () => {
1975+
const ivl = new Interval(MAX_DATETIME_VALUE, null);
1976+
1977+
ivl.pointFrom().should.eql(MAX_DATETIME_VALUE);
1978+
});
1979+
1980+
it('should return the value for a unit interval with null (min) low bound', () => {
1981+
const ivl = new Interval(null, MIN_DATETIME_VALUE);
1982+
1983+
ivl.pointFrom().should.eql(MIN_DATETIME_VALUE);
1984+
});
1985+
1986+
it('should return the point value for a unit interval with limited precision', () => {
1987+
const point = DateTime.parse('2012-01-01');
1988+
const ivl = new Interval(point, point);
1989+
1990+
ivl.pointFrom().should.eql(point);
1991+
});
1992+
1993+
it('should throw for an interval with closed null high bound', function () {
1994+
const ivl = new Interval(DateTime.parse('2012-01-01T00:00:00.0+00'), null);
1995+
should(() => ivl.pointFrom()).throw(Error);
1996+
});
1997+
1998+
it('should throw for an interval with open null high bound', function () {
1999+
const ivl = new Interval(DateTime.parse('2012-01-01T00:00:00.0+00'), null, true, false);
2000+
should(() => ivl.pointFrom()).throw(Error);
2001+
});
2002+
2003+
it('should throw for an interval with closed null low bound', function () {
2004+
const ivl = new Interval(null, DateTime.parse('2012-01-01T00:00:00.0+00'));
2005+
should(() => ivl.pointFrom()).throw(Error);
2006+
});
2007+
2008+
it('should throw for an interval with open null low bound', function () {
2009+
const ivl = new Interval(null, DateTime.parse('2012-01-01T00:00:00.0+00'), false, true);
2010+
should(() => ivl.pointFrom()).throw(Error);
2011+
});
2012+
});
19362013
});
19372014

19382015
describe('IntegerInterval', () => {
@@ -3713,6 +3790,43 @@ describe('IntegerInterval', () => {
37133790
uIvl.meetsBefore(uIvl).should.be.false();
37143791
});
37153792
});
3793+
3794+
describe('pointFrom', () => {
3795+
it('should return the point value for a unit interval', () => {
3796+
const ivl = new Interval(0, 0);
3797+
ivl.pointFrom().should.eql(0);
3798+
});
3799+
3800+
it('should throw on pointFrom call if not a unit interval', () => {
3801+
const ivl = new Interval(0, 1);
3802+
should(() => ivl.pointFrom()).throw(Error);
3803+
});
3804+
3805+
it('should return the point value for a unit interval', () => {
3806+
const ivl = new Interval(12, 12);
3807+
ivl.pointFrom().should.eql(12);
3808+
});
3809+
3810+
it('should throw on pointFrom call if not a unit interval', () => {
3811+
const ivl = new Interval(8, 9);
3812+
should(() => ivl.pointFrom()).throw(Error);
3813+
});
3814+
3815+
it('should return the point from an interval with an open high bound', async function () {
3816+
const ivl = new Interval(100, 101, true, false);
3817+
ivl.pointFrom().should.eql(100);
3818+
});
3819+
3820+
it('should throw for an interval with null high bound', function () {
3821+
const ivl = new Interval(23, null);
3822+
should(() => ivl.pointFrom()).throw(Error);
3823+
});
3824+
3825+
it('should throw for an interval with undefined width', function () {
3826+
const ivl = new Interval(0, 0, false, false);
3827+
should(() => ivl.pointFrom()).throw(Error);
3828+
});
3829+
});
37163830
});
37173831

37183832
describe('LongInterval', () => {
@@ -5493,6 +5607,33 @@ describe('LongInterval', () => {
54935607
uIvl.meetsBefore(uIvl).should.be.false();
54945608
});
54955609
});
5610+
5611+
describe('pointFrom', () => {
5612+
it('should return the point value for a unit interval', () => {
5613+
const ivl = new Interval(10n, 10n);
5614+
ivl.pointFrom().should.eql(10n);
5615+
});
5616+
5617+
it('should throw on pointFrom call if not a unit interval', () => {
5618+
const ivl = new Interval(0n, 1n);
5619+
should(() => ivl.pointFrom()).throw(Error);
5620+
});
5621+
5622+
it('should return the point from an interval with an open high bound', async function () {
5623+
const ivl = new Interval(5n, 6n, true, false);
5624+
ivl.pointFrom().should.eql(5n);
5625+
});
5626+
5627+
it('should throw for an interval with null high bound', function () {
5628+
const ivl = new Interval(0n, null);
5629+
should(() => ivl.pointFrom()).throw(Error);
5630+
});
5631+
5632+
it('should throw for an interval with undefined width', function () {
5633+
const ivl = new Interval(0n, 0n, false, false);
5634+
should(() => ivl.pointFrom()).throw(Error);
5635+
});
5636+
});
54965637
});
54975638

54985639
describe('DecimalInterval', () => {

test/elm/interval/data.cql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1008,6 +1008,16 @@ define OpenNotNull: end of Interval(DateTime(2012, 1, 1), DateTime(2013, 1, 1))
10081008
define OpenLongNotNull: end of Interval(1L, 3L)
10091009
define OpenNull: end of Interval(DateTime(2013, 1, 1), null)
10101010

1011+
// @Test: PointFrom
1012+
define IntegerPoint: point from Interval[4, 4]
1013+
define IntegerOpenHighPoint: point from Interval[4, 5)
1014+
define LongPoint: point from Interval[4294967296L, 4294967296L]
1015+
define EmptyIntervalPoint: point from Interval(0, 0)
1016+
define DateTimePoint: point from Interval[DateTime(2012, 1, 1), DateTime(2012, 1, 1)]
1017+
define NullPoint: point from (null as Interval<Integer>)
1018+
define NonUnitPoint: point from Interval[1, 4]
1019+
define NullHighPoint: point from Interval[1, null]
1020+
10111021
// @Test: Starts
10121022
define TestStartsNull: Interval[null, null] starts Interval[1, 10]
10131023
define IntegerIntervalStartsTrue: Interval[4,10] starts Interval[4, 15]

0 commit comments

Comments
 (0)