Skip to content

Commit 5c28fd1

Browse files
authored
Implement ProperContains/ProperIn for both List and Interval (#369)
- Implement ProperContains/ProperIn operators for both List and Interval - Expand unit/spec tests for List and Interval behavior and remove now-supported cases from the skip list - Update cql-tests CqlListOperatorsTest.xml to the latest from upstream - Add skip for Slice test group in CqlListOperators; Slice is CQL 2.0 and not yet implemented - Rebuild test CQL & ELM
1 parent 9877d3f commit 5c28fd1

19 files changed

Lines changed: 22511 additions & 4049 deletions

examples/browser/cql4browsers.js

Lines changed: 65 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,15 @@ class Interval {
18911891
}
18921892
return logic_1.ThreeValuedLogic.and(lowFn(this.low, item, precision), highFn(this.high, item, precision));
18931893
}
1894+
properContains(item, precision) {
1895+
if (item == null) {
1896+
return null;
1897+
}
1898+
else if (item.isInterval) {
1899+
throw new Error('Argument to contains must be a point');
1900+
}
1901+
return logic_1.ThreeValuedLogic.and(cmp.lessThan(this.start(), item, precision), cmp.greaterThan(this.end(), item, precision));
1902+
}
18941903
properlyIncludes(other, precision) {
18951904
if (other == null || !other.isInterval) {
18961905
throw new Error('Argument to properlyIncludes must be an interval');
@@ -4800,7 +4809,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
48004809
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
48014810
};
48024811
Object.defineProperty(exports, "__esModule", { value: true });
4803-
exports.doContains = exports.doExcept = exports.doIncludes = exports.doIntersect = exports.doProperIncludes = exports.doAfter = exports.doUnion = exports.doBefore = void 0;
4812+
exports.doProperContains = exports.doContains = exports.doExcept = exports.doIncludes = exports.doIntersect = exports.doProperIncludes = exports.doAfter = exports.doUnion = exports.doBefore = void 0;
48044813
__exportStar(require("./expression"), exports);
48054814
__exportStar(require("./aggregate"), exports);
48064815
__exportStar(require("./arithmetic"), exports);
@@ -4839,6 +4848,7 @@ Object.defineProperty(exports, "doIntersect", { enumerable: true, get: function
48394848
Object.defineProperty(exports, "doIncludes", { enumerable: true, get: function () { return interval_1.doIncludes; } });
48404849
Object.defineProperty(exports, "doExcept", { enumerable: true, get: function () { return interval_1.doExcept; } });
48414850
Object.defineProperty(exports, "doContains", { enumerable: true, get: function () { return interval_1.doContains; } });
4851+
Object.defineProperty(exports, "doProperContains", { enumerable: true, get: function () { return interval_1.doProperContains; } });
48424852

48434853
},{"./aggregate":15,"./arithmetic":16,"./clinical":18,"./comparison":19,"./conditional":20,"./datetime":21,"./declaration":22,"./expression":23,"./external":25,"./instance":26,"./interval":27,"./list":29,"./literal":30,"./logical":31,"./message":32,"./nullological":33,"./overloaded":34,"./parameters":35,"./quantity":36,"./query":37,"./ratio":38,"./reusable":39,"./string":40,"./structured":41,"./type":42}],25:[function(require,module,exports){
48444854
"use strict";
@@ -4991,6 +5001,7 @@ var __importStar = (this && this.__importStar) || (function () {
49915001
Object.defineProperty(exports, "__esModule", { value: true });
49925002
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;
49935003
exports.doContains = doContains;
5004+
exports.doProperContains = doProperContains;
49945005
exports.doIncludes = doIncludes;
49955006
exports.doProperIncludes = doProperIncludes;
49965007
exports.doAfter = doAfter;
@@ -5050,6 +5061,10 @@ exports.Interval = Interval;
50505061
function doContains(interval, item, precision) {
50515062
return interval.contains(item, precision);
50525063
}
5064+
// Delegated to by overloaded#ProperContains and overloaded#ProperIn
5065+
function doProperContains(interval, item, precision) {
5066+
return interval.properContains(item, precision);
5067+
}
50535068
// Delegated to by overloaded#Includes and overloaded#IncludedIn
50545069
function doIncludes(interval, subinterval, precision) {
50555070
return interval.includes(subinterval, precision);
@@ -5861,6 +5876,7 @@ exports.doUnion = doUnion;
58615876
exports.doExcept = doExcept;
58625877
exports.doIntersect = doIntersect;
58635878
exports.doContains = doContains;
5879+
exports.doProperContains = doProperContains;
58645880
exports.doIncludes = doIncludes;
58655881
exports.doProperIncludes = doProperIncludes;
58665882
const immutable_1 = require("immutable");
@@ -5990,6 +6006,15 @@ exports.IndexOf = IndexOf;
59906006
function doContains(container, item) {
59916007
return container.some((element) => (0, comparison_1.equals)(element, item) || (element == null && item == null));
59926008
}
6009+
// Delegated to by overloaded#ProperContains and overloaded#ProperIn
6010+
function doProperContains(container, item) {
6011+
// The "proper" membership operators have list semantics, not set semantics.
6012+
// The intent here is that given list semantics and a `distinct` operator,
6013+
// one can achieve set semantics, but the reverse isn't possible.
6014+
// These proper membership operators can then be described as
6015+
// the regular membership operators, plus the list is strictly larger.
6016+
return container.length > 1 && doContains(container, item);
6017+
}
59936018
// Delegated to by overloaded#Includes and overloaded@IncludedIn
59946019
function doIncludes(list, sublist) {
59956020
if (list == null || sublist == null) {
@@ -6427,7 +6452,7 @@ var __importStar = (this && this.__importStar) || (function () {
64276452
};
64286453
})();
64296454
Object.defineProperty(exports, "__esModule", { value: true });
6430-
exports.Precision = exports.SameOrBefore = exports.SameOrAfter = exports.SameAs = exports.Before = exports.After = exports.Length = exports.ProperIncludedIn = exports.ProperIncludes = exports.IncludedIn = exports.Includes = exports.Contains = exports.In = exports.Indexer = exports.Intersect = exports.Except = exports.Union = exports.NotEqual = exports.Equivalent = exports.Equal = void 0;
6455+
exports.Precision = exports.SameOrBefore = exports.SameOrAfter = exports.SameAs = exports.Before = exports.After = exports.Length = exports.ProperContains = exports.ProperIn = exports.ProperIncludedIn = exports.ProperIncludes = exports.IncludedIn = exports.Includes = exports.Contains = exports.In = exports.Indexer = exports.Intersect = exports.Except = exports.Union = exports.NotEqual = exports.Equivalent = exports.Equal = void 0;
64316456
/* eslint-disable @typescript-eslint/ban-ts-comment */
64326457
const expression_1 = require("./expression");
64336458
const logic_1 = require("../datatypes/logic");
@@ -6675,6 +6700,44 @@ class ProperIncludedIn extends expression_1.Expression {
66756700
}
66766701
}
66776702
exports.ProperIncludedIn = ProperIncludedIn;
6703+
class ProperIn extends expression_1.Expression {
6704+
constructor(json) {
6705+
super(json);
6706+
this.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
6707+
}
6708+
async exec(ctx) {
6709+
const [item, container] = await this.execArgs(ctx);
6710+
if (container == null) {
6711+
return false;
6712+
}
6713+
if ((0, util_1.typeIsArray)(container)) {
6714+
return LIST.doProperContains(container, item);
6715+
}
6716+
else {
6717+
return IVL.doProperContains(container, item, this.precision);
6718+
}
6719+
}
6720+
}
6721+
exports.ProperIn = ProperIn;
6722+
class ProperContains extends expression_1.Expression {
6723+
constructor(json) {
6724+
super(json);
6725+
this.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
6726+
}
6727+
async exec(ctx) {
6728+
const [container, item] = await this.execArgs(ctx);
6729+
if (container == null) {
6730+
return false;
6731+
}
6732+
if ((0, util_1.typeIsArray)(container)) {
6733+
return LIST.doProperContains(container, item);
6734+
}
6735+
else {
6736+
return IVL.doProperContains(container, item, this.precision);
6737+
}
6738+
}
6739+
}
6740+
exports.ProperContains = ProperContains;
66786741
class Length extends expression_1.Expression {
66796742
constructor(json) {
66806743
super(json);

src/datatypes/interval.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,18 @@ export class Interval {
114114
);
115115
}
116116

117+
properContains(item: any, precision?: any) {
118+
if (item == null) {
119+
return null;
120+
} else if (item.isInterval) {
121+
throw new Error('Argument to contains must be a point');
122+
}
123+
return ThreeValuedLogic.and(
124+
cmp.lessThan(this.start(), item, precision),
125+
cmp.greaterThan(this.end(), item, precision)
126+
);
127+
}
128+
117129
properlyIncludes(other: any, precision?: any) {
118130
if (other == null || !other.isInterval) {
119131
throw new Error('Argument to properlyIncludes must be an interval');

src/elm/expressions.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import {
3636
doIntersect,
3737
doIncludes,
3838
doExcept,
39-
doContains
39+
doContains,
40+
doProperContains
4041
} from './interval';
4142

4243
export {
@@ -47,5 +48,6 @@ export {
4748
doIntersect,
4849
doIncludes,
4950
doExcept,
50-
doContains
51+
doContains,
52+
doProperContains
5153
};

src/elm/interval.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ export function doContains(interval: any, item: any, precision?: any) {
6767
return interval.contains(item, precision);
6868
}
6969

70+
// Delegated to by overloaded#ProperContains and overloaded#ProperIn
71+
export function doProperContains(interval: any, item: any, precision?: any) {
72+
return interval.properContains(item, precision);
73+
}
74+
7075
// Delegated to by overloaded#Includes and overloaded#IncludedIn
7176
export function doIncludes(interval: any, subinterval: any, precision?: any) {
7277
return interval.includes(subinterval, precision);

src/elm/list.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,16 @@ export function doContains(container: any[], item: any) {
141141
);
142142
}
143143

144+
// Delegated to by overloaded#ProperContains and overloaded#ProperIn
145+
export function doProperContains(container: any[], item: any) {
146+
// The "proper" membership operators have list semantics, not set semantics.
147+
// The intent here is that given list semantics and a `distinct` operator,
148+
// one can achieve set semantics, but the reverse isn't possible.
149+
// These proper membership operators can then be described as
150+
// the regular membership operators, plus the list is strictly larger.
151+
return container.length > 1 && doContains(container, item);
152+
}
153+
144154
// Delegated to by overloaded#Includes and overloaded@IncludedIn
145155
export function doIncludes(list: any, sublist: any) {
146156
if (list == null || sublist == null) {

src/elm/overloaded.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,48 @@ export class ProperIncludedIn extends Expression {
269269
}
270270
}
271271

272+
export class ProperIn extends Expression {
273+
precision?: any;
274+
275+
constructor(json: any) {
276+
super(json);
277+
this.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
278+
}
279+
280+
async exec(ctx: Context) {
281+
const [item, container] = await this.execArgs(ctx);
282+
if (container == null) {
283+
return false;
284+
}
285+
if (typeIsArray(container)) {
286+
return LIST.doProperContains(container, item);
287+
} else {
288+
return IVL.doProperContains(container, item, this.precision);
289+
}
290+
}
291+
}
292+
293+
export class ProperContains extends Expression {
294+
precision?: any;
295+
296+
constructor(json: any) {
297+
super(json);
298+
this.precision = json.precision != null ? json.precision.toLowerCase() : undefined;
299+
}
300+
301+
async exec(ctx: Context) {
302+
const [container, item] = await this.execArgs(ctx);
303+
if (container == null) {
304+
return false;
305+
}
306+
if (typeIsArray(container)) {
307+
return LIST.doProperContains(container, item);
308+
} else {
309+
return IVL.doProperContains(container, item, this.precision);
310+
}
311+
}
312+
}
313+
272314
export class Length extends Expression {
273315
constructor(json: any) {
274316
super(json);

0 commit comments

Comments
 (0)