MatchExpressionParser_test.js 21 KB

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