utils.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. "use strict";
  2. var MongoError = require('mongodb-core').MongoError
  3. var shallowClone = function(obj) {
  4. var copy = {};
  5. for(var name in obj) copy[name] = obj[name];
  6. return copy;
  7. }
  8. // Set simple property
  9. var getSingleProperty = function(obj, name, value) {
  10. Object.defineProperty(obj, name, {
  11. enumerable:true,
  12. get: function() {
  13. return value
  14. }
  15. });
  16. }
  17. var formatSortValue = exports.formatSortValue = function(sortDirection) {
  18. var value = ("" + sortDirection).toLowerCase();
  19. switch (value) {
  20. case 'ascending':
  21. case 'asc':
  22. case '1':
  23. return 1;
  24. case 'descending':
  25. case 'desc':
  26. case '-1':
  27. return -1;
  28. default:
  29. throw new Error("Illegal sort clause, must be of the form "
  30. + "[['field1', '(ascending|descending)'], "
  31. + "['field2', '(ascending|descending)']]");
  32. }
  33. };
  34. var formattedOrderClause = exports.formattedOrderClause = function(sortValue) {
  35. var orderBy = {};
  36. if(sortValue == null) return null;
  37. if (Array.isArray(sortValue)) {
  38. if(sortValue.length === 0) {
  39. return null;
  40. }
  41. for(var i = 0; i < sortValue.length; i++) {
  42. if(sortValue[i].constructor == String) {
  43. orderBy[sortValue[i]] = 1;
  44. } else {
  45. orderBy[sortValue[i][0]] = formatSortValue(sortValue[i][1]);
  46. }
  47. }
  48. } else if(sortValue != null && typeof sortValue == 'object') {
  49. orderBy = sortValue;
  50. } else if (typeof sortValue == 'string') {
  51. orderBy[sortValue] = 1;
  52. } else {
  53. throw new Error("Illegal sort clause, must be of the form " +
  54. "[['field1', '(ascending|descending)'], ['field2', '(ascending|descending)']]");
  55. }
  56. return orderBy;
  57. };
  58. var checkCollectionName = function checkCollectionName (collectionName) {
  59. if('string' !== typeof collectionName) {
  60. throw Error("collection name must be a String");
  61. }
  62. if(!collectionName || collectionName.indexOf('..') != -1) {
  63. throw Error("collection names cannot be empty");
  64. }
  65. if(collectionName.indexOf('$') != -1 &&
  66. collectionName.match(/((^\$cmd)|(oplog\.\$main))/) == null) {
  67. throw Error("collection names must not contain '$'");
  68. }
  69. if(collectionName.match(/^\.|\.$/) != null) {
  70. throw Error("collection names must not start or end with '.'");
  71. }
  72. // Validate that we are not passing 0x00 in the colletion name
  73. if(!!~collectionName.indexOf("\x00")) {
  74. throw new Error("collection names cannot contain a null character");
  75. }
  76. };
  77. var handleCallback = function(callback, err, value1, value2) {
  78. try {
  79. if(callback == null) return;
  80. if(callback) {
  81. return value2 ? callback(err, value1, value2) : callback(err, value1);
  82. }
  83. } catch(err) {
  84. process.nextTick(function() { throw err; });
  85. return false;
  86. }
  87. return true;
  88. }
  89. /**
  90. * Wrap a Mongo error document in an Error instance
  91. * @ignore
  92. * @api private
  93. */
  94. var toError = function(error) {
  95. if (error instanceof Error) return error;
  96. var msg = error.err || error.errmsg || error.errMessage || error;
  97. var e = MongoError.create({message: msg, driver:true});
  98. // Get all object keys
  99. var keys = typeof error == 'object'
  100. ? Object.keys(error)
  101. : [];
  102. for(var i = 0; i < keys.length; i++) {
  103. try {
  104. e[keys[i]] = error[keys[i]];
  105. } catch(err) {
  106. // continue
  107. }
  108. }
  109. return e;
  110. }
  111. /**
  112. * @ignore
  113. */
  114. var normalizeHintField = function normalizeHintField(hint) {
  115. var finalHint = null;
  116. if(typeof hint == 'string') {
  117. finalHint = hint;
  118. } else if(Array.isArray(hint)) {
  119. finalHint = {};
  120. hint.forEach(function(param) {
  121. finalHint[param] = 1;
  122. });
  123. } else if(hint != null && typeof hint == 'object') {
  124. finalHint = {};
  125. for (var name in hint) {
  126. finalHint[name] = hint[name];
  127. }
  128. }
  129. return finalHint;
  130. };
  131. /**
  132. * Create index name based on field spec
  133. *
  134. * @ignore
  135. * @api private
  136. */
  137. var parseIndexOptions = function(fieldOrSpec) {
  138. var fieldHash = {};
  139. var indexes = [];
  140. var keys;
  141. // Get all the fields accordingly
  142. if('string' == typeof fieldOrSpec) {
  143. // 'type'
  144. indexes.push(fieldOrSpec + '_' + 1);
  145. fieldHash[fieldOrSpec] = 1;
  146. } else if(Array.isArray(fieldOrSpec)) {
  147. fieldOrSpec.forEach(function(f) {
  148. if('string' == typeof f) {
  149. // [{location:'2d'}, 'type']
  150. indexes.push(f + '_' + 1);
  151. fieldHash[f] = 1;
  152. } else if(Array.isArray(f)) {
  153. // [['location', '2d'],['type', 1]]
  154. indexes.push(f[0] + '_' + (f[1] || 1));
  155. fieldHash[f[0]] = f[1] || 1;
  156. } else if(isObject(f)) {
  157. // [{location:'2d'}, {type:1}]
  158. keys = Object.keys(f);
  159. keys.forEach(function(k) {
  160. indexes.push(k + '_' + f[k]);
  161. fieldHash[k] = f[k];
  162. });
  163. } else {
  164. // undefined (ignore)
  165. }
  166. });
  167. } else if(isObject(fieldOrSpec)) {
  168. // {location:'2d', type:1}
  169. keys = Object.keys(fieldOrSpec);
  170. keys.forEach(function(key) {
  171. indexes.push(key + '_' + fieldOrSpec[key]);
  172. fieldHash[key] = fieldOrSpec[key];
  173. });
  174. }
  175. return {
  176. name: indexes.join("_"), keys: keys, fieldHash: fieldHash
  177. }
  178. }
  179. var isObject = exports.isObject = function (arg) {
  180. return '[object Object]' == toString.call(arg)
  181. }
  182. var debugOptions = function(debugFields, options) {
  183. var finaloptions = {};
  184. debugFields.forEach(function(n) {
  185. finaloptions[n] = options[n];
  186. });
  187. return finaloptions;
  188. }
  189. var decorateCommand = function(command, options, exclude) {
  190. for(var name in options) {
  191. if(exclude[name] == null) command[name] = options[name];
  192. }
  193. return command;
  194. }
  195. var mergeOptions = function(target, source) {
  196. for(var name in source) {
  197. target[name] = source[name];
  198. }
  199. return target;
  200. }
  201. // Merge options with translation
  202. var translateOptions = function(target, source) {
  203. var translations = {
  204. // SSL translation options
  205. 'sslCA': 'ca', 'sslValidate': 'rejectUnauthorized', 'sslKey': 'key', 'sslCert': 'cert', 'sslPass': 'passphrase',
  206. // SocketTimeout translation options
  207. 'socketTimeoutMS': 'socketTimeout', 'connectTimeoutMS': 'connectionTimeout',
  208. // Replicaset options
  209. 'replicaSet': 'setName', 'rs_name': 'setName', 'secondaryAcceptableLatencyMS': 'acceptableLatency',
  210. 'connectWithNoPrimary': 'secondaryOnlyConnectionAllowed',
  211. // Mongos options
  212. 'acceptableLatencyMS': 'localThresholdMS'
  213. }
  214. for(var name in source) {
  215. if(translations[name]) {
  216. target[translations[name]] = source[name];
  217. } else {
  218. target[name] = source[name];
  219. }
  220. }
  221. return target;
  222. }
  223. var filterOptions = function(options, names) {
  224. var filterOptions = {};
  225. for(var name in options) {
  226. if(names.indexOf(name) != -1) filterOptions[name] = options[name];
  227. }
  228. // Filtered options
  229. return filterOptions;
  230. }
  231. // Object.assign method or polyfille
  232. var assign = Object.assign ? Object.assign : function assign(target) {
  233. if (target === undefined || target === null) {
  234. throw new TypeError('Cannot convert first argument to object');
  235. }
  236. var to = Object(target);
  237. for (var i = 1; i < arguments.length; i++) {
  238. var nextSource = arguments[i];
  239. if (nextSource === undefined || nextSource === null) {
  240. continue;
  241. }
  242. var keysArray = Object.keys(Object(nextSource));
  243. for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
  244. var nextKey = keysArray[nextIndex];
  245. var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
  246. if (desc !== undefined && desc.enumerable) {
  247. to[nextKey] = nextSource[nextKey];
  248. }
  249. }
  250. }
  251. return to;
  252. }
  253. exports.filterOptions = filterOptions;
  254. exports.mergeOptions = mergeOptions;
  255. exports.translateOptions = translateOptions;
  256. exports.shallowClone = shallowClone;
  257. exports.getSingleProperty = getSingleProperty;
  258. exports.checkCollectionName = checkCollectionName;
  259. exports.toError = toError;
  260. exports.formattedOrderClause = formattedOrderClause;
  261. exports.parseIndexOptions = parseIndexOptions;
  262. exports.normalizeHintField = normalizeHintField;
  263. exports.handleCallback = handleCallback;
  264. exports.decorateCommand = decorateCommand;
  265. exports.isObject = isObject;
  266. exports.debugOptions = debugOptions;
  267. exports.MAX_JS_INT = 0x20000000000000;
  268. exports.assign = assign;