index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  1. // based on code from Brian White @mscdex mariasql library - https://github.com/mscdex/node-mariasql/blob/master/lib/Client.js#L272-L332
  2. // License: https://github.com/mscdex/node-mariasql/blob/master/LICENSE
  3. var RE_PARAM = /(?:\?)|(?::(\d+|(?:[a-zA-Z][a-zA-Z0-9_]*)))/g,
  4. DQUOTE = 34,
  5. SQUOTE = 39,
  6. BSLASH = 92;
  7. var parse = function(query) {
  8. var cqfn;
  9. if (this._queryCache && (cqfn = this._queryCache.get(query)))
  10. return cqfn;
  11. var ppos = RE_PARAM.exec(query), curpos = 0, start = 0, end, parts = [],
  12. i, chr, inQuote = false, escape = false, qchr, tokens = [], qcnt = 0, fn;
  13. if (ppos) {
  14. do {
  15. for (i=curpos,end=ppos.index; i<end; ++i) {
  16. chr = query.charCodeAt(i);
  17. if (chr === BSLASH)
  18. escape = !escape;
  19. else {
  20. if (escape) {
  21. escape = false;
  22. continue;
  23. }
  24. if (inQuote && chr === qchr) {
  25. if (query.charCodeAt(i + 1) === qchr) {
  26. // quote escaped via "" or ''
  27. ++i;
  28. continue;
  29. }
  30. inQuote = false;
  31. } else if (chr === DQUOTE || chr === SQUOTE) {
  32. inQuote = true;
  33. qchr = chr;
  34. }
  35. }
  36. }
  37. if (!inQuote) {
  38. parts.push(query.substring(start, end));
  39. tokens.push(ppos[0].length === 1 ? qcnt++ : ppos[1]);
  40. start = end + ppos[0].length;
  41. }
  42. curpos = end + ppos[0].length;
  43. } while (ppos = RE_PARAM.exec(query));
  44. if (tokens.length) {
  45. if (curpos < query.length)
  46. parts.push(query.substring(curpos));
  47. return [parts, tokens];
  48. }
  49. }
  50. return [query];
  51. };
  52. var EMPTY_LRU_FN = function(key, value) {};
  53. var createCompiler = function(config) {
  54. if (!config)
  55. config = {};
  56. if (!config.placeholder) {
  57. config.placeholder = '?';
  58. }
  59. var ncache = 100;
  60. var cache;
  61. if (typeof config.cache === 'number')
  62. ncache = config.cache;
  63. if (typeof config.cache === 'object')
  64. cache = config.cache;
  65. if (config.cache !== false && !cache) {
  66. cache = require('lru-cache')({ max: ncache, dispose: EMPTY_LRU_FN });
  67. }
  68. function toArrayParams(tree, params) {
  69. var arr = [];
  70. if (tree.length == 1)
  71. return [tree[0], []];
  72. var tokens = tree[1];
  73. for (var i=0; i < tokens.length; ++i)
  74. arr.push(params[tokens[i]]);
  75. return [tree[0], arr];
  76. }
  77. function join(tree) {
  78. if (tree.length == 1)
  79. return tree;
  80. var unnamed = tree[0].join(config.placeholder);
  81. if (tree[0].length == tree[1].length)
  82. unnamed += config.placeholder;
  83. return [unnamed, tree[1]];
  84. }
  85. var compile = function(query, paramsObj) {
  86. var tree;
  87. if (cache && (tree = cache.get(query))) {
  88. return toArrayParams(tree, paramsObj)
  89. }
  90. tree = join(parse(query));
  91. cache && cache.set(query, tree);
  92. return toArrayParams(tree, paramsObj);
  93. }
  94. compile.parse = parse;
  95. return compile;
  96. }
  97. module.exports = createCompiler;