Skip to content

Commit b68c3d3

Browse files
committed
Adds tests for All, not
1 parent 265e119 commit b68c3d3

File tree

8 files changed

+323
-40
lines changed

8 files changed

+323
-40
lines changed

src/serializers/basic-query-test.js

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,3 +265,53 @@ QUnit.test("Complex queries with nested $not, $all", function(assert) {
265265
var res = converter.serializer.serialize(basicQuery);
266266
assert.deepEqual(res, query);
267267
});
268+
269+
QUnit.test("Inverting $not comparisons", function(assert) {
270+
[
271+
{
272+
query: {filter: {age:{$not: {$lt: 5}}} },
273+
expectedInstance: is.GreaterThanEqual,
274+
expectedValue: 5
275+
},
276+
{
277+
query: {filter: {age:{$not: {$lte: 5}}} },
278+
expectedInstance: is.GreaterThan,
279+
expectedValue: 5
280+
},
281+
{
282+
query: {filter: {age:{$not: {$gt: 5}}}},
283+
expectedInstance: is.LessThanEqual,
284+
expectedValue: 5
285+
},
286+
{
287+
query: {filter: {age:{$not: {$gte: 5}}}},
288+
expectedInstance: is.LessThan,
289+
expectedValue: 5
290+
},
291+
{
292+
query: {filter: {age:{$not: {$in: [2, 3]}}}},
293+
expectedInstance: is.NotIn,
294+
expectedValue: [2, 3],
295+
valueProp: "values"
296+
},
297+
{
298+
query: {filter: {age:{$not: {$nin: [2, 3]}}}},
299+
expectedInstance: is.In,
300+
expectedValue: [2, 3],
301+
valueProp: "values"
302+
}
303+
].forEach(function(options) {
304+
var query = options.query;
305+
var ExpectedInstance = options.expectedInstance;
306+
var expectedValue = options.expectedValue;
307+
var prop = options.valueProp || "value";
308+
309+
var converter = makeBasicQueryConvert(EmptySchema);
310+
var basicQuery = converter.hydrate(query);
311+
312+
assert.ok(basicQuery.filter.values.age instanceof ExpectedInstance, "changed to right instance type");
313+
assert.deepEqual(basicQuery.filter.values.age[prop],
314+
expectedValue, "has the correct value");
315+
316+
});
317+
});

src/serializers/comparisons.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,32 @@ addHydrateFrom("$lte", makeNew(is.LessThanEqual));
5252

5353
addHydrateFromValues("$all", makeNew(is.All));
5454

55+
var notRemap = {
56+
"LessThan": { Type: is.GreaterThanEqual, prop: "value" },
57+
"LessThanEqual": { Type: is.GreaterThan, prop: "value" },
58+
"GreaterThan": { Type: is.LessThanEqual, prop: "value" },
59+
"GreaterThanEqual": { Type: is.LessThan, prop: "value" },
60+
"In": { Type: is.NotIn, prop: "values" },
61+
"NotIn": { Type: is.In, prop: "values" }
62+
};
63+
5564
hydrateMap["$not"] = function(value, unknownHydrator) {
56-
return new ValuesNot(hydrateValue(value["$not"], unknownHydrator));
65+
// Many nots can be hydrated to their opposite.
66+
var hydratedValue = hydrateValue(value["$not"], unknownHydrator);
67+
var typeName = hydratedValue.constructor.name;
68+
69+
if(notRemap[typeName]) {
70+
var options = notRemap[typeName];
71+
var RemapConstructor = options.Type;
72+
var prop = options.prop;
73+
74+
return new RemapConstructor(hydratedValue[prop]);
75+
}
76+
77+
return new ValuesNot(hydratedValue);
5778
};
5879

59-
addHydrateFromValues("$nin", makeNew(is.GreaterThan));
80+
addHydrateFromValues("$nin", makeNew(is.NotIn));
6081

6182

