Matcher2.js 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. "use strict";
  2. // Autogenerated by cport.py on 2013-09-17 14:37
  3. var Matcher2 = module.exports = function Matcher2(pattern, nested){
  4. // File: matcher.cpp lines: 83-92
  5. this._pattern = pattern;
  6. this.parser = new MatchExpressionParser();
  7. var result = this.parser.parse(pattern);
  8. if (result.code != ErrorCodes.OK)
  9. return {code:16810, description:"bad query: " + result};
  10. this._expression = result.result;
  11. }, klass = Matcher2, base = Object, proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  12. // DEPENDENCIES
  13. var errors = require("../../Errors.js"),
  14. ErrorCodes = errors.ErrorCodes,
  15. MatchExpression = require("./MatchExpression.js"),
  16. MatchExpressionParser = require("./MatchExpressionParser.js"),
  17. FalseMatchExpression = require("./FalseMatchExpression.js"),
  18. ComparisonMatchExpression = require("./ComparisonMatchExpression.js"),
  19. InMatchExpression = require("./InMatchExpression.js"),
  20. AndMatchExpression = require("./AndMatchExpression.js"),
  21. OrMatchExpression = require("./OrMatchExpression.js"),
  22. IndexKeyMatchableDocument = require('./IndexKeyMatchableDocument.js'),
  23. ListOfMatchExpression = require('./ListOfMatchExpression.js'),
  24. LeafMatchExpression = require("./LeafMatchExpression.js");
  25. // File: matcher.h lines: 82-82
  26. proto._expression = undefined;
  27. // File: matcher.h lines: 80-80
  28. proto._indexKey = undefined;
  29. // File: matcher.h lines: 79-79
  30. proto._pattern = undefined;
  31. // File: matcher.h lines: 84-84
  32. proto._spliceInfo = undefined;
  33. /**
  34. *
  35. * Figure out where our index is
  36. * @method _spliceForIndex
  37. * @param keys
  38. * @param full
  39. * @param spliceInfo
  40. *
  41. */
  42. proto._spliceForIndex = function _spliceForIndex(keys, full, spliceInfo){
  43. // File: matcher.cpp lines: 236-380
  44. var dup, i, obj, lme;
  45. switch (full) {
  46. case MatchExpression.ALWAYS_FALSE:
  47. return new FalseMatchExpression();
  48. case MatchExpression.GEO_NEAR:
  49. case MatchExpression.NOT:
  50. case MatchExpression.NOR:
  51. // maybe?
  52. return null;
  53. case MatchExpression.OR:
  54. case MatchExpression.AND:
  55. dup = new ListOfMatchExpression();
  56. for (i = 0; i < full.numChildren(); i++) {
  57. var sub = this._spliceForIndex(keys, full.getChild(i), spliceInfo);
  58. if (!sub)
  59. continue;
  60. if (!dup.get()) {
  61. if (full.matchType() == MatchExpression.AND)
  62. dup.reset(new AndMatchExpression());
  63. else
  64. dup.reset(new OrMatchExpression());
  65. }
  66. dup.add(sub);
  67. }
  68. if (dup.get()) {
  69. if (full.matchType() == MatchExpression.OR && dup.numChildren() != full.numChildren()) {
  70. // TODO: I think this should actuall get a list of all the fields
  71. // and make sure that's the same
  72. // with an $or, have to make sure its all or nothing
  73. return null;
  74. }
  75. return dup.release();
  76. }
  77. return null;
  78. case MatchExpression.EQ:
  79. var cmp = new ComparisonMatchExpression(full);
  80. if (cmp.getRHS().type() == Array) {
  81. // need to convert array to an $in
  82. if (!keys.count(cmp.path().toString()))
  83. return null;
  84. var newIn = new InMatchExpression();
  85. newIn.init(cmp.path());
  86. if (newIn.getArrayFilterEntries().addEquality(cmp.getRHS()).isOK())
  87. return null;
  88. if (cmp.getRHS().Obj().isEmpty())
  89. newIn.getArrayFilterEntries().addEquality(undefined);
  90. obj = cmp.getRHS().Obj();
  91. for(i in obj) {
  92. var s = newIn.getArrayFilterEntries().addEquality( obj[i].next() );
  93. if (s.code != ErrorCodes.OK)
  94. return null;
  95. }
  96. return newIn.release();
  97. }
  98. else if (cmp.getRHS().type() === null) {
  99. //spliceInfo.hasNullEquality = true;
  100. return null;
  101. }
  102. break;
  103. case MatchExpression.LTE:
  104. case MatchExpression.LT:
  105. case MatchExpression.GT:
  106. case MatchExpression.GTE:
  107. cmp = new ComparisonMatchExpression(full);
  108. if ( cmp.getRHS().type() === null) {
  109. // null and indexes don't play nice
  110. //spliceInfo.hasNullEquality = true;
  111. return null;
  112. }
  113. break;
  114. case MatchExpression.REGEX:
  115. case MatchExpression.MOD:
  116. lme = new LeafMatchExpression(full);
  117. if (!keys.count(lme.path().toString()))
  118. return null;
  119. return lme.shallowClone();
  120. case MatchExpression.MATCH_IN:
  121. lme = new LeafMatchExpression(full);
  122. if (!keys.count(lme.path().toString()))
  123. return null;
  124. var cloned = new InMatchExpression(lme.shallowClone());
  125. if (cloned.getArrayFilterEntries().hasEmptyArray())
  126. cloned.getArrayFilterEntries().addEquality(undefined);
  127. // since { $in : [[1]] } matches [1], need to explode
  128. for (i = cloned.getArrayFilterEntries().equalities().begin(); i != cloned.getArrayFilterEntries().equalities().end(); ++i) {
  129. var x = cloned[i];
  130. if (x.type() == Array) {
  131. for(var j in x) {
  132. cloned.getArrayFilterEntries().addEquality(x[j]);
  133. }
  134. }
  135. }
  136. return cloned;
  137. case MatchExpression.ALL:
  138. // TODO: convert to $in
  139. return null;
  140. case MatchExpression.ELEM_MATCH_OBJECT:
  141. case MatchExpression.ELEM_MATCH_VALUE:
  142. // future
  143. return null;
  144. case MatchExpression.GEO:
  145. case MatchExpression.SIZE:
  146. case MatchExpression.EXISTS:
  147. case MatchExpression.NIN:
  148. case MatchExpression.TYPE_OPERATOR:
  149. case MatchExpression.ATOMIC:
  150. case MatchExpression.WHERE:
  151. // no go
  152. return null;
  153. }
  154. return null;
  155. };
  156. /**
  157. *
  158. * return if our _expression property is atomic or not
  159. * @method atomic
  160. *
  161. */
  162. proto.atomic = function atomic(){
  163. // File: matcher.cpp lines: 120-133
  164. if (!this._expression)
  165. return false;
  166. if (this._expression.matchType() == MatchExpression.ATOMIC)
  167. return true;
  168. // we only go down one level
  169. for (var i = 0; i < this._expression.numChildren(); i++) {
  170. if (this._expression.getChild(i).matchType() == MatchExpression.ATOMIC)
  171. return true;
  172. }
  173. return false;
  174. };
  175. /**
  176. *
  177. * Return the _pattern property
  178. * @method getQuery
  179. *
  180. */
  181. proto.getQuery = function getQuery(){
  182. // File: matcher.h lines: 65-64
  183. return this._pattern;
  184. };
  185. /**
  186. *
  187. * Check if we exist
  188. * @method hasExistsFalse
  189. *
  190. */
  191. proto.hasExistsFalse = function hasExistsFalse(){
  192. // File: matcher.cpp lines: 172-180
  193. if (this._spliceInfo.hasNullEquality) {
  194. // { a : NULL } is very dangerous as it may not got indexed in some cases
  195. // so we just totally ignore
  196. return true;
  197. }
  198. return this._isExistsFalse(this._expression.get(), false, this._expression.matchType() == MatchExpression.AND ? -1 : 0);
  199. };
  200. /**
  201. *
  202. * Find if we have a matching key inside us
  203. * @method keyMatch
  204. * @param docMatcher
  205. *
  206. */
  207. proto.keyMatch = function keyMatch(docMatcher){
  208. // File: matcher.cpp lines: 199-206
  209. if (!this._expression)
  210. return docMatcher._expression.get() === null;
  211. if (!docMatcher._expression)
  212. return false;
  213. if (this._spliceInfo.hasNullEquality)
  214. return false;
  215. return this._expression.equivalent(docMatcher._expression.get());
  216. };
  217. /**
  218. *
  219. * matches checks the input doc against the internal element path to see if it is a match
  220. * @method matches
  221. * @param doc
  222. * @param details
  223. *
  224. */
  225. proto.matches = function matches(doc, details){
  226. // File: matcher.cpp lines: 105-116
  227. if (!this._expression)
  228. return true;
  229. if (this._indexKey == {})
  230. return this._expression.matchesBSON(doc, details);
  231. if ((doc != {}) && (Object.keys(doc)[0]))
  232. return this._expression.matchesBSON(doc, details);
  233. var mydoc = new IndexKeyMatchableDocument(this._indexKey, doc);
  234. return this._expression.matches(mydoc, details);
  235. };
  236. /**
  237. *
  238. * Check if we are a simple match
  239. * @method singleSimpleCriterion
  240. *
  241. */
  242. proto.singleSimpleCriterion = function singleSimpleCriterion(){
  243. // File: matcher.cpp lines: 184-196
  244. if (!this._expression)
  245. return false;
  246. if (this._expression.matchType() == MatchExpression.EQ)
  247. return true;
  248. if (this._expression.matchType() == MatchExpression.AND && this._expression.numChildren() == 1 && this._expression.getChild(0).matchType() == MatchExpression.EQ)
  249. return true;
  250. return false;
  251. };
  252. /**
  253. *
  254. * Wrapper around _spliceForIndex
  255. * @method spliceForIndex
  256. * @param key
  257. * @param full
  258. * @param spliceInfo
  259. *
  260. */
  261. proto.spliceForIndex = function spliceForIndex(key, full, spliceInfo){
  262. // File: matcher.cpp lines: 209-217
  263. var keys = [],
  264. e, i;
  265. for (i in key) {
  266. e = key[i];
  267. keys.insert(e.fieldName());
  268. }
  269. return this._spliceForIndex(keys, full, spliceInfo);
  270. };
  271. /**
  272. *
  273. * Convert _pattern into a string
  274. * @method toString
  275. *
  276. */
  277. proto.toString = function toString(){
  278. // File: matcher.h lines: 66-65
  279. return this._pattern.toString();
  280. };