MatchExpressionParser.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735
  1. "use strict";
  2. // Autogenerated by cport.py on 2013-09-17 14:37
  3. var MatchExpressionParser = module.exports = function (){
  4. }, klass = MatchExpressionParser, base = Object , proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  5. // DEPENDENCIES
  6. var errors = require("../../Errors.js"),
  7. ErrorCodes = errors.ErrorCodes,
  8. AndMatchExpression = require("./AndMatchExpression.js"),
  9. MatchExpression = require("./MatchExpression.js"),
  10. OrMatchExpression = require("./OrMatchExpression.js"),
  11. ModMatchExpression = require("./ModMatchExpression.js"),
  12. NorMatchExpression = require("./NorMatchExpression.js"),
  13. NotMatchExpression = require("./NotMatchExpression.js"),
  14. LTMatchExpression = require("./LTMatchExpression.js"),
  15. LTEMatchExpression = require("./LTEMatchExpression.js"),
  16. GTMatchExpression = require("./GTMatchExpression.js"),
  17. GTEMatchExpression = require("./GTEMatchExpression.js"),
  18. InMatchExpression = require("./InMatchExpression.js"),
  19. SizeMatchExpression = require("./SizeMatchExpression.js"),
  20. TypeMatchExpression = require("./TypeMatchExpression.js"),
  21. ExistsMatchExpression = require("./ExistsMatchExpression.js"),
  22. EqualityMatchExpression = require("./EqualityMatchExpression.js"),
  23. ArrayMatchingMatchExpression = require("./ArrayMatchingMatchExpression.js"),
  24. RegexMatchExpression = require("./RegexMatchExpression.js"),
  25. FalseMatchExpression = require("./FalseMatchExpression.js"),
  26. ComparisonMatchExpression = require("./ComparisonMatchExpression.js"),
  27. ElemMatchValueMatchExpression = require("./ElemMatchValueMatchExpression.js"),
  28. ElemMatchObjectMatchExpression = require("./ElemMatchObjectMatchExpression.js"),
  29. AllElemMatchOp = require("./AllElemMatchOp.js"),
  30. AtomicMatchExpression = require("./AtomicMatchExpression.js");
  31. /**
  32. *
  33. * Check if the input element is an expression
  34. * @method _isExpressionDocument
  35. * @param element
  36. *
  37. */
  38. proto._isExpressionDocument = function _isExpressionDocument(element){
  39. // File: expression_parser.cpp lines: 340-355
  40. if (!(element instanceof Object))
  41. return false;
  42. if (Object.keys(element).length === 0)
  43. return false;
  44. var name = Object.keys(element)[0];
  45. if (name[0] != '$')
  46. return false;
  47. if ("$ref" == name)
  48. return false;
  49. return true;
  50. };
  51. /**
  52. *
  53. * Parse the input object into individual elements
  54. * @method _parse
  55. * @param obj
  56. * @param topLevel
  57. *
  58. */
  59. proto._parse = function _parse(obj, topLevel){
  60. // File: expression_parser.cpp lines: 217-319
  61. var rest, temp, status, element, eq, real;
  62. var root = new AndMatchExpression();
  63. var objkeys = Object.keys(obj);
  64. var currname, currval;
  65. for (var i = 0; i < objkeys.length; i++) {
  66. currname = objkeys[i];
  67. currval = obj[currname];
  68. if (currname[0] == '$' ) {
  69. rest = currname.substr(1);
  70. // TODO: optimize if block?
  71. if ("or" == rest) {
  72. if (!(currval instanceof Array))
  73. return {code:ErrorCodes.BAD_VALUE, description:"$or needs an array"};
  74. temp = new OrMatchExpression();
  75. status = this._parseTreeList(currval, temp);
  76. if (status.code != ErrorCodes.OK)
  77. return status;
  78. root.add(temp);
  79. }
  80. else if ("and" == rest) {
  81. if (!(currval instanceof Array))
  82. return {code:ErrorCodes.BAD_VALUE, description:"and needs an array"};
  83. temp = new AndMatchExpression();
  84. status = this._parseTreeList(currval, temp);
  85. if (status.code != ErrorCodes.OK)
  86. return status;
  87. root.add(temp);
  88. }
  89. else if ("nor" == rest) {
  90. if (!(currval instanceof Array))
  91. return {code:ErrorCodes.BAD_VALUE, description:"and needs an array"};
  92. temp = new NorMatchExpression();
  93. status = this._parseTreeList(currval, temp);
  94. if (status.code != ErrorCodes.OK)
  95. return status;
  96. root.add(temp);
  97. }
  98. else if (("atomic" == rest) || ("isolated" == rest)) {
  99. if (!topLevel)
  100. return {code:ErrorCodes.BAD_VALUE, description:"$atomic/$isolated has to be at the top level"};
  101. if (element)
  102. root.add(new AtomicMatchExpression());
  103. }
  104. else if ("where" == rest) {
  105. /*
  106. if ( !topLevel )
  107. return StatusWithMatchExpression( ErrorCodes::BAD_VALUE, "$where has to be at the top level" );
  108. */
  109. return {'code':'FAILED_TO_PARSE', 'desc':'Where unimplimented.'};
  110. /*
  111. status = this.expressionParserWhereCallback(element);
  112. if (status.code != ErrorCodes.OK)
  113. return status;
  114. root.add(status.result);*/
  115. }
  116. else if ("comment" == rest) {
  117. 1+1;
  118. }
  119. else {
  120. return {code:ErrorCodes.BAD_VALUE, description:"unknown top level operator: " + currname};
  121. }
  122. continue;
  123. }
  124. if (this._isExpressionDocument(currval)) {
  125. status = this._parseSub(currname, currval, root);
  126. if (status.code != ErrorCodes.OK)
  127. return status;
  128. continue;
  129. }
  130. if (currval instanceof RegExp) {
  131. status = this._parseRegexElement(currname, currval);
  132. if (status.code != ErrorCodes.OK)
  133. return status;
  134. root.add(status.result);
  135. continue;
  136. }
  137. eq = new EqualityMatchExpression();
  138. status = eq.init(currname, currval);
  139. if (status.code != ErrorCodes.OK)
  140. return status;
  141. root.add(eq);
  142. }
  143. if (root.numChildren() == 1) {
  144. return {code:ErrorCodes.OK, result:root.getChild(0)};
  145. }
  146. return {code:ErrorCodes.OK, result:root};
  147. };
  148. /**
  149. *
  150. * Parse the $all element
  151. * @method _parseAll
  152. * @param name
  153. * @param element
  154. *
  155. */
  156. proto._parseAll = function _parseAll(name, element){
  157. // File: expression_parser.cpp lines: 512-583
  158. var status, i;
  159. if (!(element instanceof Array))
  160. return {code:ErrorCodes.BAD_VALUE, description:"$all needs an array"};
  161. var arr = element;
  162. if ((arr[0] instanceof Object) && ("$elemMatch" == Object.keys(arr[0])[0])) {
  163. // $all : [ { $elemMatch : {} } ... ]
  164. var temp = new AllElemMatchOp();
  165. status = temp.init(name);
  166. if (status.code != ErrorCodes.OK)
  167. return status;
  168. for (i = 0; i < arr.length; i++) {
  169. var hopefullyElemMatchElement = arr[i];
  170. if (!(hopefullyElemMatchElement instanceof Object)) {
  171. // $all : [ { $elemMatch : ... }, 5 ]
  172. return {code:ErrorCodes.BAD_VALUE, description:"$all/$elemMatch has to be consistent"};
  173. }
  174. if ("$elemMatch" != Object.keys(hopefullyElemMatchElement)[0]) {
  175. // $all : [ { $elemMatch : ... }, { x : 5 } ]
  176. return {code:ErrorCodes.BAD_VALUE, description:"$all/$elemMatch has to be consistent"};
  177. }
  178. status = this._parseElemMatch("", hopefullyElemMatchElement.$elemMatch ); // TODO: wrong way to do this?
  179. if (status.code != ErrorCodes.OK)
  180. return status;
  181. temp.add(status.result);
  182. }
  183. return {code:ErrorCodes.OK, result:temp};
  184. }
  185. var myAnd = new AndMatchExpression();
  186. for (i = 0; i < arr.length; i++) {
  187. var e = arr[i];
  188. if (e instanceof RegExp) {
  189. var r = new RegexMatchExpression();
  190. status = r.init(name, e);
  191. if (status.code != ErrorCodes.OK)
  192. return status;
  193. myAnd.add(r);
  194. }
  195. else if ((e instanceof Object) && (typeof(Object.keys(e)[0] == 'string' && Object.keys(e)[0][0] == '$' ))) {
  196. return {code:ErrorCodes.BAD_VALUE, description:"no $ expressions in $all"};
  197. }
  198. else {
  199. var x = new EqualityMatchExpression();
  200. status = x.init(name, e);
  201. if (status.code != ErrorCodes.OK)
  202. return status;
  203. myAnd.add(x);
  204. }
  205. }
  206. if (myAnd.numChildren() === 0) {
  207. return {code:ErrorCodes.OK, result:new FalseMatchExpression()};
  208. }
  209. return {code:ErrorCodes.OK, result:myAnd};
  210. };
  211. /**
  212. *
  213. * Parse the input array and add new RegexMatchExpressions to entries
  214. * @method _parseArrayFilterEntries
  215. * @param entries
  216. * @param theArray
  217. *
  218. */
  219. proto._parseArrayFilterEntries = function _parseArrayFilterEntries(entries, theArray){
  220. // File: expression_parser.cpp lines: 445-468
  221. var status, e, r;
  222. for (var i = 0; i < theArray.length; i++) {
  223. e = theArray[i];
  224. if (e instanceof RegExp ) {
  225. r = new RegexMatchExpression();
  226. status = r.init("", e);
  227. if (status.code != ErrorCodes.OK)
  228. return status;
  229. status = entries.addRegex(r);
  230. if (status.code != ErrorCodes.OK)
  231. return status;
  232. }
  233. else {
  234. status = entries.addEquality(e);
  235. if (status.code != ErrorCodes.OK)
  236. return status;
  237. }
  238. }
  239. return {code:ErrorCodes.OK};
  240. };
  241. /**
  242. *
  243. * Parse the input ComparisonMatchExpression
  244. * @method _parseComparison
  245. * @param name
  246. * @param cmp
  247. * @param element
  248. *
  249. */
  250. proto._parseComparison = function _parseComparison(name, cmp, element){
  251. // File: expression_parser.cpp lines: 34-43
  252. var temp = new ComparisonMatchExpression(cmp);
  253. var status = temp.init(name, element);
  254. if (status.code != ErrorCodes.OK)
  255. return status;
  256. return {code:ErrorCodes.OK, result:temp};
  257. };
  258. /**
  259. *
  260. * Parse an element match into the appropriate expression
  261. * @method _parseElemMatch
  262. * @param name
  263. * @param element
  264. *
  265. */
  266. proto._parseElemMatch = function _parseElemMatch(name, element){
  267. // File: expression_parser.cpp lines: 471-509
  268. var temp, status;
  269. if (!(element instanceof Object))
  270. return {code:ErrorCodes.BAD_VALUE, description:"$elemMatch needs an Object"};
  271. if (this._isExpressionDocument(element)) {
  272. // value case
  273. var theAnd = new AndMatchExpression();
  274. status = this._parseSub("", element, theAnd);
  275. if (status.code != ErrorCodes.OK)
  276. return status;
  277. temp = new ElemMatchValueMatchExpression();
  278. status = temp.init(name);
  279. if (status.code != ErrorCodes.OK)
  280. return status;
  281. for (var i = 0; i < theAnd.numChildren(); i++ ) {
  282. temp.add(theAnd.getChild(i));
  283. }
  284. theAnd.clearAndRelease();
  285. return {code:ErrorCodes.OK, result:temp};
  286. }
  287. // object case
  288. status = this._parse(element, false);
  289. if (status.code != ErrorCodes.OK)
  290. return status;
  291. temp = new ElemMatchObjectMatchExpression();
  292. status = temp.init(name, status.result);
  293. if (status.code != ErrorCodes.OK)
  294. return status;
  295. return {code:ErrorCodes.OK, result:temp};
  296. };
  297. /**
  298. *
  299. * Parse a ModMatchExpression
  300. * @method _parseMOD
  301. * @param name
  302. * @param element
  303. *
  304. */
  305. proto._parseMOD = function _parseMOD(name, element){
  306. // File: expression_parser.cpp lines: 360-387
  307. var d,r;
  308. if (!(element instanceof Array))
  309. return {code:ErrorCodes.BAD_VALUE, result:"malformed mod, needs to be an array"};
  310. if (element.length < 2)
  311. return {code:ErrorCodes.BAD_VALUE, result:"malformed mod, not enough elements"};
  312. if (element.length > 2)
  313. return {code:ErrorCodes.BAD_VALUE, result:"malformed mod, too many elements"};
  314. if ((typeof(element[0]) != 'number')) {
  315. return {code:ErrorCodes.BAD_VALUE, result:"malformed mod, divisor not a number"};
  316. } else {
  317. d = element[0];
  318. }
  319. if (( typeof(element[1]) != 'number') ) {
  320. r = 0;
  321. } else {
  322. r = element[1];
  323. }
  324. var temp = new ModMatchExpression();
  325. var status = temp.init( name, d, r);
  326. if (status.code != ErrorCodes.OK)
  327. return status;
  328. return {code:ErrorCodes.OK, result:temp};
  329. };
  330. /**
  331. *
  332. * Parse a NotMatchExpression
  333. * @method _parseNot
  334. * @param name
  335. * @param element
  336. *
  337. */
  338. proto._parseNot = function _parseNot(name, element){
  339. // File: expression_parser_tree.cpp lines: 55-91
  340. var status;
  341. if (element instanceof RegExp) {
  342. status = this._parseRegexElement(name, element);
  343. if (status.code != ErrorCodes.OK)
  344. return status;
  345. var n = new NotMatchExpression();
  346. status = n.init(status.result);
  347. if (status.code != ErrorCodes.OK)
  348. return status;
  349. return {code:ErrorCodes.OK, result:n};
  350. }
  351. if (!(element instanceof Object))
  352. return {code:ErrorCodes.BAD_VALUE, result:"$not needs a regex or a document"};
  353. if (element == {})
  354. return {code:ErrorCodes.BAD_VALUE, result:"$not cannot be empty"};
  355. var theAnd = new AndMatchExpression();
  356. status = this._parseSub(name, element, theAnd);
  357. if (status.code != ErrorCodes.OK)
  358. return status;
  359. // TODO: this seems arbitrary?
  360. // tested in jstests/not2.js
  361. for (var i = 0; i < theAnd.numChildren(); i++) {
  362. if (theAnd.getChild(i).matchType == MatchExpression.REGEX) {
  363. return {code:ErrorCodes.BAD_VALUE, result:"$not cannot have a regex"};
  364. }
  365. }
  366. var theNot = new NotMatchExpression();
  367. status = theNot.init(theAnd);
  368. if (status.code != ErrorCodes.OK)
  369. return status;
  370. return {code:ErrorCodes.OK, result:theNot};
  371. };
  372. /**
  373. *
  374. * Parse a RegexMatchExpression
  375. * @method _parseRegexDocument
  376. * @param name
  377. * @param doc
  378. *
  379. */
  380. proto._parseRegexDocument = function _parseRegexDocument(name, doc){
  381. // File: expression_parser.cpp lines: 402-442
  382. var regex = '', regexOptions = '', e;
  383. if(doc.$regex) {
  384. e = doc.$regex;
  385. if(e instanceof RegExp) {
  386. var str = e.toString(),
  387. flagIndex = 0;
  388. for (var c = str.length; c > 0; c--){
  389. if (str[c] == '/') {
  390. flagIndex = c;
  391. break;
  392. }
  393. }
  394. regex = (flagIndex? str : str.substr(1, flagIndex-1));
  395. regexOptions = str.substr(flagIndex, str.length);
  396. } else if (typeof(e) == 'string') {
  397. regex = e;
  398. } else {
  399. return {code:ErrorCodes.BAD_VALUE, description:"$regex has to be a string"};
  400. }
  401. }
  402. if(doc.$options) {
  403. e = doc.$options;
  404. if(typeof(e) == 'string') {
  405. regexOptions = e;
  406. } else {
  407. return {code:ErrorCodes.BAD_VALUE, description:"$options has to be a string"};
  408. }
  409. }
  410. var temp = new RegexMatchExpression();
  411. var status = temp.init(name, regex, regexOptions);
  412. if (status.code != ErrorCodes.OK)
  413. return status;
  414. return {code:ErrorCodes.OK, result:temp};
  415. };
  416. /**
  417. *
  418. * Parse an element into a RegexMatchExpression
  419. * @method _parseRegexElement
  420. * @param name
  421. * @param element
  422. *
  423. */
  424. proto._parseRegexElement = function _parseRegexElement(name, element){
  425. // File: expression_parser.cpp lines: 390-399
  426. if (!(element instanceof RegExp))
  427. return {code:ErrorCodes.BAD_VALUE, description:"not a regex"};
  428. var str = element.toString(),
  429. flagIndex = 0;
  430. for (var c = str.length; c > 0; c--){
  431. if (str[c] == '/') {
  432. flagIndex = c;
  433. break;
  434. }
  435. }
  436. var regex = str.substr(1, flagIndex-1),
  437. regexOptions = str.substr(flagIndex+1, str.length),
  438. temp = new RegexMatchExpression(),
  439. status = temp.init(name, regex, regexOptions);
  440. if (status.code != ErrorCodes.OK)
  441. return status;
  442. return {code:ErrorCodes.OK, result:temp};
  443. };
  444. /**
  445. *
  446. * Parse a sub expression
  447. * @method _parseSub
  448. * @param name
  449. * @param sub
  450. * @param root
  451. *
  452. */
  453. proto._parseSub = function _parseSub(name, sub, root){
  454. // File: expression_parser.cpp lines: 322-337
  455. var subkeys = Object.keys(sub),
  456. currname, currval;
  457. for (var i = 0; i < subkeys.length; i++) {
  458. currname = subkeys[i];
  459. currval = sub[currname];
  460. var deep = {};
  461. deep[currname] = currval;
  462. var status = this._parseSubField(sub, root, name, deep);
  463. if (status.code != ErrorCodes.OK)
  464. return status;
  465. if (status.result)
  466. root.add(status.result);
  467. }
  468. return {code:ErrorCodes.OK, result:root};
  469. };
  470. /**
  471. *
  472. * Parse a sub expression field
  473. * @method _parseSubField
  474. * @param context
  475. * @param andSoFar
  476. * @param name
  477. * @param element
  478. *
  479. */
  480. proto._parseSubField = function _parseSubField(context, andSoFar, name, element){
  481. // File: expression_parser.cpp lines: 46-214
  482. // TODO: these should move to getGtLtOp, or its replacement
  483. var currname = Object.keys(element)[0];
  484. var currval = element[currname];
  485. if ("$eq" == currname)
  486. return this._parseComparison(name, 'EQ', currval);
  487. if ("$not" == currname) {
  488. return this._parseNot(name, currval);
  489. }
  490. var status, temp, temp2;
  491. switch (currname) {
  492. case '$lt':
  493. return this._parseComparison(name, 'LT', currval);
  494. case '$lte':
  495. return this._parseComparison(name, 'LTE', currval);
  496. case '$gt':
  497. return this._parseComparison(name, 'GT', currval);
  498. case '$gte':
  499. return this._parseComparison(name, 'GTE', currval);
  500. case '$ne':
  501. status = this._parseComparison(name, 'EQ', currval);
  502. if (status.code != ErrorCodes.OK)
  503. return status;
  504. var n = new NotMatchExpression();
  505. status = n.init(status.result);
  506. if (status.code != ErrorCodes.OK)
  507. return status;
  508. return {code:ErrorCodes.OK, result:n};
  509. case '$eq':
  510. return this._parseComparison(name, 'EQ', currval);
  511. case '$in':
  512. if (!(currval instanceof Array))
  513. return {code:ErrorCodes.BAD_VALUE, description:"$in needs an array"};
  514. temp = new InMatchExpression();
  515. status = temp.init(name);
  516. if (status.code != ErrorCodes.OK)
  517. return status;
  518. status = this._parseArrayFilterEntries(temp.getArrayFilterEntries(), currval);
  519. if (status.code != ErrorCodes.OK)
  520. return status;
  521. return {code:ErrorCodes.OK, result:temp};
  522. case '$nin':
  523. if (!(currval instanceof Array))
  524. return {code:ErrorCodes.BAD_VALUE, description:"$nin needs an array"};
  525. temp = new InMatchExpression();
  526. status = temp.init(name);
  527. if (status.code != ErrorCodes.OK)
  528. return status;
  529. status = this._parseArrayFilterEntries(temp.getArrayFilterEntries(), currval);
  530. if (status.code != ErrorCodes.OK)
  531. return status;
  532. temp2 = new NotMatchExpression();
  533. status = temp2.init(temp);
  534. if (status.code != ErrorCodes.OK)
  535. return status;
  536. return {code:ErrorCodes.OK, result:temp2};
  537. case '$size':
  538. var size = 0;
  539. if ( typeof(currval) === 'string')
  540. // matching old odd semantics
  541. size = 0;
  542. else if (typeof(currval) === 'number')
  543. size = currval;
  544. else {
  545. return {code:ErrorCodes.BAD_VALUE, description:"$size needs a number"};
  546. }
  547. temp = new SizeMatchExpression();
  548. status = temp.init(name, size);
  549. if (status.code != ErrorCodes.OK)
  550. return status;
  551. return {code:ErrorCodes.OK, result:temp};
  552. case '$exists':
  553. if (currval == {})
  554. return {code:ErrorCodes.BAD_VALUE, description:"$exists can't be eoo"};
  555. temp = new ExistsMatchExpression();
  556. status = temp.init(name);
  557. if (status.code != ErrorCodes.OK)
  558. return status;
  559. if (currval)
  560. return {code:ErrorCodes.OK, result:temp};
  561. temp2 = new NotMatchExpression();
  562. status = temp2.init(temp);
  563. if (status.code != ErrorCodes.OK)
  564. return status;
  565. return {code:ErrorCodes.OK, result:temp2};
  566. case '$type':
  567. if (typeof(currval) != 'number')
  568. return {code:ErrorCodes.BAD_VALUE, description:"$type has to be a number"};
  569. var type = currval;
  570. temp = new TypeMatchExpression();
  571. status = temp.init(name, type);
  572. if (status.code != ErrorCodes.OK)
  573. return status;
  574. return {code:ErrorCodes.OK, result:temp};
  575. case '$mod':
  576. return this._parseMOD(name, currval);
  577. case '$options':
  578. // TODO: try to optimize this
  579. // we have to do this since $options can be before or after a $regex
  580. // but we validate here
  581. for(var i = 0; i < Object.keys(context).length; i++) {
  582. temp = Object.keys(context)[i];
  583. if (temp == '$regex')
  584. return {code:ErrorCodes.OK, result:null};
  585. }
  586. return {code:ErrorCodes.BAD_VALUE, description:"$options needs a $regex"};
  587. case '$regex':
  588. return this._parseRegexDocument(name, context);
  589. case '$elemMatch':
  590. return this._parseElemMatch(name, currval);
  591. case '$all':
  592. return this._parseAll(name, currval);
  593. case '$geoWithin':
  594. case '$geoIntersects':
  595. case '$near':
  596. case '$nearSphere':
  597. var x = 'Temporary value until Geo fns implimented.';
  598. return this.expressionParserGeoCallback(name, x, context);
  599. default:
  600. return {code:ErrorCodes.BAD_VALUE, description:"not handled: " + element};
  601. } // end switch
  602. return {code:ErrorCodes.BAD_VALUE, description:"not handled: " + element};
  603. };
  604. /**
  605. *
  606. * Parse a list of parsable elements
  607. * @method _parseTreeList
  608. * @param arr
  609. * @param out
  610. *
  611. */
  612. proto._parseTreeList = function _parseTreeList(arr, out){
  613. // File: expression_parser_tree.cpp lines: 33-52
  614. if (arr.length === 0)
  615. return {code:ErrorCodes.BAD_VALUE, description:"$and/$or/$nor must be a nonempty array"};
  616. var status, element;
  617. for (var i = 0; i < arr.length; i++) {
  618. element = arr[i];
  619. if (!(element instanceof Object))
  620. return {code:ErrorCodes.BAD_VALUE, description:"$or/$and/$nor entries need to be full objects"};
  621. status = this._parse(element, false);
  622. if (status.code != ErrorCodes.OK)
  623. return status;
  624. out.add(status.result);
  625. }
  626. return {code:ErrorCodes.OK};
  627. };
  628. /**
  629. *
  630. * Wrapper for _parse
  631. * @method parse
  632. * @param obj
  633. *
  634. */
  635. proto.parse = function parse(obj){
  636. // File: expression_parser.h lines: 40-41
  637. return this._parse(obj, true);
  638. };