6283
var serializer = new Serializer([

src/types/array-comparisons.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
var common = require("./comparisons-common");
2+
var set = require("../set");
3+
var ValuesNot = require("./values-not");
4+
5+
var comparisons = {
6+
All: function(values){
7+
this.values = values;
8+
}
9+
};
10+
11+
comparisons.All.prototype.isMember = common.isMemberThatUsesTestOnValues;
12+
13+
var is = comparisons;
14+
15+
comparisons.All.test = function(allValues, recordValues) {
16+
return allValues.every(function(allValue) {
17+
return recordValues.some(function(recordValue){
18+
var values = set.ownAndMemberValue(allValue, recordValue);
19+
return values.own === values.member;
20+
});
21+
});
22+
};
23+
24+
function makeThrowCannotCompare(type, left, right) {
25+
return function() {
26+
throw new Error("can-query-logic: Cannot perform " + type + " between " + left + " and " + right);
27+
}
28+
}
29+
30+
function throwComparatorAllTypes(type1, type2) {
31+
return {
32+
union: makeThrowCannotCompare("union", type1, type2),
33+
difference: makeThrowCannotCompare("difference", type1, type2),
34+
intersection: makeThrowCannotCompare("intersection", type1, type2)
35+
};
36+
}
37+
38+
function throwComparatorDifference(type1, type2) {
39+
return {
40+
difference: makeThrowCannotCompare("difference", type1, type2)
41+
};
42+
}
43+
44+
var comparators = {
45+
UNIVERSAL_All: {
46+
difference: function(universe, all) {
47+
return new ValuesNot(all);
48+
}
49+
},
50+
All_UNIVERSAL: {
51+
difference: function() {
52+
return set.EMPTY;
53+
}
54+
},
55+
All_All: {
56+
union: function(a, b) {
57+
return new is.Or([a, b]);
58+
}
59+
},
60+
In_All: throwComparatorDifference("In", "All"),
61+
All_In: throwComparatorAllTypes("All", "In"),
62+
NotIn_All: throwComparatorDifference("NotIn", "All"),
63+
All_NotIn: throwComparatorAllTypes("All", "NotIn"),
64+
GreaterThan_All: throwComparatorDifference("GreaterThan", "All"),
65+
All_GreaterThan: throwComparatorAllTypes("All", "GreaterThan"),
66+
GreaterThanEqual_All: throwComparatorDifference("GreaterThanEqual", "All"),
67+
All_GreaterThanEqual: throwComparatorAllTypes("All", "GreaterThanEqual"),
68+
LessThan_All: throwComparatorDifference("LessThan", "All"),
69+
All_LessThan: throwComparatorAllTypes("All", "LessThan"),
70+
LessThanEqual_All: throwComparatorDifference("LessThanEqual", "All"),
71+
All_LessThanEqual: throwComparatorAllTypes("All", "LessThanEqual"),
72+
All_And: throwComparatorDifference("All", "And"),
73+
And_All: throwComparatorAllTypes("And", "All"),
74+
All_Or: throwComparatorDifference("All", "Or"),
75+
Or_All: throwComparatorAllTypes("Or", "All")
76+
}
77+
78+
exports.comparisons = comparisons;
79+
exports.comparators = comparators;

src/types/basic-query-test.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,25 @@ QUnit.test("Able to filter on a universal set", function(assert) {
2626
var res = root.filterMembersAndGetCount(bData, parent);
2727
assert.equal(res.count, 2, "got all members");
2828
});
29+
30+
QUnit.test("Page is a universal set", function(assert) {
31+
var parent = new BasicQuery({
32+
filter: new KeysAnd({})
33+
})
34+
var bData = [{},{}];
35+
36+
var FooType = function(value) { this.value = value; };
37+
FooType.prototype.isMember = function() {
38+
return true;
39+
};
40+
41+
var root = new BasicQuery({
42+
filter: new ValuesAnd([
43+
new FooType()
44+
]),
45+
page: new BasicQuery.RecordRange(1,2)
46+
});
47+
48+
var res = root.filterMembersAndGetCount(bData, parent);
49+
assert.equal(res.count, 2, "got all members");
50+
});

src/types/basic-query.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,11 @@ canReflect.assignMap(BasicQuery.prototype, {
171171
return data.slice(0).sort(this.sort.compare);
172172
},
173173
filterMembersAndGetCount: function(bData, parentQuery) {
174+
var parentIsUniversal;
174175
if (parentQuery) {
175-
if (!set.isEqual(set.UNIVERSAL, parentQuery.filter) &&
176+
parentIsUniversal = set.isEqual(parentQuery.page, set.UNIVERSAL);
177+
if ((parentIsUniversal &&
178+
!set.isEqual(parentQuery.filter, set.UNIVERSAL)) &&
176179
!set.isSubset(this, parentQuery)) {
177180
throw new Error("can-query-logic: Unable to get members from a set that is not a superset of the current set.");
178181
}
@@ -192,8 +195,10 @@ canReflect.assignMap(BasicQuery.prototype, {
192195
aData = this.sortData(aData);
193196
}
194197

195-
var thisIsUniversal = set.isEqual(this.page, set.UNIVERSAL),
198+
var thisIsUniversal = set.isEqual(this.page, set.UNIVERSAL);
199+
if(parentIsUniversal == null) {
196200
parentIsUniversal = set.isEqual(parentQuery.page, set.UNIVERSAL);
201+
}
197202

198203
if (parentIsUniversal) {
199204
if (thisIsUniversal) {

src/types/comparisons-common.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
var set = require("../set");
2+
3+
function isMemberThatUsesTestOnValues(value) {
4+
return this.constructor.test(this.values, value);
5+
}
6+
7+
exports.isMemberThatUsesTestOnValues = isMemberThatUsesTestOnValues;

src/types/comparisons-test.js

Lines changed: 115 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3831,7 +3831,7 @@ var tests = {
38313831
var all = new is.All(["test"]);
38323832
assert.deepEqual(
38333833
set.difference(set.UNIVERSAL, all),
3834-
set.UNKNOWABLE
3834+
new ValuesNot(new is.All(["test"]))
38353835
);
38363836
}
38373837
},
@@ -3843,6 +3843,120 @@ var tests = {
38433843
set.EMPTY
38443844
);
38453845
}
3846+
},
3847+
All_All: {
3848+
union: function(assert) {
3849+
// {$all:["a"]} ∪ {$all:["b"]} -> {$or: [{$all:["a"]}]}
3850+
var a = new is.All(["a"]);
3851+
var b = new is.All(["b"]);
3852+
3853+
assert.deepEqual(
3854+
set.union(a, b),
3855+
new is.Or([new is.All(["a"]), new is.All(["b"])])
3856+
)
3857+
}
3858+
},
3859+
In_All: {
3860+
union: function(assert) {
3861+
var a = new is.In(["a"]);
3862+
var b = new is.All(["b"]);
3863+
assert.throws(function(){
3864+
set.union(a, b);
3865+
}, "unable to compare");
3866+
},
3867+
difference: function(assert) {
3868+
var a = new is.In(["a"]);
3869+
var b = new is.All(["b"]);
3870+
assert.throws(function(){
3871+
set.union(a, b);
3872+
}, "unable to compare");
3873+
}
3874+
},
3875+
All_In: {
3876+
union: function(assert) {
3877+
var a = new is.In(["a"]);
3878+
var b = new is.All(["b"]);
3879+
assert.throws(function(){
3880+
set.union(b, a);
3881+
}, "unable to compare");
3882+
},
3883+
difference: function(assert) {
3884+
var a = new is.In(["a"]);
3885+
var b = new is.All(["b"]);
3886+
assert.throws(function(){
3887+
set.difference(b, a);
3888+
}, "unable to compare");
3889+
}
3890+
},
3891+
NotIn_All: {
3892+
union: function(assert) {
3893+
var a = new is.In(["a"]);
3894+
var b = new is.All(["b"]);
3895+
assert.throws(function() {
3896+
set.union(a, b);
3897+
}, "unable to compare");
3898+
}
3899+
},
3900+
All_NotIn: {
3901+
union: function(assert) {
3902+
var a = new is.In(["a"]);
3903+
var b = new is.All(["b"]);
3904+
assert.throws(function() {
3905+
set.union(b, a);
3906+
}, );
3907+
}
3908+
},
3909+
And_All: {
3910+
union: function(assert) {
3911+
// {$and:[{"a":"b"}]} ∪ {$all:["b"]} -> ?
3912+
var a = new is.And([{a:"b"}]);
3913+
var b = new is.All(["b"]);
3914+
assert.throws(function() {
3915+
set.union(a, b)
3916+
}, "unable to compare");
3917+
},
3918+
difference: function(assert) {
3919+
// {$and:[{"a":"b"}]} ∖ {$all:["b"]} -> ?
3920+
var a = new is.And([{a:"b"}]);
3921+
var b = new is.All(["b"]);
3922+
assert.throws(function() {
3923+
set.difference(a, b)
3924+
}, "unable to compare");
3925+
},
3926+
intersection: function(assert) {
3927+
// {$and:[{"a":"b"}]} ∩ {$all:["b"]} -> ?
3928+
var a = new is.And([{a:"b"}]);
3929+
var b = new is.All(["b"]);
3930+
assert.throws(function() {
3931+
set.intersection(a, b)
3932+
}, "unable to compare");
3933+
}
3934+
},
3935+
All_Or: {
3936+
union: function(assert) {
3937+
// {$and:[{"a":"b"}]} ∪ {$all:["b"]} -> ?
3938+
var a = new is.Or([{a:"b"}]);
3939+
var b = new is.All(["b"]);
3940+
assert.throws(function() {
3941+
set.union(a, b)
3942+
}, "unable to compare");
3943+
},
3944+
difference: function(assert) {
3945+
// {$and:[{"a":"b"}]} \ {$all:["b"]} -> ?
3946+
var a = new is.Or([{a:"b"}]);
3947+
var b = new is.All(["b"]);
3948+
assert.throws(function() {
3949+
set.difference(a, b)
3950+
}, "unable to compare");
3951+
},
3952+
intersection: function(assert) {
3953+
// {$and:[{"a":"b"}]} ∩ {$all:["b"]} -> ?
3954+
var a = new is.Or([{a:"b"}]);
3955+
var b = new is.All(["b"]);
3956+
assert.throws(function() {
3957+
set.intersection(a, b)
3958+
}, "unable to compare");
3959+
}
38463960
}
38473961
};
38483962

0 commit comments

Comments
 (0)