ElementPath.js 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. "use strict";
  2. var FieldRef = require('./FieldRef');
  3. // Autogenerated by cport.py on 2013-09-17 14:37
  4. var ElementPath = module.exports = function ElementPath(){
  5. this._fieldRef = new FieldRef();
  6. this._shouldTraverseLeafArray = false;
  7. }, klass = ElementPath, base = Object , proto = klass.prototype = Object.create(base.prototype, {constructor:{value:klass}});
  8. // File: path.h lines: 41-41
  9. // FieldRef _fieldRef;
  10. proto._fieldRef = undefined;
  11. // File: path.h lines: 42-42
  12. // bool _shouldTraverseLeafArray;
  13. proto._shouldTraverseLeafArray = undefined;
  14. /**
  15. * getFieldDottedOrArray
  16. *
  17. * @method getFieldDottedArray
  18. * @param doc
  19. * @param path
  20. * @param idxPathObj This is an object with a pathID element. This allows for pass by ref in calling function.
  21. * */
  22. klass.getFieldDottedOrArray = function getFieldDottedOrArray(doc, path, idxPathObj){
  23. // File path_internal.cpp lines 31-72
  24. if (path.numParts() === 0 ) { return doc; }
  25. var res,curr = doc,
  26. stop = false,
  27. partNum = 0;
  28. while (partNum < path.numParts() && !stop) {
  29. res = curr[path.getPart( partNum)];
  30. if(res == {}){
  31. stop = true;
  32. } else if (res instanceof Object) {
  33. curr = res;
  34. partNum++;
  35. } else if (res instanceof Array) {
  36. stop = true;
  37. } else {
  38. if (partNum + 1 < path.numParts() ) {
  39. res = {};
  40. }
  41. stop = true;
  42. }
  43. }
  44. //idxPathObj.pathID = partNum;
  45. return res;
  46. };
  47. /**
  48. * isAllDigits does what it says on the tin.
  49. *
  50. * @method isAllDigits
  51. * @param str
  52. */
  53. klass.isAllDigits = function isAllDigits ( str ){
  54. // File path_internal.cpp lines 23-29
  55. var digitCheck = /\D/g;
  56. if (digitCheck.exec(str) === null){ return true; }
  57. return false;
  58. };
  59. /**
  60. *
  61. * return the internal fieldRef object
  62. * @method fieldRef
  63. * @param
  64. *
  65. */
  66. proto.fieldRef = function fieldRef( /* */ ){
  67. // File: path.h lines: 37-36
  68. return this._fieldRef;
  69. };
  70. /**
  71. *
  72. * Initialize necessary items on this instance
  73. * @method init
  74. * @param path
  75. *
  76. */
  77. proto.init = function init( path ){ // const StringData& path
  78. // File: path.cpp lines: 26-29
  79. this._shouldTraverseLeafArray = true;
  80. this._fieldRef.parse( path );
  81. return {'code':'OK'};
  82. };
  83. /**
  84. *
  85. * Set whether paths should traverse leaves inside arrays
  86. * @method setTraverseLeafArray
  87. * @param
  88. *
  89. */
  90. proto.setTraverseLeafArray = function setTraverseLeafArray( b ){ // bool b
  91. // File: path.h lines: 35-34
  92. this._shouldTraverseLeafArray = b;
  93. };
  94. /**
  95. *
  96. * Return whether arrays should traverse leaf arrays
  97. * @method shouldTraverseLeafArray
  98. * @param
  99. *
  100. */
  101. proto.shouldTraverseLeafArray = function shouldTraverseLeafArray( /* */ ){
  102. // File: path.h lines: 38-37
  103. return this._shouldTraverseLeafArray;
  104. };
  105. proto.objAtPath = function objAtPath(doc) {
  106. return klass.objAtPath(doc, this._fieldRef._path);
  107. };
  108. klass.objAtPath = function objAtPath(doc, path) {
  109. if(path.length === 0) {
  110. return doc;
  111. }
  112. if (path.length > 0 && Object.keys(doc).length === 0){
  113. return {};
  114. }
  115. if (doc === null || doc === undefined) {
  116. return doc;
  117. }
  118. var tpath = path.split('.');
  119. return klass.objAtPath(doc[tpath[0]],tpath.slice(1).join('.'));
  120. };
  121. /**
  122. *
  123. * Helper to wrap our path into the static method
  124. * @method _matches
  125. * @param doc
  126. * @param details
  127. * @param function checker this function is used to check for a valid item at the end of the path
  128. *
  129. */
  130. proto._matches = function _matches(doc, details, checker) {
  131. return klass._matches(doc, this._fieldRef._array, this._shouldTraverseLeafArray, details, checker);
  132. };
  133. /**
  134. *
  135. * _matches exists because we don't have pathIterators, so we need a recursive function call
  136. * through the path pieces
  137. * @method _matches
  138. * @param doc
  139. * @param path
  140. * @param details
  141. * @param function checker this function is used to check for a valid item at the end of the path
  142. *
  143. */
  144. klass._matches = function _matches(doc, path, shouldTraverseLeafArray, details, checker){
  145. // File: expression_array.cpp lines: 34-53
  146. var k, result, ii, il,
  147. curr = doc,
  148. item = doc;
  149. for (k = 0; k < path.length; k++) {
  150. if((curr instanceof Object) && (path[k] in curr)) {
  151. item = curr[path[k]];
  152. }
  153. if(path[k].length === 0)
  154. continue;
  155. item = curr[path[k]];
  156. if (item instanceof Object && item.constructor === Object) {
  157. if (!(isNaN(parseInt(path[k], 10)))) {
  158. result = checker(item[path[k]]);
  159. if (result) {
  160. if (details && details.needRecord())
  161. details.setElemMatchKey(ii.toString());
  162. return result;
  163. }
  164. }
  165. curr = item;
  166. continue;
  167. } else if (item instanceof Object && item.constructor === Array) {
  168. if (k == path.length-1) {
  169. if ((shouldTraverseLeafArray) && (isNaN(parseInt(path[k], 10)))) {
  170. for (ii = 0, il = item.length; ii < il; ii++) {
  171. result = checker(item[ii]);
  172. if (result) {
  173. if (details && details.needRecord())
  174. details.setElemMatchKey(ii.toString());
  175. return result;
  176. }
  177. }
  178. if(item.length === 0)
  179. return checker({});
  180. }
  181. curr = item;
  182. break; // this is the end of the path, so check this array
  183. } else if (!(isNaN(parseInt(path[k+1], 10)))) {
  184. curr = item;
  185. continue; // the *next* path section is an item in the array so we don't check this whole array
  186. }
  187. // otherwise, check each item in the array against the rest of the path
  188. for(ii = 0, il = item.length; ii < il; ii++){
  189. var subitem = item[ii];
  190. if (subitem.constructor !== Object) continue; // can't look for a subfield in a non-object value.
  191. if (this._matches(subitem, path.slice(k), shouldTraverseLeafArray, null, checker)) { // check the item against the rest of the path
  192. if (details && details.needRecord())
  193. details.setElemMatchKey(ii.toString());
  194. return true;
  195. }
  196. }
  197. return false; // checked all items in the array and found no matches
  198. }
  199. }
  200. return checker(item);
  201. };