|
|
@@ -1,11 +1,14 @@
|
|
|
"use strict";
|
|
|
var assert = require("assert"),
|
|
|
- Expression = require("../../../../lib/pipeline/expressions/Expression"),
|
|
|
+ pipeline = require("../../../../lib/pipeline"),
|
|
|
+ expressions = pipeline.expressions,
|
|
|
+ Expression = expressions.Expression,
|
|
|
CompareExpression = require("../../../../lib/pipeline/expressions/CompareExpression"),
|
|
|
- FieldRangeExpression = require("../../../../lib/pipeline/expressions/FieldRangeExpression"),
|
|
|
VariablesParseState = require("../../../../Lib/pipeline/expressions/VariablesParseState"),
|
|
|
VariablesIdGenerator = require("../../../../Lib/pipeline/expressions/VariablesIdGenerator"),
|
|
|
- ConstantExpression = require("../../../../Lib/pipeline/expressions/ConstantExpression");
|
|
|
+ utils = require("./utils"),
|
|
|
+ constify = utils.constify,
|
|
|
+ expressionToJson = utils.expressionToJson;
|
|
|
|
|
|
module.exports = {
|
|
|
|
|
|
@@ -17,6 +20,18 @@ module.exports = {
|
|
|
assert.throws(function() {
|
|
|
new CompareExpression();
|
|
|
});
|
|
|
+ },
|
|
|
+
|
|
|
+ "should throw if more than 1 args": function testConstructor() {
|
|
|
+ assert.throws(function() {
|
|
|
+ new CompareExpression(1,2);
|
|
|
+ });
|
|
|
+ },
|
|
|
+
|
|
|
+ "should not throw if 1 arg and arg is string": function testConstructor() {
|
|
|
+ assert.doesNotThrow(function() {
|
|
|
+ new CompareExpression("a");
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
},
|
|
|
@@ -35,327 +50,479 @@ module.exports = {
|
|
|
|
|
|
},
|
|
|
|
|
|
- "#evaluateInternal()": {
|
|
|
-
|
|
|
- "$eq": {
|
|
|
-
|
|
|
- "should return false if first < second; {$eq:[1,2]}": function testEqLt() {
|
|
|
- //debugger;
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- var parseOp = Expression.parseOperand({
|
|
|
- $eq: [{
|
|
|
- $const: 1
|
|
|
- }, {
|
|
|
- $const: 2
|
|
|
- }]
|
|
|
- }, vps);
|
|
|
- var result = parseOp.evaluateInternal({});
|
|
|
-
|
|
|
- //assert.equal(new CompareExpression( CompareExpression.EQ).evaluateInternal({"$eq":[1,2]}), false);
|
|
|
- assert.equal(result, false);
|
|
|
-
|
|
|
- },
|
|
|
-
|
|
|
- "should return true if first == second; {$eq:[1,1]}": function testEqEq() {
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
-
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [1, 1]
|
|
|
- }, vps).evaluateInternal({}), true);
|
|
|
- },
|
|
|
-
|
|
|
- "should return false if first > second {$eq:[1,0]}": function testEqGt() {
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [1, 0]
|
|
|
- }).evaluateInternal({}), false);
|
|
|
- },
|
|
|
-
|
|
|
- "should return false if first and second are different types {$eq:[null,0]}": function testEqGt() {
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [null, 0]
|
|
|
- }, vps).evaluateInternal({}), false);
|
|
|
- },
|
|
|
-
|
|
|
- "should return false if first and second are different types {$eq:[undefined,0]}": function testEqGt() {
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [undefined, 0]
|
|
|
- }, vps).evaluateInternal({}), false);
|
|
|
- },
|
|
|
-
|
|
|
- "should return false if first and second are different arrays {$eq:[[1],[null]]}": function testEqGt() {
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [
|
|
|
- [1],
|
|
|
- [null]
|
|
|
- ]
|
|
|
- }, vps).evaluateInternal({}), false);
|
|
|
- },
|
|
|
-
|
|
|
- "should return false if first and second are different arrays {$eq:[[1],[]]}": function testEqGt() {
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [
|
|
|
- [1],
|
|
|
- []
|
|
|
- ]
|
|
|
- }, vps).evaluateInternal({}), false);
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- },
|
|
|
-
|
|
|
- "should return true if first and second are the same arrays {$eq:[[1],[1]]}": function testEqGt() {
|
|
|
- var idGenerator = new VariablesIdGenerator();
|
|
|
- var vps = new VariablesParseState(idGenerator);
|
|
|
- assert.equal(Expression.parseOperand({
|
|
|
- $eq: [
|
|
|
- [1],
|
|
|
- [1]
|
|
|
- ]
|
|
|
- }, vps).evaluateInternal({}), true);
|
|
|
- }
|
|
|
- },
|
|
|
-
|
|
|
- // "$ne": {
|
|
|
-
|
|
|
- // "should return true if first < second; {$ne:[1,2]}": function testNeLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$ne:[1,2]}).evaluateInternal({}), true);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return false if first == second; {$ne:[1,1]}": function testNeLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$ne:[1,1]}).evaluateInternal({}), false);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return true if first > second; {$ne:[1,0]}": function testNeGt(){
|
|
|
- // assert.equal(Expression.parseOperand({$ne:[1,0]}).evaluateInternal({}), true);
|
|
|
- // }
|
|
|
-
|
|
|
- // },
|
|
|
-
|
|
|
- // "$gt": {
|
|
|
-
|
|
|
- // "should return false if first < second; {$gt:[1,2]}": function testGtLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$gt:[1,2]}).evaluateInternal({}), false);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return false if first == second; {$gt:[1,1]}": function testGtLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$gt:[1,1]}).evaluateInternal({}), false);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return true if first > second; {$gt:[1,0]}": function testGtGt(){
|
|
|
- // assert.equal(Expression.parseOperand({$gt:[1,0]}).evaluateInternal({}), true);
|
|
|
- // }
|
|
|
-
|
|
|
- // },
|
|
|
-
|
|
|
- // "$gte": {
|
|
|
-
|
|
|
- // "should return false if first < second; {$gte:[1,2]}": function testGteLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$gte:[1,2]}).evaluateInternal({}), false);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return true if first == second; {$gte:[1,1]}": function testGteLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$gte:[1,1]}).evaluateInternal({}), true);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return true if first > second; {$gte:[1,0]}": function testGteGt(){
|
|
|
- // assert.equal(Expression.parseOperand({$gte:[1,0]}).evaluateInternal({}), true);
|
|
|
- // }
|
|
|
-
|
|
|
- // },
|
|
|
-
|
|
|
- // "$lt": {
|
|
|
-
|
|
|
- // "should return true if first < second; {$lt:[1,2]}": function testLtLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$lt:[1,2]}).evaluateInternal({}), true);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return false if first == second; {$lt:[1,1]}": function testLtLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$lt:[1,1]}).evaluateInternal({}), false);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return false if first > second; {$lt:[1,0]}": function testLtGt(){
|
|
|
- // assert.equal(Expression.parseOperand({$lt:[1,0]}).evaluateInternal({}), false);
|
|
|
- // }
|
|
|
-
|
|
|
- // },
|
|
|
-
|
|
|
- // "$lte": {
|
|
|
-
|
|
|
- // "should return true if first < second; {$lte:[1,2]}": function testLteLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$lte:[1,2]}).evaluateInternal({}), true);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return true if first == second; {$lte:[1,1]}": function testLteLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$lte:[1,1]}).evaluateInternal({}), true);
|
|
|
- // },
|
|
|
-
|
|
|
- // "should return false if first > second; {$lte:[1,0]}": function testLteGt(){
|
|
|
- // assert.equal(Expression.parseOperand({$lte:[1,0]}).evaluateInternal({}), false);
|
|
|
- // }
|
|
|
+ "#evaluate()": {
|
|
|
+
|
|
|
+ before: function before() {
|
|
|
+ var self = this;
|
|
|
+ //OptimizeBase
|
|
|
+ this.OptimizeBase = function() {};
|
|
|
+ var oBProto = this.OptimizeBase.prototype;
|
|
|
+ oBProto.run = function run() {
|
|
|
+ var specElement = this.spec(),
|
|
|
+ idGenerator = new VariablesIdGenerator(),
|
|
|
+ vps = new VariablesParseState(idGenerator),
|
|
|
+ expression = Expression.parseOperand(specElement, vps),
|
|
|
+ optimized = expression.optimize();
|
|
|
+ assert.deepEqual(constify(this.expectedOptimized()), expressionToJson(optimized));
|
|
|
+ };
|
|
|
+ //FieldRangeOptimize
|
|
|
+ this.FieldRangeOptimize = function FieldRangeOptimize() {};
|
|
|
+ var fROProto = Object.create(oBProto);
|
|
|
+ this.FieldRangeOptimize.prototype = fROProto;
|
|
|
+ fROProto.expectedOptimized = function() {
|
|
|
+ return this.spec();
|
|
|
+ };
|
|
|
+ //NoOptimize
|
|
|
+ this.NoOptimize = function NoOptimize() {};
|
|
|
+ var nOProto = Object.create(oBProto);
|
|
|
+ this.NoOptimize.prototype = nOProto;
|
|
|
+ nOProto.expectedOptimized = function() {
|
|
|
+ return this.spec();
|
|
|
+ };
|
|
|
+ //ExpectedResultBase
|
|
|
+ this.ExpectedResultBase = function ExpectedResultBase() {};
|
|
|
+ var eRBProto = Object.create(oBProto);
|
|
|
+ this.ExpectedResultBase.prototype = eRBProto;
|
|
|
+ eRBProto.run = function run() {
|
|
|
+ oBProto.run.call(this);
|
|
|
+ var specElement = this.spec(),
|
|
|
+ idGenerator = new VariablesIdGenerator(),
|
|
|
+ vps = new VariablesParseState(idGenerator),
|
|
|
+ expression = Expression.parseOperand(specElement, vps);
|
|
|
+ assert.deepEqual(expressionToJson(expression),
|
|
|
+ constify(specElement));
|
|
|
+ assert.strictEqual(expression.evaluate({}),
|
|
|
+ this.expectedResult());
|
|
|
+ var optimized = expression.optimize();
|
|
|
+ assert.strictEqual(optimized.evaluate({}),
|
|
|
+ this.expectedResult());
|
|
|
+ };
|
|
|
+ eRBProto.expectedOptimized = function expectedOptimized() {
|
|
|
+ return {$const:this.expectedResult()};
|
|
|
+ };
|
|
|
+ //ExpectedTrue
|
|
|
+ this.ExpectedTrue = function ExpectedTrue() {};
|
|
|
+ var eTProto = Object.create(eRBProto);
|
|
|
+ this.ExpectedTrue.prototype = eTProto;
|
|
|
+ eTProto.expectedResult = function() {
|
|
|
+ return true;
|
|
|
+ };
|
|
|
+ //ExpectedTrue
|
|
|
+ this.ExpectedFalse = function ExpectedFalse() {};
|
|
|
+ var eFProto = Object.create(eRBProto);
|
|
|
+ this.ExpectedFalse.prototype = eFProto;
|
|
|
+ eFProto.expectedResult = function() {
|
|
|
+ return false;
|
|
|
+ };
|
|
|
+ //ParseError
|
|
|
+ this.ParseError = function ParseError() {};
|
|
|
+ var pEProto = this.ParseError.prototype;
|
|
|
+ pEProto.run = function run() {
|
|
|
+ var specElement = this.spec(),
|
|
|
+ idGenerator = new VariablesIdGenerator(),
|
|
|
+ vps = new VariablesParseState(idGenerator);
|
|
|
+ assert.throws(function() {
|
|
|
+ Expression.parseOperand(specElement, vps);
|
|
|
+ });
|
|
|
+ };
|
|
|
+ //IncompatibleTypes
|
|
|
+ this.IncompatibleTypes = function IncompatibleTypes() {};
|
|
|
+ var iTProto = this.IncompatibleTypes.prototype;
|
|
|
+ iTProto.run = function() {
|
|
|
+ var specElement = {$ne:["a", 1]},
|
|
|
+ idGenerator = new VariablesIdGenerator(),
|
|
|
+ vps = new VariablesParseState(idGenerator),
|
|
|
+ expression = Expression.parseOperand(specElement, vps);
|
|
|
+ assert.strictEqual(expression.evaluate({}), true);
|
|
|
+ };
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** $eq with first < second. */
|
|
|
+ "EqLt": function EqLt() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1,2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "$cmp": {
|
|
|
+ /** $eq with first == second. */
|
|
|
+ "EqEq": function EqEq() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1,1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should return -1 if first < second; {$cmp:[1,2]}": function testCmpLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$cmp:[1,2]}).evaluateInternal({}), -1);
|
|
|
- // },
|
|
|
+ /** $eq with first > second. */
|
|
|
+ "EqGt": function EqEq() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1,0]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should return 0 if first < second; {$cmp:[1,1]}": function testCmpLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$cmp:[1,1]}).evaluateInternal({}), 0);
|
|
|
- // },
|
|
|
+ /** $ne with first < second. */
|
|
|
+ "NeLt": function NeLt() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$ne:[1,2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should return 1 if first < second; {$cmp:[1,0]}": function testCmpLt(){
|
|
|
- // assert.equal(Expression.parseOperand({$cmp:[1,0]}).evaluateInternal({}), 1);
|
|
|
- // },
|
|
|
+ /** $ne with first == second. */
|
|
|
+ "NeEq": function NeEq() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$ne:[1,1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should return 1 even if comparison is larger; {$cmp:['z','a']}": function testCmpBracketed(){
|
|
|
- // assert.equal(Expression.parseOperand({$cmp:['z','a']}).evaluateInternal({}), 1);
|
|
|
- // }
|
|
|
+ /** $ne with first > second. */
|
|
|
+ "NeGt": function NeGt() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$ne:[1,0]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** $gt with first < second. */
|
|
|
+ "GtLt": function GtLt() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gt:[1,2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should throw Error": {
|
|
|
+ /** $gt with first == second. */
|
|
|
+ "GtEq": function GtEq() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gt:[1,1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "if zero operands are provided; {$ne:[]}": function testZeroOperands(){
|
|
|
- // assert.throws(function(){
|
|
|
- // Expression.parseOperand({$ne:[]}).evaluateInternal({});
|
|
|
- // });
|
|
|
- // },
|
|
|
+ /** $gt with first > second. */
|
|
|
+ "GtGt": function GtGt() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gt:[1,0]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "if one operand is provided; {$eq:[1]}": function testOneOperand(){
|
|
|
- // assert.throws(function(){
|
|
|
- // Expression.parseOperand({$eq:[1]}).evaluateInternal({});
|
|
|
- // });
|
|
|
- // },
|
|
|
+ /** $gte with first < second. */
|
|
|
+ "GteLt": function GteLt() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gte:[1,2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "if three operands are provided; {$gt:[2,3,4]}": function testThreeOperands(){
|
|
|
- // assert.throws(function(){
|
|
|
- // Expression.parseOperand({$gt:[2,3,4]}).evaluateInternal({});
|
|
|
- // });
|
|
|
- // }
|
|
|
- // }
|
|
|
+ /** $gte with first == second. */
|
|
|
+ "GteEq": function GteEq() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gte:[1,1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** $gte with first > second. */
|
|
|
+ "GteGt": function GteGt() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gte:[1,0]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "#optimize()": {
|
|
|
+ /** $gte with first > second. */
|
|
|
+ "LtLt": function LtLt() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lt:[1,2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should optimize constants; {$eq:[1,1]}": function testOptimizeConstants(){
|
|
|
- // assert.deepEqual(Expression.parseOperand({$eq:[1,1]}).optimize().toJSON(true), {$const:true});
|
|
|
- // },
|
|
|
+ /** $lt with first == second. */
|
|
|
+ "LtEq": function LtEq() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lt:[1,1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should not optimize if $cmp op; {$cmp:[1,'$a']}": function testNoOptimizeCmp(){
|
|
|
- // assert.deepEqual(Expression.parseOperand({$cmp:[1,'$a']}).optimize().toJSON(), {$cmp:[1,'$a']});
|
|
|
- // },
|
|
|
+ /** $lt with first > second. */
|
|
|
+ "LtGt": function LtGt() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lt:[1,0]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should not optimize if $ne op; {$ne:[1,'$a']}": function testNoOptimizeNe(){
|
|
|
- // assert.deepEqual(Expression.parseOperand({$ne:[1,'$a']}).optimize().toJSON(), {$ne:[1,'$a']});
|
|
|
- // },
|
|
|
+ /** $lte with first < second. */
|
|
|
+ "LteLt": function LteLt() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lte:[1,2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should not optimize if no constants; {$ne:['$a','$b']}": function testNoOptimizeNoConstant(){
|
|
|
- // assert.deepEqual(Expression.parseOperand({$ne:['$a','$b']}).optimize().toJSON(), {$ne:['$a','$b']});
|
|
|
- // },
|
|
|
+ /** $lte with first == second. */
|
|
|
+ "LteEq": function LteEq() {
|
|
|
+ var test = new this.ExpectedTrue();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lte:[1,1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should not optimize without an immediate field path;": {
|
|
|
+ /** $lte with first > second. */
|
|
|
+ "LteGt": function LteGt() {
|
|
|
+ var test = new this.ExpectedFalse();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lte:[1,0]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$eq:[{$and:['$a']},1]}": function testNoOptimizeWithoutFieldPath(){
|
|
|
- // assert.deepEqual(Expression.parseOperand({$eq:[{$and:['$a']},1]}).optimize().toJSON(), {$eq:[{$and:['$a']},1]});
|
|
|
- // },
|
|
|
+ /** $cmp with first < second. */
|
|
|
+ "CmpLt": function CmpLt() {
|
|
|
+ var test = new this.ExpectedResultBase();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$cmp:[1,2]};
|
|
|
+ };
|
|
|
+ test.expectedResult = function() {
|
|
|
+ return -1;
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "(reversed); {$eq:[1,{$and:['$a']}]}": function testNoOptimizeWithoutFieldPathReverse(){
|
|
|
- // assert.deepEqual(Expression.parseOperand({$eq:[1,{$and:['$a']}]}).optimize().toJSON(), {$eq:[1,{$and:['$a']}]});
|
|
|
- // }
|
|
|
+ /** $cmp with first == second. */
|
|
|
+ "CmpEq": function CmpEq() {
|
|
|
+ var test = new this.ExpectedResultBase();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$cmp:[1,1]};
|
|
|
+ };
|
|
|
+ test.expectedResult = function() {
|
|
|
+ return 0;
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** $cmp with first > second. */
|
|
|
+ "CmpGt": function CmpGt() {
|
|
|
+ var test = new this.ExpectedResultBase();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$cmp:[1,0]};
|
|
|
+ };
|
|
|
+ test.expectedResult = function() {
|
|
|
+ return 1;
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should optimize $eq expressions;": {
|
|
|
+ /** $cmp results are bracketed to an absolute value of 1. */
|
|
|
+ "CmpBracketed": function CmpBracketed() {
|
|
|
+ var test = new this.ExpectedResultBase();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$cmp:["z","a"]};
|
|
|
+ };
|
|
|
+ test.expectedResult = function() {
|
|
|
+ return 1;
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$eq:['$a',1]}": function testOptimizeEq(){
|
|
|
- // var expr = Expression.parseOperand({$eq:['$a',1]}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$eq:['$a',1]});
|
|
|
- // },
|
|
|
+ /** Zero operands provided. */
|
|
|
+ "ZeroOperands": function ZeroOperands() {
|
|
|
+ var test = new this.ParseError();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$ne:[]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$eq:[1,'$a']} (reversed)": function testOptimizeEqReverse(){
|
|
|
- // var expr = Expression.parseOperand({$eq:[1,'$a']}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$eq:['$a',1]});
|
|
|
- // }
|
|
|
+ /** One operands provided. */
|
|
|
+ "OneOperand": function OneOperand() {
|
|
|
+ var test = new this.ParseError();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** Three operands provided. */
|
|
|
+ "ThreeOperands": function ThreeOperands() {
|
|
|
+ var test = new this.ParseError();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gt:[2,3,4]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should optimize $lt expressions;": {
|
|
|
+ /**
|
|
|
+ * An expression depending on constants is optimized to a constant via
|
|
|
+ * ExpressionNary::optimize().
|
|
|
+ */
|
|
|
+ "OptimizeConstants": function OptimizeConstants() {
|
|
|
+ var test = new this.OptimizeBase();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1,1]};
|
|
|
+ };
|
|
|
+ test.expectedOptimized = function() {
|
|
|
+ return {$const:true};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$lt:['$a',1]}": function testOptimizeLt(){
|
|
|
- // var expr = Expression.parseOperand({$lt:['$a',1]}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$lt:['$a',1]});
|
|
|
- // },
|
|
|
+ /** $cmp is not optimized. */
|
|
|
+ "NoOptimizeCmp": function NoOptimizeCmp() {
|
|
|
+ var test = new this.NoOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$cmp:[1,"$a"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$lt:[1,'$a']} (reversed)": function testOptimizeLtReverse(){
|
|
|
- // var expr = Expression.parseOperand({$lt:[1,'$a']}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$gt:['$a',1]});
|
|
|
- // }
|
|
|
+ /** $ne is not optimized. */
|
|
|
+ "NoOptimizeNe": function NoOptimizeNe() {
|
|
|
+ var test = new this.NoOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$ne:[1,"$a"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** No optimization is performend without a constant. */
|
|
|
+ "NoOptimizeNoConstant": function NoOptimizeNoConstant() {
|
|
|
+ var test = new this.NoOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$ne:["$a", "$b"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should optimize $lte expressions;": {
|
|
|
+ /** No optimization is performend without an immediate field path. */
|
|
|
+ "NoOptimizeWithoutFieldPath": function NoOptimizeWithoutFieldPath() {
|
|
|
+ var test = new this.NoOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[{$and:["$a"]},1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$lte:['$b',2]}": function testOptimizeLte(){
|
|
|
- // var expr = Expression.parseOperand({$lte:['$b',2]}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$lte:['$b',2]});
|
|
|
- // },
|
|
|
+ /** No optimization is performend without an immediate field path. */
|
|
|
+ "NoOptimizeWithoutFieldPathReverse": function NoOptimizeWithoutFieldPathReverse() {
|
|
|
+ var test = new this.NoOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1,{$and:["$a"]}]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$lte:[2,'$b']} (reversed)": function testOptimizeLteReverse(){
|
|
|
- // var expr = Expression.parseOperand({$lte:[2,'$b']}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$gte:['$b',2]});
|
|
|
- // }
|
|
|
+ /** An equality expression is optimized. */
|
|
|
+ "OptimizeEq": function OptimizeEq() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:["$a",1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** A reverse sense equality expression is optimized. */
|
|
|
+ "OptimizeEqReverse": function OptimizeEqReverse() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$eq:[1,"$a"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should optimize $gt expressions;": {
|
|
|
+ /** A $lt expression is optimized. */
|
|
|
+ "OptimizeLt": function OptimizeLt() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lt:["$a",1]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$gt:['$b',2]}": function testOptimizeGt(){
|
|
|
- // var expr = Expression.parseOperand({$gt:['$b',2]}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$gt:['$b',2]});
|
|
|
- // },
|
|
|
+ /** A reverse sense $lt expression is optimized. */
|
|
|
+ "OptimizeLtReverse": function OptimizeLtReverse() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lt:[1,"$a"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$gt:[2,'$b']} (reversed)": function testOptimizeGtReverse(){
|
|
|
- // var expr = Expression.parseOperand({$gt:[2,'$b']}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$lt:['$b',2]});
|
|
|
- // }
|
|
|
+ /** A $lte expression is optimized. */
|
|
|
+ "OptimizeLte": function OptimizeLte() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lte:["$b",2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** A reverse sense $lte expression is optimized. */
|
|
|
+ "OptimizeLteReverse": function OptimizeLteReverse() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$lte:[2,"$b"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "should optimize $gte expressions;": {
|
|
|
+ /** A $gt expression is optimized. */
|
|
|
+ "OptimizeGt": function OptimizeGt() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gt:["$b",2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$gte:['$b',2]}": function testOptimizeGte(){
|
|
|
- // var expr = Expression.parseOperand({$gte:['$b',2]}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$gte:['$b',2]});
|
|
|
- // },
|
|
|
+ /** A reverse sense $gt expression is optimized. */
|
|
|
+ "OptimizeGtReverse": function OptimizeGtReverse() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gt:["$b",2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // "{$gte:[2,'$b']} (reversed)": function testOptimizeGteReverse(){
|
|
|
- // var expr = Expression.parseOperand({$gte:[2,'$b']}).optimize();
|
|
|
- // assert(expr instanceof FieldRangeExpression, "not optimized");
|
|
|
- // assert.deepEqual(expr.toJSON(), {$lte:['$b',2]});
|
|
|
- // }
|
|
|
+ /** A $gte expression is optimized. */
|
|
|
+ "OptimizeGte": function OptimizeGte() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gte:["$b",2]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
- // },
|
|
|
+ /** A reverse sense $gte expression is optimized. */
|
|
|
+ "OptimizeGteReverse": function OptimizeGteReverse() {
|
|
|
+ var test = new this.FieldRangeOptimize();
|
|
|
+ test.spec = function() {
|
|
|
+ return {$gte:[2,"$b"]};
|
|
|
+ };
|
|
|
+ test.run();
|
|
|
+ },
|
|
|
|
|
|
|
|
|
}
|