MatchExpressionParser_test.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. "use strict";
  2. if (!module.parent) return require.cache[__filename] = 0, (new(require("mocha"))()).addFile(__filename).ui("exports").run(process.exit);
  3. var assert = require("assert"),
  4. ErrorCodes = require("../../../../lib/Errors").ErrorCodes,
  5. MatchExpressionParser = require("../../../../lib/pipeline/matcher/MatchExpressionParser");
  6. module.exports = {
  7. "MatchExpressionParser": {
  8. "Should generate matchers that work with no operators": function (){
  9. var goodQ = {"x":2},badQ = {"x":3};
  10. var parser = new MatchExpressionParser();
  11. var res = parser.parse(goodQ);
  12. assert.strictEqual(res.code,ErrorCodes.OK,res.description);
  13. assert.ok( res.result.matches(goodQ));
  14. assert.ok( ! res.result.matches(badQ));
  15. },
  16. "Should parse {x:5,y:{$gt:5, :$lt:8}}": function() {
  17. var q = {"x":5, "y":{"$gt":5, "$lt":8}};
  18. var parser = new MatchExpressionParser();
  19. var res = parser.parse( q );
  20. assert.strictEqual(res.code,ErrorCodes.OK,res.description);
  21. assert.ok( res.result.matches({"x":5, "y":7}) );
  22. assert.ok( res.result.matches({"x":5, "y":6}) );
  23. assert.ok( ! res.result.matches({"x":6, "y":7}) );
  24. assert.ok( ! res.result.matches({"x":5, "y":9}) );
  25. assert.ok( ! res.result.matches({"x":5, "y":4}) );
  26. },
  27. "Should parse $isolated and $atomic appropriately": function() {
  28. var q1 = {"x":5, "$atomic": {"$gt":5, "$lt":8}},
  29. q2 = {"x":5, "$isolated":1},
  30. q3 = {"x":5, "y":{"$isolated":1}};
  31. var parser = new MatchExpressionParser();
  32. parser.parse(q1);
  33. assert.strictEqual(parser.parse(q1).code, ErrorCodes.OK);
  34. assert.strictEqual(parser.parse(q2).code, ErrorCodes.OK);
  35. assert.strictEqual(parser.parse(q3).code, ErrorCodes.BAD_VALUE);
  36. },
  37. "Should parse and match $size with an int": function() {
  38. var parser = new MatchExpressionParser();
  39. var q = {"x":{"$size":2}};
  40. var res = parser.parse(q);
  41. assert.strictEqual(res.code,ErrorCodes.OK,res.description);
  42. assert.ok( ! res.result.matches({"x":1}) );
  43. assert.ok( res.result.matches({"x":[1,2]}) );
  44. assert.ok( ! res.result.matches({"x":[1]}) );
  45. assert.ok( ! res.result.matches({"x":[1,2,3]}) );
  46. },
  47. "Should parse and match $size with a string argument": function() {
  48. var parser = new MatchExpressionParser();
  49. var q = {"x":{"$size":"a"}};
  50. var res = parser.parse( q );
  51. assert.strictEqual(res.code,ErrorCodes.OK,res.description);
  52. assert.ok( ! res.result.matches({"x":1}) );
  53. assert.ok( ! res.result.matches({"x":[1,2]}) );
  54. assert.ok( res.result.matches({"x":[]}) );
  55. assert.ok( ! res.result.matches({"x": [1]}) );
  56. },
  57. "Should parse and match $size with a float argument":function() {
  58. var parser = new MatchExpressionParser();
  59. var q = {"x": {"$size": 2.5}};
  60. var res = parser.parse( q );
  61. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  62. assert.ok( ! res.result.matches({"x":1}) );
  63. assert.ok( ! res.result.matches({"x":[1,2]}) );
  64. assert.ok( ! res.result.matches({"x":[]}) );
  65. assert.ok( ! res.result.matches({"x":[1,2,3]}) );
  66. },
  67. "Should not accept null": function() {
  68. var parser = new MatchExpressionParser();
  69. var q = {"x":{"$size":null}};
  70. var res = parser.parse( q );
  71. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  72. },
  73. "Should parse $elemMatch : {x:1,y:2}": function() {
  74. var parser = new MatchExpressionParser();
  75. var q = {"x":{"$elemMatch": {"x":1,"y":2}}};
  76. var res = parser.parse( q );
  77. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  78. assert.ok( ! res.result.matches({"x":1}) );
  79. assert.ok( ! res.result.matches({"x":[1,2]}) );
  80. assert.ok( ! res.result.matches({"x":[{"x":1}]}) );
  81. assert.ok( res.result.matches({"x": [{"x":1,"y":2}]}) );
  82. },
  83. "Should parse and match $elemMatch: {$gt:5}": function() {
  84. var parser = new MatchExpressionParser();
  85. var q = {"x": {"$elemMatch": {"$gt":5}}};
  86. var res = parser.parse( q );
  87. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  88. assert.ok( ! res.result.matches({"x":1}) );
  89. assert.ok( ! res.result.matches({"x":[4]}) );
  90. assert.ok( res.result.matches({"x":[6]}) );
  91. },
  92. "Should parse and match $all:[1,2]" : function() {
  93. var parser = new MatchExpressionParser();
  94. var q = {"x":{"$all":[1,2]}};
  95. var res = parser.parse( q );
  96. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  97. assert.ok( ! res.result.matches({"x":1}) );
  98. assert.ok( ! res.result.matches({"x":[1]}) );
  99. assert.ok( ! res.result.matches({"x":[2]}) );
  100. assert.ok( res.result.matches({"x":[1,2]}) );
  101. assert.ok( res.result.matches({"x":[1,2,3]}) );
  102. assert.ok( ! res.result.matches({"x":[2,3]}) );
  103. },
  104. "Should not allow $all to have an element argument": function() {
  105. var parser = new MatchExpressionParser();
  106. var q = {"x": {"$all":1}};
  107. var res = parser.parse( q );
  108. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  109. },
  110. "Should not allow large regex patterns": function () {
  111. var parser = new MatchExpressionParser();
  112. var q = {"x":{"$all":[new RegExp((new Array(50*1000+1)).join("z"))] }};
  113. var res = parser.parse( q );
  114. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  115. },
  116. "Should parse and match some simple regex patterns": function() {
  117. var parser = new MatchExpressionParser();
  118. var a = /^a/;
  119. var b = /B/i;
  120. var q = {"a": {"$all": [ a , b ]}};
  121. var res = parser.parse( q );
  122. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  123. assert.ok( ! res.result.matches({"a":"ax"}) );
  124. assert.ok( ! res.result.matches({"a":"qqb"}) );
  125. assert.ok( res.result.matches({"a":"ab"}) );
  126. },
  127. "Should parse and match some more simple regexes" : function(){
  128. var parser = new MatchExpressionParser();
  129. var a = /^a/;
  130. var b = /abc/;
  131. var q = {"a": {"$all": [a, b]}};
  132. var res = parser.parse( q );
  133. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  134. assert.ok( ! res.result.matches({"a":"ax"}) );
  135. assert.ok( res.result.matches({"a":"abc"}) );
  136. },
  137. "Should properly handle x:{$all:[5]}": function() {
  138. var parser = new MatchExpressionParser();
  139. var q = {"x":{"$all":[5]}};
  140. var res = parser.parse( q );
  141. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  142. assert.ok( res.result.matches({"x":5}) );
  143. assert.ok( res.result.matches({"x":[5]}) );
  144. assert.ok( ! res.result.matches({"x":4}) );
  145. assert.ok( ! res.result.matches({"x":[4]}) );
  146. },
  147. "Should handle a good $all $elemMatch query": function() {
  148. var parser = new MatchExpressionParser();
  149. var q = {"x":{"$all":[{"$elemMatch": {"x":1,"y":2}}]}};
  150. var res = parser.parse( q );
  151. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  152. assert.ok( ! res.result.matches({"x":1}) );
  153. assert.ok( ! res.result.matches({"x":[1,2]}) );
  154. assert.ok( ! res.result.matches({"x":[{"x":1}]}) );
  155. assert.ok( res.result.matches({"x":[{"x":1,"y":2}]}) );
  156. },
  157. "Should properly not parse bad $all $elemMatch queries": function() {
  158. var parser = new MatchExpressionParser();
  159. var q = {"x":{"$all":[{"$elemMatch":{"x":1,"y":2}}, 5]}};
  160. var res = parser.parse( q );
  161. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  162. q = {"x":{"$all":[5,{"$elemMatch":{"x":1,"y":2}}]}};
  163. res = parser.parse( q );
  164. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  165. },
  166. "Should parse and match simple $eq": function () {
  167. var parser = new MatchExpressionParser();
  168. var q = {"x": {"$eq": 2}};
  169. var res = parser.parse( q );
  170. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  171. assert.ok( ! res.result.matches({"x":1}) );
  172. assert.ok( res.result.matches({"x":2}) );
  173. assert.ok( ! res.result.matches({"x":3}) );
  174. },
  175. "Should parse and match simple $gt": function() {
  176. var parser = new MatchExpressionParser();
  177. var q = {"x": {"$gt":2}};
  178. var res = parser.parse( q );
  179. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  180. assert.ok( ! res.result.matches({"x":2}) );
  181. assert.ok( res.result.matches({"x":3}) );
  182. },
  183. "Should parse and match a simple $lt": function () {
  184. var parser = new MatchExpressionParser();
  185. var q = {"x":{"$lt":2}};
  186. var res = parser.parse( q );
  187. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  188. assert.ok( res.result.matches({"x":1}) );
  189. assert.ok( ! res.result.matches({"x":2}) );
  190. assert.ok( ! res.result.matches({"x":3}) );
  191. },
  192. "Should parse and match simple $gte": function() {
  193. var parser = new MatchExpressionParser();
  194. var q = {"x": {"$gte":2}};
  195. var res = parser.parse( q );
  196. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  197. assert.ok( ! res.result.matches({"x":1}) );
  198. assert.ok( res.result.matches({"x":2}) );
  199. assert.ok( res.result.matches({"x":3}) );
  200. },
  201. "Should parse and matc simple $lte": function() {
  202. var parser = new MatchExpressionParser();
  203. var q = {"x": {"$lte":2}};
  204. var res = parser.parse( q );
  205. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  206. assert.ok( res.result.matches({"x":1}) );
  207. assert.ok( res.result.matches({"x":2}) );
  208. assert.ok( ! res.result.matches({"x":3}) );
  209. },
  210. "Should parse and match simple $ne": function() {
  211. var parser = new MatchExpressionParser();
  212. var q = {"x": {"$ne":2}};
  213. var res = parser.parse( q );
  214. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  215. assert.ok( res.result.matches({"x":1}) );
  216. assert.ok( ! res.result.matches({"x":2}) );
  217. assert.ok( res.result.matches({"x":3}) );
  218. },
  219. "Should parse simple $mod patterns":function(){
  220. var parser = new MatchExpressionParser();
  221. var q = {"x":{"$mod":[3,2]}};
  222. var res = parser.parse( q );
  223. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  224. q = {"x":{"$mod":[3]}};
  225. res = parser.parse( q );
  226. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  227. q = {"x":{"$mod":[3,2,4]}};
  228. res = parser.parse( q );
  229. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  230. q = {"x":{"$mod":["q",2]}};
  231. res = parser.parse( q );
  232. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  233. q = {"x":{"$mod":3}};
  234. res = parser.parse( q );
  235. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  236. q = {"x":{"$mod":{"a":1,"b":2}}};
  237. res = parser.parse( q );
  238. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  239. },
  240. "Should parse and match simple $mod": function() {
  241. var parser = new MatchExpressionParser();
  242. var q = {"x":{"$mod":[3,2]}};
  243. var res = parser.parse( q );
  244. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  245. assert.ok( res.result.matches({"x":5}) );
  246. assert.ok( ! res.result.matches({"x":4}) );
  247. assert.ok( res.result.matches({"x":8}) );
  248. },
  249. "Should parse and match a simple $in": function() {
  250. var parser = new MatchExpressionParser();
  251. var q = {"x": {"$in":[2,3]}};
  252. var res = parser.parse( q );
  253. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  254. assert.ok( ! res.result.matches({"x":1}) );
  255. assert.ok( res.result.matches({"x":2}) );
  256. assert.ok( res.result.matches({"x":3}) );
  257. },
  258. "Should not accept a scalar as an arg to $in" : function() {
  259. var parser = new MatchExpressionParser();
  260. var q = {"x":{"$in": 5}};
  261. var res = parser.parse( q );
  262. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  263. },
  264. "Should not accept an $elemMatch as an arg to an $in": function () {
  265. var parser = new MatchExpressionParser();
  266. var q = {"x":{"$in":[{"$elemMatch": 1}]}};
  267. var res = parser.parse( q );
  268. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  269. },
  270. "Should not parse regexes that are too long": function() {
  271. var parser = new MatchExpressionParser();
  272. var str = (new Array(50*1000+1).join("z"));
  273. var q = {"x": {"$in":[new RegExp(str)]}};
  274. var res = parser.parse( q );
  275. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  276. q = {"x":{"$in": [{"$regex": str}]}};
  277. res = parser.parse( q );
  278. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  279. },
  280. "Should parse and match $regex in an $in expression": function() {
  281. var parser = new MatchExpressionParser();
  282. var a = /^a/;
  283. var b = /B/i;
  284. var q = {"a": {"$in": [a,b,"2",4]}};
  285. var res = parser.parse( q );
  286. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  287. assert.ok( res.result.matches({"a":"ax"}) );
  288. assert.ok( res.result.matches({"a":/^a/}) );
  289. assert.ok( res.result.matches({"a":"qqb"}) );
  290. assert.ok( res.result.matches({"a":/B/i}) );
  291. assert.ok( res.result.matches({"a":4}) );
  292. assert.ok( ! res.result.matches({"a":"l"}) );
  293. assert.ok( ! res.result.matches({"a":/B/}) );
  294. },
  295. "Should parse and match a simple $nin": function() {
  296. var parser = new MatchExpressionParser();
  297. var q = {"x": {"$nin": [2,3]}};
  298. var res = parser.parse( q );
  299. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  300. assert.ok( res.result.matches({"x":1}) );
  301. assert.ok( ! res.result.matches({"x":2}) );
  302. assert.ok( ! res.result.matches({"x":3}) );
  303. },
  304. "Should not accept a scalar argument to $nin":function() {
  305. var parser = new MatchExpressionParser();
  306. var q = {"x":{$nin: 5}};
  307. var res = parser.parse( q );
  308. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  309. },
  310. "Should properly handle /regex/i":function() {
  311. var parser = new MatchExpressionParser();
  312. var a = /abc/i;
  313. var q = {"x": a };
  314. var res = parser.parse( q );
  315. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  316. assert.ok( res.result.matches({"x":"ABC"}) );
  317. assert.ok( res.result.matches({"x":"abc"}) );
  318. assert.ok( ! res.result.matches({"x":"AC"}) );
  319. },
  320. "Should properly handle $regex x $option i": function() {
  321. var parser = new MatchExpressionParser();
  322. var q = {"x": {"$regex": "abc", "$options":"i"}};
  323. var res = parser.parse( q );
  324. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  325. assert.ok( res.result.matches({"x":"abc"}) );
  326. assert.ok( res.result.matches({"x":"ABC"}) );
  327. assert.ok( ! res.result.matches({"x":"AC"}) );
  328. },
  329. "Should properly handle $option i $regex x": function () {
  330. var parser = new MatchExpressionParser();
  331. var q = {"x":{"$options": "i", "$regex": "abc"}};
  332. var res = parser.parse( q );
  333. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  334. assert.ok( res.result.matches({"x":"abc"}) );
  335. assert.ok( res.result.matches({"x":"ABC"}) );
  336. assert.ok( ! res.result.matches({"x":"AC"}) );
  337. },
  338. "Should not accept $optionas":function() {
  339. var parser = new MatchExpressionParser();
  340. var q = {"x":{"$regex":"abc", "$optionas":"i"}};
  341. var res = parser.parse( q );
  342. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  343. q = {"x":{"$optionas": "i"}};
  344. res = parser.parse( q );
  345. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  346. q = {"x":{"$options":"i"}};
  347. res = parser.parse( q );
  348. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  349. },
  350. "Should parse and match $exist true": function () {
  351. var parser = new MatchExpressionParser();
  352. var q = {"x":{"$exists": true}};
  353. var res = parser.parse( q );
  354. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  355. assert.ok( res.result.matches({"x":"abc"}) );
  356. assert.ok( ! res.result.matches({"y":"AC"}) );
  357. },
  358. "Should parse and match $exists false": function() {
  359. var parser = new MatchExpressionParser();
  360. var q = {"x":{"$exists":false}};
  361. var res = parser.parse( q );
  362. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  363. assert.ok( ! res.result.matches({"x":"abc"}) );
  364. assert.ok( res.result.matches({"y":"AC"}) );
  365. },
  366. "Should parse and match String $type": function() {
  367. var parser = new MatchExpressionParser();
  368. var q = {"x":{"$type": 2 }};
  369. var res = parser.parse( q );
  370. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  371. assert.ok( res.result.matches({"x": "abc"}) );
  372. assert.ok( ! res.result.matches({"x": 2}) );
  373. },
  374. "Should parse and match Number $type":function() {
  375. var parser = new MatchExpressionParser();
  376. var q = {"x":{"$type":1}};
  377. var res = parser.parse( q );
  378. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  379. assert.ok( res.result.matches({"x":2}) );
  380. assert.ok( ! res.result.matches({"x": "f"}) );
  381. },
  382. "Should parse and match null $type" : function() {
  383. var parser = new MatchExpressionParser();
  384. var q = {"x":{"$type": 10}};
  385. var res = parser.parse( q );
  386. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  387. assert.ok( ! res.result.matches({"x":{}}) );
  388. assert.ok( ! res.result.matches({"x":5}) );
  389. assert.ok( res.result.matches({"x":null}) );
  390. },
  391. "Should parse but not match a type beyond typemax in $type": function() {
  392. var parser = new MatchExpressionParser();
  393. var q = {"x":{"$type": 1000}};
  394. var res = parser.parse( q );
  395. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  396. assert.ok( ! res.result.matches({"x":5}) );
  397. assert.ok( ! res.result.matches({"x":"abc"}) );
  398. },
  399. "Should not parse a $type: Object":function() {
  400. var parser = new MatchExpressionParser();
  401. var q = {"x":{"$type": {"x":1}}};
  402. var res = parser.parse( q );
  403. assert.strictEqual( res.code, ErrorCodes.BAD_VALUE );
  404. },
  405. "Should parse and match a simple $or": function() {
  406. var parser = new MatchExpressionParser();
  407. var q = {"$or":[{"x":1},{"y":2}]};
  408. var res = parser.parse( q );
  409. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  410. assert.ok( res.result.matches({"x":1}) );
  411. assert.ok( res.result.matches({"y":2}) );
  412. assert.ok( ! res.result.matches({"x":3}) );
  413. assert.ok( ! res.result.matches({"y":1}) );
  414. },
  415. "Should parse and match with nested $or s": function() {
  416. var parser = new MatchExpressionParser();
  417. var q = {"$or":[{"$or":[{"x":1},{"y":2}]}]};
  418. var res = parser.parse( q );
  419. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  420. assert.ok( res.result.matches({"x":1}) );
  421. assert.ok( res.result.matches({"y":2}) );
  422. assert.ok( ! res.result.matches({"x":3}) );
  423. assert.ok( ! res.result.matches({"y":1}) );
  424. },
  425. "Should parse and match $and": function(){
  426. var parser = new MatchExpressionParser();
  427. var q = {"$and":[{"x":1},{"y":2}]};
  428. var res = parser.parse( q );
  429. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  430. assert.ok( ! res.result.matches({"x":1}) );
  431. assert.ok( ! res.result.matches({"y":2}) );
  432. assert.ok( ! res.result.matches({"x":3}) );
  433. assert.ok( ! res.result.matches({"y":1}) );
  434. assert.ok( res.result.matches({"x":1, "y":2}) );
  435. assert.ok( ! res.result.matches({"x":2, "y":2}) );
  436. },
  437. "Should parse and match $nor": function() {
  438. var parser = new MatchExpressionParser();
  439. var q = {"$nor":[{"x":1},{"y":2}]};
  440. var res = parser.parse( q );
  441. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  442. assert.ok( ! res.result.matches({"x":1}) );
  443. assert.ok( ! res.result.matches({"y":2}) );
  444. assert.ok( res.result.matches({"x":3}) );
  445. assert.ok( res.result.matches({"y":1}) );
  446. },
  447. "Should parse and match $not": function() {
  448. var parser = new MatchExpressionParser();
  449. var q = {"x":{"$not":{"$gt":5}}};
  450. var res = parser.parse( q );
  451. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  452. assert.ok( res.result.matches({"x":2}) );
  453. assert.ok( ! res.result.matches({"x":8}) );
  454. },
  455. "should allow trees less than the maximum recursion depth": function() {
  456. var parser = new MatchExpressionParser(),
  457. depth = 60,
  458. q = "",
  459. i;
  460. for (i = 0; i < depth/2; i++) {
  461. q = q + "{\"$and\": [{\"a\":3}, {\"$or\": [{\"b\":2},";
  462. }
  463. q = q + "{\"b\": 4}";
  464. for (i = 0; i < depth/2; i++) {
  465. q = q + "]}]}";
  466. }
  467. var res = parser.parse(JSON.parse(q));
  468. assert.strictEqual(res.code, ErrorCodes.OK, res.description);
  469. },
  470. "should error when depth limit is exceeded": function() {
  471. var parser = new MatchExpressionParser(),
  472. depth = 105,
  473. q = "",
  474. i;
  475. for (i = 0; i < depth/2; i++) {
  476. q = q + "{\"$and\": [{\"a\":3}, {\"$or\": [{\"b\":2},";
  477. }
  478. q = q + "{\"b\": 4}";
  479. for (i = 0; i < depth/2; i++) {
  480. q = q + "]}]}";
  481. }
  482. var res = parser.parse(JSON.parse(q));
  483. assert.strictEqual(res.description.substr(0, 43), "exceeded maximum query tree depth of 100 at");
  484. assert.strictEqual(res.code, ErrorCodes.BAD_VALUE);
  485. },
  486. "should error when depth limit is reached through a $not": function() {
  487. var parser = new MatchExpressionParser(),
  488. depth = 105,
  489. q = "{\"a\": ",
  490. i;
  491. for (i = 0; i < depth; i++) {
  492. q = q + "{\"$not\": ";
  493. }
  494. q = q + "{\"$eq\": 5}";
  495. for (i = 0; i < depth+1; i++) {
  496. q = q + "}";
  497. }
  498. var res = parser.parse(JSON.parse(q));
  499. assert.strictEqual(res.description.substr(0, 43), "exceeded maximum query tree depth of 100 at");
  500. assert.strictEqual(res.code, ErrorCodes.BAD_VALUE);
  501. },
  502. "should error when depth limit is reached through an $elemMatch": function() {
  503. var parser = new MatchExpressionParser(),
  504. depth = 105,
  505. q = "",
  506. i;
  507. for (i = 0; i < depth; i++) {
  508. q = q + "{\"a\": {\"$elemMatch\": ";
  509. }
  510. q = q + "{\"b\": 5}";
  511. for (i = 0; i < depth; i++) {
  512. q = q + "}}";
  513. }
  514. var res = parser.parse(JSON.parse(q));
  515. assert.strictEqual(res.description.substr(0, 43), "exceeded maximum query tree depth of 100 at");
  516. assert.strictEqual(res.code, ErrorCodes.BAD_VALUE);
  517. },
  518. "Should parse $not $regex and match properly": function() {
  519. var parser = new MatchExpressionParser();
  520. var a = /abc/i;
  521. var q = {"x":{"$not": a}};
  522. var res = parser.parse( q );
  523. assert.strictEqual( res.code,ErrorCodes.OK,res.description );
  524. assert.ok( ! res.result.matches({"x":"abc"}) );
  525. assert.ok( ! res.result.matches({"x":"ABC"}) );
  526. assert.ok( res.result.matches({"x":"AC"}) );
  527. }
  528. }
  529. };