CompareExpression.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. "use strict";
  2. var assert = require("assert"),
  3. CompareExpression = require("../../../../lib/pipeline/expressions/CompareExpression"),
  4. Expression = require("../../../../lib/pipeline/expressions/Expression"),
  5. FieldRangeExpression = require("../../../../lib/pipeline/expressions/FieldRangeExpression");
  6. module.exports = {
  7. "CompareExpression": {
  8. "constructor()": {
  9. "should throw Error if no args": function testConstructor(){
  10. assert.throws(function(){
  11. new CompareExpression();
  12. });
  13. }
  14. },
  15. "#getOpName()": {
  16. "should return the correct op name; $eq, $ne, $gt, $gte, $lt, $lte, $cmp": function testOpName(){
  17. assert.equal((new CompareExpression(Expression.CmpOp.EQ)).getOpName(), "$eq");
  18. assert.equal((new CompareExpression(Expression.CmpOp.NE)).getOpName(), "$ne");
  19. assert.equal((new CompareExpression(Expression.CmpOp.GT)).getOpName(), "$gt");
  20. assert.equal((new CompareExpression(Expression.CmpOp.GTE)).getOpName(), "$gte");
  21. assert.equal((new CompareExpression(Expression.CmpOp.LT)).getOpName(), "$lt");
  22. assert.equal((new CompareExpression(Expression.CmpOp.LTE)).getOpName(), "$lte");
  23. assert.equal((new CompareExpression(Expression.CmpOp.CMP)).getOpName(), "$cmp");
  24. }
  25. },
  26. "#evaluate()": {
  27. "$eq": {
  28. "should return false if first < second; {$eq:[1,2]}": function testEqLt(){
  29. assert.equal(Expression.parseOperand({$eq:[1,2]}).evaluate({}), false);
  30. },
  31. "should return true if first == second; {$eq:[1,1]}": function testEqEq(){
  32. assert.equal(Expression.parseOperand({$eq:[1,1]}).evaluate({}), true);
  33. },
  34. "should return false if first > second {$eq:[1,0]}": function testEqGt(){
  35. assert.equal(Expression.parseOperand({$eq:[1,0]}).evaluate({}), false);
  36. },
  37. "should return false if first and second are different types {$eq:[null,0]}": function testEqGt(){
  38. assert.equal(Expression.parseOperand({$eq:[null,0]}).evaluate({}), false);
  39. },
  40. "should return false if first and second are different types {$eq:[undefined,0]}": function testEqGt(){
  41. assert.equal(Expression.parseOperand({$eq:[undefined,0]}).evaluate({}), false);
  42. },
  43. "should return false if first and second are different arrays {$eq:[[1],[null]]}": function testEqGt(){
  44. assert.equal(Expression.parseOperand({$eq:[[1],[null]]}).evaluate({}), false);
  45. },
  46. "should return false if first and second are different arrays {$eq:[[1],[]]}": function testEqGt(){
  47. assert.equal(Expression.parseOperand({$eq:[[1],[]]}).evaluate({}), false);
  48. },
  49. "should return true if first and second are the same arrays {$eq:[[1],[1]]}": function testEqGt(){
  50. assert.equal(Expression.parseOperand({$eq:[[1],[1]]}).evaluate({}), true);
  51. }
  52. },
  53. "$ne": {
  54. "should return true if first < second; {$ne:[1,2]}": function testNeLt(){
  55. assert.equal(Expression.parseOperand({$ne:[1,2]}).evaluate({}), true);
  56. },
  57. "should return false if first == second; {$ne:[1,1]}": function testNeLt(){
  58. assert.equal(Expression.parseOperand({$ne:[1,1]}).evaluate({}), false);
  59. },
  60. "should return true if first > second; {$ne:[1,0]}": function testNeGt(){
  61. assert.equal(Expression.parseOperand({$ne:[1,0]}).evaluate({}), true);
  62. }
  63. },
  64. "$gt": {
  65. "should return false if first < second; {$gt:[1,2]}": function testGtLt(){
  66. assert.equal(Expression.parseOperand({$gt:[1,2]}).evaluate({}), false);
  67. },
  68. "should return false if first == second; {$gt:[1,1]}": function testGtLt(){
  69. assert.equal(Expression.parseOperand({$gt:[1,1]}).evaluate({}), false);
  70. },
  71. "should return true if first > second; {$gt:[1,0]}": function testGtGt(){
  72. assert.equal(Expression.parseOperand({$gt:[1,0]}).evaluate({}), true);
  73. }
  74. },
  75. "$gte": {
  76. "should return false if first < second; {$gte:[1,2]}": function testGteLt(){
  77. assert.equal(Expression.parseOperand({$gte:[1,2]}).evaluate({}), false);
  78. },
  79. "should return true if first == second; {$gte:[1,1]}": function testGteLt(){
  80. assert.equal(Expression.parseOperand({$gte:[1,1]}).evaluate({}), true);
  81. },
  82. "should return true if first > second; {$gte:[1,0]}": function testGteGt(){
  83. assert.equal(Expression.parseOperand({$gte:[1,0]}).evaluate({}), true);
  84. }
  85. },
  86. "$lt": {
  87. "should return true if first < second; {$lt:[1,2]}": function testLtLt(){
  88. assert.equal(Expression.parseOperand({$lt:[1,2]}).evaluate({}), true);
  89. },
  90. "should return false if first == second; {$lt:[1,1]}": function testLtLt(){
  91. assert.equal(Expression.parseOperand({$lt:[1,1]}).evaluate({}), false);
  92. },
  93. "should return false if first > second; {$lt:[1,0]}": function testLtGt(){
  94. assert.equal(Expression.parseOperand({$lt:[1,0]}).evaluate({}), false);
  95. }
  96. },
  97. "$lte": {
  98. "should return true if first < second; {$lte:[1,2]}": function testLteLt(){
  99. assert.equal(Expression.parseOperand({$lte:[1,2]}).evaluate({}), true);
  100. },
  101. "should return true if first == second; {$lte:[1,1]}": function testLteLt(){
  102. assert.equal(Expression.parseOperand({$lte:[1,1]}).evaluate({}), true);
  103. },
  104. "should return false if first > second; {$lte:[1,0]}": function testLteGt(){
  105. assert.equal(Expression.parseOperand({$lte:[1,0]}).evaluate({}), false);
  106. }
  107. },
  108. "$cmp": {
  109. "should return -1 if first < second; {$cmp:[1,2]}": function testCmpLt(){
  110. assert.equal(Expression.parseOperand({$cmp:[1,2]}).evaluate({}), -1);
  111. },
  112. "should return 0 if first < second; {$cmp:[1,1]}": function testCmpLt(){
  113. assert.equal(Expression.parseOperand({$cmp:[1,1]}).evaluate({}), 0);
  114. },
  115. "should return 1 if first < second; {$cmp:[1,0]}": function testCmpLt(){
  116. assert.equal(Expression.parseOperand({$cmp:[1,0]}).evaluate({}), 1);
  117. },
  118. "should return 1 even if comparison is larger; {$cmp:['z','a']}": function testCmpBracketed(){
  119. assert.equal(Expression.parseOperand({$cmp:['z','a']}).evaluate({}), 1);
  120. }
  121. },
  122. "should throw Error": {
  123. "if zero operands are provided; {$ne:[]}": function testZeroOperands(){
  124. assert.throws(function(){
  125. Expression.parseOperand({$ne:[]}).evaluate({});
  126. });
  127. },
  128. "if one operand is provided; {$eq:[1]}": function testOneOperand(){
  129. assert.throws(function(){
  130. Expression.parseOperand({$eq:[1]}).evaluate({});
  131. });
  132. },
  133. "if three operands are provided; {$gt:[2,3,4]}": function testThreeOperands(){
  134. assert.throws(function(){
  135. Expression.parseOperand({$gt:[2,3,4]}).evaluate({});
  136. });
  137. }
  138. }
  139. },
  140. "#optimize()": {
  141. "should optimize constants; {$eq:[1,1]}": function testOptimizeConstants(){
  142. assert.deepEqual(Expression.parseOperand({$eq:[1,1]}).optimize().toJSON(true), {$const:true});
  143. },
  144. "should not optimize if $cmp op; {$cmp:[1,'$a']}": function testNoOptimizeCmp(){
  145. assert.deepEqual(Expression.parseOperand({$cmp:[1,'$a']}).optimize().toJSON(), {$cmp:[1,'$a']});
  146. },
  147. "should not optimize if $ne op; {$ne:[1,'$a']}": function testNoOptimizeNe(){
  148. assert.deepEqual(Expression.parseOperand({$ne:[1,'$a']}).optimize().toJSON(), {$ne:[1,'$a']});
  149. },
  150. "should not optimize if no constants; {$ne:['$a','$b']}": function testNoOptimizeNoConstant(){
  151. assert.deepEqual(Expression.parseOperand({$ne:['$a','$b']}).optimize().toJSON(), {$ne:['$a','$b']});
  152. },
  153. "should not optimize without an immediate field path;": {
  154. "{$eq:[{$and:['$a']},1]}": function testNoOptimizeWithoutFieldPath(){
  155. assert.deepEqual(Expression.parseOperand({$eq:[{$and:['$a']},1]}).optimize().toJSON(), {$eq:[{$and:['$a']},1]});
  156. },
  157. "(reversed); {$eq:[1,{$and:['$a']}]}": function testNoOptimizeWithoutFieldPathReverse(){
  158. assert.deepEqual(Expression.parseOperand({$eq:[1,{$and:['$a']}]}).optimize().toJSON(), {$eq:[1,{$and:['$a']}]});
  159. }
  160. },
  161. "should optimize $eq expressions;": {
  162. "{$eq:['$a',1]}": function testOptimizeEq(){
  163. var expr = Expression.parseOperand({$eq:['$a',1]}).optimize();
  164. assert(expr instanceof FieldRangeExpression, "not optimized");
  165. assert.deepEqual(expr.toJSON(), {$eq:['$a',1]});
  166. },
  167. "{$eq:[1,'$a']} (reversed)": function testOptimizeEqReverse(){
  168. var expr = Expression.parseOperand({$eq:[1,'$a']}).optimize();
  169. assert(expr instanceof FieldRangeExpression, "not optimized");
  170. assert.deepEqual(expr.toJSON(), {$eq:['$a',1]});
  171. }
  172. },
  173. "should optimize $lt expressions;": {
  174. "{$lt:['$a',1]}": function testOptimizeLt(){
  175. var expr = Expression.parseOperand({$lt:['$a',1]}).optimize();
  176. assert(expr instanceof FieldRangeExpression, "not optimized");
  177. assert.deepEqual(expr.toJSON(), {$lt:['$a',1]});
  178. },
  179. "{$lt:[1,'$a']} (reversed)": function testOptimizeLtReverse(){
  180. var expr = Expression.parseOperand({$lt:[1,'$a']}).optimize();
  181. assert(expr instanceof FieldRangeExpression, "not optimized");
  182. assert.deepEqual(expr.toJSON(), {$gt:['$a',1]});
  183. }
  184. },
  185. "should optimize $lte expressions;": {
  186. "{$lte:['$b',2]}": function testOptimizeLte(){
  187. var expr = Expression.parseOperand({$lte:['$b',2]}).optimize();
  188. assert(expr instanceof FieldRangeExpression, "not optimized");
  189. assert.deepEqual(expr.toJSON(), {$lte:['$b',2]});
  190. },
  191. "{$lte:[2,'$b']} (reversed)": function testOptimizeLteReverse(){
  192. var expr = Expression.parseOperand({$lte:[2,'$b']}).optimize();
  193. assert(expr instanceof FieldRangeExpression, "not optimized");
  194. assert.deepEqual(expr.toJSON(), {$gte:['$b',2]});
  195. }
  196. },
  197. "should optimize $gt expressions;": {
  198. "{$gt:['$b',2]}": function testOptimizeGt(){
  199. var expr = Expression.parseOperand({$gt:['$b',2]}).optimize();
  200. assert(expr instanceof FieldRangeExpression, "not optimized");
  201. assert.deepEqual(expr.toJSON(), {$gt:['$b',2]});
  202. },
  203. "{$gt:[2,'$b']} (reversed)": function testOptimizeGtReverse(){
  204. var expr = Expression.parseOperand({$gt:[2,'$b']}).optimize();
  205. assert(expr instanceof FieldRangeExpression, "not optimized");
  206. assert.deepEqual(expr.toJSON(), {$lt:['$b',2]});
  207. }
  208. },
  209. "should optimize $gte expressions;": {
  210. "{$gte:['$b',2]}": function testOptimizeGte(){
  211. var expr = Expression.parseOperand({$gte:['$b',2]}).optimize();
  212. assert(expr instanceof FieldRangeExpression, "not optimized");
  213. assert.deepEqual(expr.toJSON(), {$gte:['$b',2]});
  214. },
  215. "{$gte:[2,'$b']} (reversed)": function testOptimizeGteReverse(){
  216. var expr = Expression.parseOperand({$gte:[2,'$b']}).optimize();
  217. assert(expr instanceof FieldRangeExpression, "not optimized");
  218. assert.deepEqual(expr.toJSON(), {$lte:['$b',2]});
  219. }
  220. },
  221. }
  222. }
  223. };
  224. if (!module.parent)(new(require("mocha"))()).ui("exports").reporter("spec").addFile(__filename).run(process.exit);